forked from sch/Rivista
Rename project to Rivista;
CSS: Improve position of elements; JS: Improve handling of content in erroneous cases; JS: Render post as HTML when XSLT does not render correctly; JS: Handle posts which were tagged as Text instead of HTML and vice versa; XSLT: Adapt to be viewed on browsers with a lack of support; XSLT: Add Support for link elements of attribute "rel"; Python: Add elements author and link of attribute "rel".
This commit is contained in:
parent
040d532fb9
commit
cb4507bb78
8 changed files with 510 additions and 322 deletions
26
README.md
26
README.md
|
@ -1,14 +1,14 @@
|
||||||
# XMPP Journal Publisher
|
# Rivista
|
||||||
|
|
||||||
Previously, XMPP PubSub To Atom ("XPTA").
|
Previously, XMPP Journal Publisher ("XJP") and XMPP PubSub To Atom ("XPTA").
|
||||||
|
|
||||||
XMPP Journal Publisher ("XJP") is a software that parses XMPP Pubsub Nodes and sends them as Atom Syndication Format or OPML over HTTP.
|
Rivista is a software that parses XMPP Pubsub Nodes and sends them as Atom Syndication Format or OPML over HTTP.
|
||||||
|
|
||||||
XJP generates Atom syndication feeds ([RFC 4287](https://www.rfc-editor.org/rfc/rfc4287)) from XMPP PubSub nodes ([XEP-0060](http://xmpp.org/extensions/xep-0060.html)).
|
Rivista generates Atom syndication feeds ([RFC 4287](https://www.rfc-editor.org/rfc/rfc4287)) from XMPP PubSub nodes ([XEP-0060](http://xmpp.org/extensions/xep-0060.html)).
|
||||||
|
|
||||||
XJP includes [XSLT ](https://www.w3.org/TR/xslt/) stylesheets that transform PubSub nodes into static XHTML journal sites.
|
Rivista includes [XSLT ](https://www.w3.org/TR/xslt/) stylesheets that transform PubSub nodes into static XHTML journal sites.
|
||||||
|
|
||||||
XJP was inspired from Tigase and was motivated by Movim.
|
Rivista was inspired from Tigase and was motivated by Movim.
|
||||||
|
|
||||||
## Preview
|
## Preview
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ XJP was inspired from Tigase and was motivated by Movim.
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
XMPP Journal Publisher is a syndication project which makes journals and publications that are hosted on XMPP PubSub nodes, available
|
Rivista is a syndication project which makes journals and publications that are hosted on XMPP PubSub nodes, available
|
||||||
from HTTP to both, XML news readers and even HTML browsers.
|
from HTTP to both, XML news readers and even HTML browsers.
|
||||||
|
|
||||||
This means that instead of hosting a journal or publication site in the old fashion (i.e. HTML documents hosted on an HTTP server), one only has to have an HTTP server to operate XMPP Journal Publisher, and the rest of the content is delivered from an XMPP server (i.e. PubSub nodes).
|
This means that instead of hosting a journal or publication site in the old fashion (i.e. HTML documents hosted on an HTTP server), one only has to have an HTTP server to operate Rivista, and the rest of the content is delivered from an XMPP server (i.e. PubSub nodes).
|
||||||
|
|
||||||
The project also showcases the non-necessity of HTML, as it automatically generates valid XHTML pages by HTML browsers (client-side) from XSLT stylesheets.
|
The project also showcases the non-necessity of HTML, as it automatically generates valid XHTML pages by HTML browsers (client-side) from XSLT stylesheets.
|
||||||
|
|
||||||
Because XMPP Journal Publisher reads XMPP PubSub nodes, it is possible to view a complete set of node items, and even a single node item, which means, that a considered and carefully earnest use of XMPP Journal Publisher would save bandwidth and system overhead, which includes CPU, I/O and RAM usage.
|
Because Rivista reads XMPP PubSub nodes, it is possible to view a complete set of node items, and even a single node item, which means, that a considered and carefully earnest use of Rivista would save bandwidth and system overhead, which includes CPU, I/O and RAM usage.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@ Because XMPP Journal Publisher reads XMPP PubSub nodes, it is possible to view a
|
||||||
Extract the source package to a directory that you have permission to run software.
|
Extract the source package to a directory that you have permission to run software.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ git clone https://git.xmpp-it.net/sch/XJP
|
$ git clone https://git.xmpp-it.net/sch/Rivista
|
||||||
$ cd XJP/
|
$ cd Rivista/
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configure
|
### Configure
|
||||||
|
@ -60,7 +60,7 @@ Add account credentials to file `configuration.toml`.
|
||||||
|
|
||||||
### Start
|
### Start
|
||||||
|
|
||||||
Execute XMPP Journal Publisher with one of the following commands:
|
Execute Rivista with one of the following commands:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ python -m uvicorn main:app --reload
|
$ python -m uvicorn main:app --reload
|
||||||
|
@ -148,7 +148,7 @@ Thank you to to Mr. Timothée Jaussoin ([edhelas](https://edhelas.movim.eu/)) wh
|
||||||
|
|
||||||
A special thank you to the gentlemen "d3x" and "cchianel" from IRC channel #python on irc.libera.chat for initial references concerning code, servers and FastAPI.
|
A special thank you to the gentlemen "d3x" and "cchianel" from IRC channel #python on irc.libera.chat for initial references concerning code, servers and FastAPI.
|
||||||
|
|
||||||
And an important thank you to Mr. Simone Canaletti ([roughnecks](https://blog.woodpeckersnest.space/)) for testing and deploying XMPP Journal Publisher into production.
|
And an important thank you to Mr. Simone Canaletti ([roughnecks](https://blog.woodpeckersnest.space/)) for testing and deploying Rivista into production.
|
||||||
|
|
||||||
## Similar Projects
|
## Similar Projects
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,30 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
pubsub: news.movim.eu
|
||||||
|
node: fake-news
|
||||||
|
item: fdef84f5-e3e1-41ea-9b68-af4bb9130f77
|
||||||
|
title: #14October2023EpochEclipse
|
||||||
|
date: Fri, 15 Jan 2021 20:24:46
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
* {
|
* {
|
||||||
color: #eee;
|
color: #eee;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: #000;
|
background: #000;
|
||||||
}
|
}
|
||||||
|
@ -12,26 +34,26 @@ code, pre {
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
max-width: 100%; }
|
max-width: 100%; }
|
||||||
|
|
||||||
img, video {
|
img, svg, video {
|
||||||
|
display: block;
|
||||||
|
max-height: 500px;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice.no-entry {
|
|
||||||
margin: auto;
|
|
||||||
/* margin-left: 2%; */
|
|
||||||
/* margin-top: 2%; */
|
|
||||||
text-align: center;
|
|
||||||
padding-top: 100px;
|
|
||||||
padding-bottom: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1#title, h2#subtitle, #actions, #references {
|
h1#title, h2#subtitle, #actions, #references {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
line-height: 140%;
|
line-height: 140%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h5.related > a {
|
||||||
|
margin-right: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
h3.title > a {
|
h3.title > a {
|
||||||
display: block;
|
display: block;
|
||||||
padding-top: 50px;
|
padding-top: 50px;
|
||||||
|
@ -59,24 +81,17 @@ h3.title > a {
|
||||||
padding-left: 2%;
|
padding-left: 2%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#menu > ul > li {
|
#menu > ol > li {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note {
|
|
||||||
line-height: 30px;
|
|
||||||
margin: auto;
|
|
||||||
margin-top: 0.67em;
|
|
||||||
max-width: 70%;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#references {
|
#references {
|
||||||
|
margin-top: 5em;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
#articles {
|
#articles {
|
||||||
|
min-height: 80vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +106,12 @@ h3.title > a {
|
||||||
|
|
||||||
#journal {
|
#journal {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
padding-top: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#articles > ul {
|
#articles > ul {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
margin-left: 2%;
|
||||||
margin-top: 2%;
|
margin-top: 2%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,10 +120,7 @@ h3.title > a {
|
||||||
/* height: 500px; */
|
/* height: 500px; */
|
||||||
line-height: 160%;
|
line-height: 160%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
word-wrap: break-word;
|
||||||
|
|
||||||
#articles #journal > a {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#articles div.content {
|
#articles div.content {
|
||||||
|
@ -174,7 +188,91 @@ h3.title > a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1525px) {
|
.enclosures {
|
||||||
|
cursor: help;
|
||||||
|
direction: ltr;
|
||||||
|
margin: 5px auto 15px 1%;
|
||||||
|
padding: 15px;
|
||||||
|
padding: 1em;
|
||||||
|
/* background: #222;
|
||||||
|
border: 1px solid GrayText;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-radius: .5em;
|
||||||
|
color: #525c66;
|
||||||
|
border-left: double;
|
||||||
|
max-width: 40%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure a {
|
||||||
|
margin: 3px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span[icon='atom']:after,
|
||||||
|
.enclosure > span[icon='html5']:after,
|
||||||
|
.enclosure > span[icon='rss']:after {
|
||||||
|
content: '📰';
|
||||||
|
margin:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span.audio:after {
|
||||||
|
content: ' (Audio file) ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span[icon='audio']:after{
|
||||||
|
content: '🎼️';
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span:after {
|
||||||
|
content: ' (Document file) ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span[icon]:after {
|
||||||
|
content: '📄️';
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span.executable:after{
|
||||||
|
content: ' (Executable file) ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span[icon='executable']:after {
|
||||||
|
content: '📦️';
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span.image:after {
|
||||||
|
content: ' (Image file) ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span[icon='image']:after {
|
||||||
|
content: '🖼️';
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span.video:after {
|
||||||
|
content: ' (Video file) ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.enclosure > span[icon='video']:after {
|
||||||
|
content: '📽️';
|
||||||
|
margin:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#note {
|
||||||
|
line-height: 30px;
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 0.67em;
|
||||||
|
max-width: 70%;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1550px) {
|
||||||
#articles {
|
#articles {
|
||||||
display: unset;
|
display: unset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ from fastapi.staticfiles import StaticFiles
|
||||||
import json
|
import json
|
||||||
from slixmpp import ClientXMPP
|
from slixmpp import ClientXMPP
|
||||||
from slixmpp.exceptions import IqError, IqTimeout
|
from slixmpp.exceptions import IqError, IqTimeout
|
||||||
|
import xml
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
#import importlib.resources
|
#import importlib.resources
|
||||||
|
|
||||||
|
@ -56,17 +57,15 @@ async def view_pubsub_nodes(request: Request):
|
||||||
if iq:
|
if iq:
|
||||||
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
|
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
|
||||||
xml_opml = generate_opml(iq)
|
xml_opml = generate_opml(iq)
|
||||||
result = append_stylesheet(xml_opml, 'opml.xsl')
|
result = append_stylesheet(xml_opml, 'opml')
|
||||||
else:
|
else:
|
||||||
text = 'Please check that PubSub Jabber ID is valid and accessible.'
|
text = 'Please check that PubSub Jabber ID is valid and accessible.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
else:
|
else:
|
||||||
text = 'The given domain {} is not allowed.'.format(pubsub)
|
text = 'The given domain {} is not allowed.'.format(pubsub)
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
default = get_configuration('default')
|
default = get_configuration('default')
|
||||||
if not result:
|
if not result:
|
||||||
if default['pubsub']:
|
if default['pubsub']:
|
||||||
|
@ -75,17 +74,16 @@ async def view_pubsub_nodes(request: Request):
|
||||||
iq = await get_nodes(pubsub)
|
iq = await get_nodes(pubsub)
|
||||||
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
|
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
|
||||||
xml_opml = generate_opml(iq)
|
xml_opml = generate_opml(iq)
|
||||||
result = append_stylesheet(xml_opml, 'opml.xsl')
|
result = append_stylesheet(xml_opml, 'opml')
|
||||||
elif not settings['service']:
|
elif not settings['service']:
|
||||||
pubsub = default['pubsub']
|
pubsub = default['pubsub']
|
||||||
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
|
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
|
||||||
xml_opml = generate_opml(iq)
|
xml_opml = generate_opml(iq)
|
||||||
result = append_stylesheet(xml_opml, 'opml.xsl')
|
result = append_stylesheet(xml_opml, 'opml')
|
||||||
else:
|
else:
|
||||||
text = 'Please contact the administrator and ask him to set default PubSub and Node ID.'
|
text = 'Please contact the administrator and ask him to set default PubSub and Node ID.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
response = Response(content=result, media_type="application/xml")
|
response = Response(content=result, media_type="application/xml")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -115,11 +113,12 @@ async def view_node_items(request: Request):
|
||||||
else:
|
else:
|
||||||
operator = get_configuration('settings')['operator']
|
operator = get_configuration('settings')['operator']
|
||||||
json_data = [{'title' : 'Error retrieving items list.',
|
json_data = [{'title' : 'Error retrieving items list.',
|
||||||
'link' : ('javascript:alert("XJP: XMPP Journal Publisher has experienced an error '
|
'link' : ('javascript:alert("Rivista has experienced an error '
|
||||||
'while attempting to retrieve the list of items for Node {} of PubSub {}.")')
|
'while attempting to retrieve the list of items for '
|
||||||
|
'Node {} of PubSub {}.")')
|
||||||
.format(node, pubsub)},
|
.format(node, pubsub)},
|
||||||
{'title' : 'Contact the operator.',
|
{'title' : 'Contact the operator.',
|
||||||
'link' : ('xmpp:{}?message;subject=XJP: XMPP Journal Publisher;body=Greetings! '
|
'link' : ('xmpp:{}?message;subject=Rivista;body=Greetings! '
|
||||||
'I am contacting you to inform you that there is an error listing '
|
'I am contacting you to inform you that there is an error listing '
|
||||||
'node items for Node {} on PubSub {}.').format(operator, node, pubsub)}]
|
'node items for Node {} on PubSub {}.').format(operator, node, pubsub)}]
|
||||||
filename = 'data/{}.json'.format(node)
|
filename = 'data/{}.json'.format(node)
|
||||||
|
@ -128,8 +127,7 @@ async def view_node_items(request: Request):
|
||||||
else:
|
else:
|
||||||
text = 'Please check that PubSub node and item are valid and accessible.'
|
text = 'Please check that PubSub node and item are valid and accessible.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
|
|
||||||
# try:
|
# try:
|
||||||
# iq = await get_node_items(pubsub, node)
|
# iq = await get_node_items(pubsub, node)
|
||||||
|
@ -149,26 +147,22 @@ async def view_node_items(request: Request):
|
||||||
else:
|
else:
|
||||||
text = 'Please check that PubSub node is valid and accessible.'
|
text = 'Please check that PubSub node is valid and accessible.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
elif pubsub:
|
elif pubsub:
|
||||||
text = 'Node parameter is missing.'
|
text = 'Node parameter is missing.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
elif node:
|
elif node:
|
||||||
text = 'PubSub parameter is missing.'
|
text = 'PubSub parameter is missing.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
# else:
|
# else:
|
||||||
# result = ('Mandatory parameter PubSub and '
|
# result = ('Mandatory parameter PubSub and '
|
||||||
# 'optional parameter Node are missing.')
|
# 'optional parameter Node are missing.')
|
||||||
else:
|
else:
|
||||||
text = 'The given domain {} is not allowed.'.format(pubsub)
|
text = 'The given domain {} is not allowed.'.format(pubsub)
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
default = get_configuration('default')
|
default = get_configuration('default')
|
||||||
if not result:
|
if not result:
|
||||||
if default['pubsub'] and default['nodeid']:
|
if default['pubsub'] and default['nodeid']:
|
||||||
|
@ -178,21 +172,18 @@ async def view_node_items(request: Request):
|
||||||
iq = await get_node_items(pubsub, node)
|
iq = await get_node_items(pubsub, node)
|
||||||
link = form_a_node_link(pubsub, node)
|
link = form_a_node_link(pubsub, node)
|
||||||
xml_atom = generate_atom(iq, link)
|
xml_atom = generate_atom(iq, link)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
elif not settings['service']:
|
elif not settings['service']:
|
||||||
pubsub = default['pubsub']
|
pubsub = default['pubsub']
|
||||||
node = default['nodeid']
|
node = default['nodeid']
|
||||||
iq = await get_node_items(pubsub, node)
|
iq = await get_node_items(pubsub, node)
|
||||||
link = form_a_node_link(pubsub, node)
|
link = form_a_node_link(pubsub, node)
|
||||||
xml_atom = generate_atom(iq, link)
|
xml_atom = generate_atom(iq, link)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
else:
|
else:
|
||||||
text = 'Please contact the administrator and ask him to set default PubSub and Node ID.'
|
text = 'Please contact the administrator and ask him to set default PubSub and Node ID.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
result = append_stylesheet(
|
result = append_stylesheet(xml_atom, 'atom')
|
||||||
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
|
||||||
response = Response(content=result, media_type="application/xml")
|
response = Response(content=result, media_type="application/xml")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -234,24 +225,25 @@ def form_an_item_link(pubsub, node, item_id):
|
||||||
|
|
||||||
def error_message(text):
|
def error_message(text):
|
||||||
"""Error message in RFC 4287: The Atom Syndication Format."""
|
"""Error message in RFC 4287: The Atom Syndication Format."""
|
||||||
title = 'StreamBurner'
|
title = 'Rivista'
|
||||||
subtitle = 'XMPP Journal Publisher'
|
subtitle = 'XMPP Journal Publisher'
|
||||||
description = ('This is a syndication feed generated with XMPP Journal '
|
description = ('This is a syndication feed generated with Rivista, an XMPP '
|
||||||
'Publisher, which conveys XEP-0060: Publish-Subscribe '
|
'Journal Publisher, which conveys XEP-0060: Publish-'
|
||||||
'nodes to standard RFC 4287: The Atom Syndication Format.')
|
'Subscribe nodes to standard RFC 4287: The Atom Syndication '
|
||||||
|
'Format.')
|
||||||
language = 'en'
|
language = 'en'
|
||||||
feed = ET.Element("feed")
|
feed = ET.Element("feed")
|
||||||
feed.set('xmlns', 'http://www.w3.org/2005/Atom')
|
feed.set('xmlns', 'http://www.w3.org/2005/Atom')
|
||||||
ET.SubElement(feed, 'title', {'type': 'text'}).text = title
|
ET.SubElement(feed, 'title', {'type': 'text'}).text = title
|
||||||
ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle
|
ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle
|
||||||
ET.SubElement(feed, 'author', {'name':'XMPP Journal Publisher','email':'xjp@schimon.i2p'})
|
ET.SubElement(feed, 'author', {'name':'Rivista','email':'rivista@schimon.i2p'})
|
||||||
ET.SubElement(feed, 'generator', {
|
ET.SubElement(feed, 'generator', {
|
||||||
'uri': 'https://git.xmpp-it.net/sch/XJP',
|
'uri': 'https://git.xmpp-it.net/sch/Rivista',
|
||||||
'version': '0.1'}).text = 'XMPP Journal Publisher (XJP)'
|
'version': '0.1'}).text = 'Rivista'
|
||||||
ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
|
ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
|
||||||
entry = ET.SubElement(feed, 'entry')
|
entry = ET.SubElement(feed, 'entry')
|
||||||
ET.SubElement(entry, 'title').text = 'Error'
|
ET.SubElement(entry, 'title').text = 'Error'
|
||||||
ET.SubElement(entry, 'id').text = 'xjp-error'
|
ET.SubElement(entry, 'id').text = 'rivista-error'
|
||||||
ET.SubElement(entry, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
|
ET.SubElement(entry, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
|
||||||
ET.SubElement(entry, 'published').text = datetime.datetime.now(datetime.UTC).isoformat()
|
ET.SubElement(entry, 'published').text = datetime.datetime.now(datetime.UTC).isoformat()
|
||||||
# ET.SubElement(entry, 'summary', {'type': summary_type_text}).text = summary_text
|
# ET.SubElement(entry, 'summary', {'type': summary_type_text}).text = summary_text
|
||||||
|
@ -268,55 +260,77 @@ def generate_atom(iq, link):
|
||||||
# link = form_a_node_link(pubsub, node)
|
# link = form_a_node_link(pubsub, node)
|
||||||
# subtitle = 'XMPP PubSub Syndication Feed'
|
# subtitle = 'XMPP PubSub Syndication Feed'
|
||||||
subtitle = pubsub
|
subtitle = pubsub
|
||||||
description = ('This is a syndication feed generated with XMPP Journal '
|
description = ('This is a syndication feed generated with Rivista, an XMPP '
|
||||||
'Publisher, which conveys XEP-0060: Publish-Subscribe '
|
'Journal Publisher, which conveys XEP-0060: Publish-'
|
||||||
'nodes to standard RFC 4287: The Atom Syndication Format.')
|
'Subscribe nodes to standard RFC 4287: The Atom Syndication '
|
||||||
|
'Format.')
|
||||||
language = iq['pubsub']['items']['lang']
|
language = iq['pubsub']['items']['lang']
|
||||||
items = iq['pubsub']['items']
|
items = iq['pubsub']['items']
|
||||||
feed = ET.Element("feed")
|
e_feed = ET.Element("feed")
|
||||||
feed.set('xmlns', 'http://www.w3.org/2005/Atom')
|
e_feed.set('xmlns', 'http://www.w3.org/2005/Atom')
|
||||||
ET.SubElement(feed, 'title', {'type': 'text'}).text = title
|
ET.SubElement(e_feed, 'title', {'type': 'text'}).text = title
|
||||||
ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle
|
ET.SubElement(e_feed, 'subtitle', {'type': 'text'}).text = subtitle
|
||||||
ET.SubElement(feed, 'link', {'rel': 'self', 'href': link})
|
ET.SubElement(e_feed, 'link', {'rel': 'self', 'href': link})
|
||||||
ET.SubElement(feed, 'generator', {
|
ET.SubElement(e_feed, 'generator', {
|
||||||
'uri': 'https://git.xmpp-it.net/sch/XJP',
|
'uri': 'https://git.xmpp-it.net/sch/Rivista',
|
||||||
'version': '0.1'}).text = 'XMPP Journal Publisher (XJP)'
|
'version': '0.1'}).text = 'Rivista'
|
||||||
ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
|
ET.SubElement(e_feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
|
||||||
for item in items:
|
for item in items:
|
||||||
item_id = item['id']
|
item_id = item['id']
|
||||||
item_payload = item['payload']
|
item_payload = item['payload']
|
||||||
namespace = '{http://www.w3.org/2005/Atom}'
|
namespace = '{http://www.w3.org/2005/Atom}'
|
||||||
title = item_payload.find(namespace + 'title')
|
title = item_payload.find(namespace + 'title')
|
||||||
|
links = item_payload.find(namespace + 'link')
|
||||||
|
if (not isinstance(title, xml.etree.ElementTree.Element) and
|
||||||
|
not isinstance(links, xml.etree.ElementTree.Element)): continue
|
||||||
title_text = None if title == None else title.text
|
title_text = None if title == None else title.text
|
||||||
# link = item_payload.find(namespace + 'link')
|
e_entry = ET.SubElement(e_feed, 'entry')
|
||||||
# link_href = '' if link == None else link.attrib['href']
|
ET.SubElement(e_entry, 'title').text = title_text
|
||||||
link_href = form_an_item_link(pubsub, node, item_id)
|
if isinstance(links, xml.etree.ElementTree.Element):
|
||||||
if not title_text or not link_href: continue
|
for link in item_payload.findall(namespace + 'link'):
|
||||||
content = item_payload.find(namespace + 'content')
|
link_href = link.attrib['href'] if 'href' in link.attrib else ''
|
||||||
content_text = 'No content' if content == None else content.text
|
link_type = link.attrib['type'] if 'type' in link.attrib else ''
|
||||||
if content:
|
link_rel = link.attrib['rel'] if 'rel' in link.attrib else ''
|
||||||
content_type = content.attrib['type'] if 'type' in content.attrib else 'text'
|
ET.SubElement(e_entry, 'link', {'href': link_href, 'rel': link_rel, 'type': link_type})
|
||||||
content_type_text = 'html' if 'html' in content_type else 'text'
|
|
||||||
else:
|
else:
|
||||||
content_type_text = 'html'
|
ET.SubElement(e_entry, 'content', {'href': ''})
|
||||||
|
link_xmpp = form_an_item_link(pubsub, node, item_id)
|
||||||
|
ET.SubElement(e_entry, 'link', {'href': link_xmpp, 'rel': 'alternate', 'type': 'x-scheme-handler/xmpp'})
|
||||||
|
contents = item_payload.find(namespace + 'content')
|
||||||
|
if isinstance(contents, xml.etree.ElementTree.Element):
|
||||||
|
for content in item_payload.findall(namespace + 'content'):
|
||||||
|
content_text = content.text if content.text else 'No content.'
|
||||||
|
content_type = content.attrib['type'] if 'type' in content.attrib else 'html'
|
||||||
|
content_type_text = 'html' if 'html' in content_type else 'html'
|
||||||
|
ET.SubElement(e_entry, 'content', {'type': content_type_text}).text = content_text
|
||||||
|
else:
|
||||||
|
ET.SubElement(e_entry, 'content').text = 'No content.'
|
||||||
published = item_payload.find(namespace + 'published')
|
published = item_payload.find(namespace + 'published')
|
||||||
published_text = None if published == None else published.text
|
published_text = None if published == None else published.text
|
||||||
|
ET.SubElement(e_entry, 'published').text = published_text
|
||||||
updated = item_payload.find(namespace + 'updated')
|
updated = item_payload.find(namespace + 'updated')
|
||||||
updated_text = None if updated == None else updated.text
|
updated_text = None if updated == None else updated.text
|
||||||
author = item_payload.find(namespace + 'author')
|
ET.SubElement(e_entry, 'updated').text = updated_text
|
||||||
if author and author.attrib: print(author.attrib)
|
e_author = ET.SubElement(e_entry, 'author')
|
||||||
|
authors = item_payload.find(namespace + 'author')
|
||||||
|
if isinstance(authors, xml.etree.ElementTree.Element):
|
||||||
|
for author in item_payload.findall(namespace + 'author'):
|
||||||
|
if not author.text: continue
|
||||||
|
author_text = author.text
|
||||||
|
author_email = link.attrib['href'] if 'href' in link.attrib else ''
|
||||||
|
author_uri = link.attrib['type'] if 'type' in link.attrib else ''
|
||||||
|
author_summary = link.attrib['rel'] if 'rel' in link.attrib else ''
|
||||||
|
ET.SubElement(e_author, 'name').text = author_text
|
||||||
|
if author and author.attrib: print(author.attrib)
|
||||||
|
|
||||||
|
|
||||||
identifier = item_payload.find(namespace + 'id')
|
identifier = item_payload.find(namespace + 'id')
|
||||||
if identifier and identifier.attrib: print(identifier.attrib)
|
if identifier and identifier.attrib: print(identifier.attrib)
|
||||||
identifier_text = 'None' if identifier == None else identifier.text
|
|
||||||
entry = ET.SubElement(feed, 'entry')
|
identifier_text = None if identifier == None else identifier.text
|
||||||
ET.SubElement(entry, 'title').text = title_text
|
ET.SubElement(e_entry, 'id').text = identifier_text
|
||||||
ET.SubElement(entry, 'link', {'href': link_href})
|
# ET.SubElement(e_entry, 'summary', {'type': summary_type_text}).text = summary_text
|
||||||
ET.SubElement(entry, 'id').text = identifier_text
|
return ET.tostring(e_feed, encoding='unicode')
|
||||||
ET.SubElement(entry, 'updated').text = updated_text
|
|
||||||
ET.SubElement(entry, 'published').text = published_text
|
|
||||||
# ET.SubElement(entry, 'summary', {'type': summary_type_text}).text = summary_text
|
|
||||||
ET.SubElement(entry, 'content', {'type': content_type_text}).text = content_text
|
|
||||||
return ET.tostring(feed, encoding='unicode')
|
|
||||||
|
|
||||||
def generate_json(iq):
|
def generate_json(iq):
|
||||||
"""Create a JSON file from node items."""
|
"""Create a JSON file from node items."""
|
||||||
|
@ -344,25 +358,11 @@ def generate_json(iq):
|
||||||
with open(filename, 'w', encoding='utf-8') as f:
|
with open(filename, 'w', encoding='utf-8') as f:
|
||||||
json.dump(json_data, f, ensure_ascii=False, indent=4)
|
json.dump(json_data, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
"""Patch function to append elements which are not provided by feedgenerator"""
|
|
||||||
def append_element(xml_data, element, text):
|
|
||||||
root = ET.fromstring(xml_data)
|
|
||||||
|
|
||||||
# Create the generator element
|
|
||||||
generator_element = ET.Element(element)
|
|
||||||
generator_element.text = text
|
|
||||||
|
|
||||||
# Append the generator element to the root
|
|
||||||
root.append(generator_element)
|
|
||||||
|
|
||||||
# Return the modified XML as a string
|
|
||||||
return ET.tostring(root, encoding='unicode')
|
|
||||||
|
|
||||||
"""Patch function to append XSLT reference to XML"""
|
"""Patch function to append XSLT reference to XML"""
|
||||||
"""Why is not this a built-in function of ElementTree or LXML"""
|
"""Why is not this a built-in function of ElementTree or LXML"""
|
||||||
def append_stylesheet(xml_data, filename, namespace=None):
|
def append_stylesheet(xml_data, type):
|
||||||
# Register namespace in order to avoide ns0:
|
# Register namespace in order to avoide ns0:
|
||||||
if namespace: ET.register_namespace("", namespace)
|
if type == 'atom': ET.register_namespace('', 'http://www.w3.org/2005/Atom')
|
||||||
# Load XML from string
|
# Load XML from string
|
||||||
tree = ET.fromstring(xml_data)
|
tree = ET.fromstring(xml_data)
|
||||||
# The following direction removes the XML declaration
|
# The following direction removes the XML declaration
|
||||||
|
@ -370,7 +370,7 @@ def append_stylesheet(xml_data, filename, namespace=None):
|
||||||
# Add XML declaration and stylesheet
|
# Add XML declaration and stylesheet
|
||||||
xml_data_declaration = (
|
xml_data_declaration = (
|
||||||
'<?xml version="1.0" encoding="utf-8"?>'
|
'<?xml version="1.0" encoding="utf-8"?>'
|
||||||
'<?xml-stylesheet type="text/xsl" href="xsl/{}"?>'.format(filename) +
|
'<?xml-stylesheet type="text/xsl" href="xsl/{}.xsl"?>'.format(type) +
|
||||||
xml_data_without_a_declaration)
|
xml_data_without_a_declaration)
|
||||||
return xml_data_declaration
|
return xml_data_declaration
|
||||||
|
|
||||||
|
@ -380,11 +380,11 @@ def generate_opml(iq):
|
||||||
opml = ET.Element("opml")
|
opml = ET.Element("opml")
|
||||||
opml.set("version", "1.0")
|
opml.set("version", "1.0")
|
||||||
head = ET.SubElement(opml, "head")
|
head = ET.SubElement(opml, "head")
|
||||||
ET.SubElement(head, "title").text = pubsub
|
ET.SubElement(head, "title").text = 'An OPML of ' + pubsub
|
||||||
ET.SubElement(head, "description").text = (
|
ET.SubElement(head, "description").text = (
|
||||||
"PubSub Nodes of {}").format(pubsub)
|
"PubSub Nodes of {}").format(pubsub)
|
||||||
ET.SubElement(head, "generator").text = 'XMPP Journal Publisher (XJP)'
|
ET.SubElement(head, "generator").text = 'Rivista'
|
||||||
ET.SubElement(head, "urlPublic").text = 'https://git.xmpp-it.net/sch/XJP'
|
ET.SubElement(head, "urlPublic").text = 'https://git.xmpp-it.net/sch/Rivista'
|
||||||
time_stamp = datetime.datetime.now(datetime.UTC).isoformat()
|
time_stamp = datetime.datetime.now(datetime.UTC).isoformat()
|
||||||
ET.SubElement(head, "dateCreated").text = time_stamp
|
ET.SubElement(head, "dateCreated").text = time_stamp
|
||||||
ET.SubElement(head, "dateModified").text = time_stamp
|
ET.SubElement(head, "dateModified").text = time_stamp
|
||||||
|
|
|
@ -2,7 +2,8 @@ window.onload = async function(){
|
||||||
let locationHref = new URL(location.href);
|
let locationHref = new URL(location.href);
|
||||||
let node = locationHref.searchParams.get('node')
|
let node = locationHref.searchParams.get('node')
|
||||||
let pubsub = locationHref.searchParams.get('pubsub')
|
let pubsub = locationHref.searchParams.get('pubsub')
|
||||||
// Fix button follow
|
|
||||||
|
// Set button follow
|
||||||
let follow = document.querySelector('#follow');
|
let follow = document.querySelector('#follow');
|
||||||
if (follow) {
|
if (follow) {
|
||||||
//let feedUrl = location.href.replace(/^https?:/, 'feed:');
|
//let feedUrl = location.href.replace(/^https?:/, 'feed:');
|
||||||
|
@ -14,6 +15,7 @@ window.onload = async function(){
|
||||||
// Fix button subtome
|
// Fix button subtome
|
||||||
document.querySelector('#subtome').href='https://www.subtome.com/#/subscribe?feeds=' + feedUrl;
|
document.querySelector('#subtome').href='https://www.subtome.com/#/subscribe?feeds=' + feedUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert ISO8601 To UTC
|
// Convert ISO8601 To UTC
|
||||||
for (let element of document.querySelectorAll(
|
for (let element of document.querySelectorAll(
|
||||||
'#articles > ul > li > div > h4.published,' +
|
'#articles > ul > li > div > h4.published,' +
|
||||||
|
@ -22,11 +24,62 @@ window.onload = async function(){
|
||||||
let timeStamp = new Date(element.textContent);
|
let timeStamp = new Date(element.textContent);
|
||||||
element.textContent = timeStamp.toUTCString();
|
element.textContent = timeStamp.toUTCString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse Markdown
|
// Parse Markdown
|
||||||
for (let element of document.querySelectorAll('#articles div[type="text"]')) {
|
for (let element of document.querySelectorAll('#articles div[type="text"]')) {
|
||||||
let markDown = element.textContent
|
element.innerHTML = marked.parse(element.textContent);
|
||||||
element.innerHTML = marked.parse(markDown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE Report this issue to Movim. See node "deltachat" of pubsub "news.movim.eu".
|
||||||
|
for (let element of document.querySelectorAll('#articles div[type="html"]')) {
|
||||||
|
if (!element.children.length) {
|
||||||
|
element.innerHTML = marked.parse(element.textContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
|
||||||
|
The reason for the following code to parse HTML inside an software which
|
||||||
|
already parses HTML, is that some people who influence the so called Gecko
|
||||||
|
HTML Engine product (mostly people from the advertisement industry with whom
|
||||||
|
I shamefully used to work with) have intentions to eliminate standards and
|
||||||
|
technologies such as Syndication (Atom/RDF/RSS), XSLT and many other
|
||||||
|
technologies that actually empower people and their privacy.
|
||||||
|
|
||||||
|
Recently, some changes were made to the XSLT parser of Gecko which result in
|
||||||
|
noncompliance with the XSLT standard.
|
||||||
|
|
||||||
|
The XSLT feature that was removed is "disable-output-escaping" which upon the
|
||||||
|
value "yes" the XSLT engine should transform and treat a subject string into
|
||||||
|
HTML, yet the Gecko HTML Engine ignores this XSLT direction.
|
||||||
|
|
||||||
|
This change was probably made in order to:
|
||||||
|
* Frustrate new XSLT developers; or
|
||||||
|
* Influence new XSLT developers to think that XSLT has a limited set of
|
||||||
|
features and believing of some sort of inability to parse HTML from a
|
||||||
|
retrieved HTML string; and
|
||||||
|
* Consequently cause developers to abstain from using the XSLT technology.
|
||||||
|
|
||||||
|
Do not use HTML browsers or use Ladybird, Pale Moon or browsers that are
|
||||||
|
powered by KHTML (WebKit) instead of anti-privacy software such as Chromium
|
||||||
|
and Gecko.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Parse HTML
|
||||||
|
//if (navigator.userAgent.includes(') Gecko/')) {
|
||||||
|
// for (let element of document.querySelectorAll('#articles div[type="html"]')) {
|
||||||
|
// element.innerHTML = element.textContent;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
for (let element of document.querySelectorAll('#articles div[type="html"]')) {
|
||||||
|
if (!element.children.length) {
|
||||||
|
element.innerHTML = element.textContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build a journal list
|
// Build a journal list
|
||||||
if (node) {
|
if (node) {
|
||||||
itemsList = await openJson(node)
|
itemsList = await openJson(node)
|
||||||
|
@ -79,8 +132,11 @@ window.onload = async function(){
|
||||||
document.querySelector('#articles').appendChild(elementDiv);
|
document.querySelector('#articles').appendChild(elementDiv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert URI xmpp: to URI http: links.
|
// Convert URI xmpp: to URI http: links.
|
||||||
for (let xmppLink of document.querySelectorAll('#articles > ul a[href^="xmpp:"], ol a[href^="xmpp:"]')) {
|
for (let xmppLink of document.querySelectorAll(
|
||||||
|
'#articles > ul > li > div > h3 > a[href^="xmpp:"],' +
|
||||||
|
'#journal > ol > li > a[href^="xmpp:"]')) {
|
||||||
xmppUri = new URL(xmppLink);
|
xmppUri = new URL(xmppLink);
|
||||||
let parameters = xmppUri.search.split(';');
|
let parameters = xmppUri.search.split(';');
|
||||||
try {
|
try {
|
||||||
|
@ -98,6 +154,7 @@ window.onload = async function(){
|
||||||
console.warn(err)
|
console.warn(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display a selection of suggested software.
|
// Display a selection of suggested software.
|
||||||
const selection = {
|
const selection = {
|
||||||
'akregator' : {
|
'akregator' : {
|
||||||
|
@ -144,14 +201,14 @@ window.onload = async function(){
|
||||||
elementH1.textContent = 'Get A News Reader';
|
elementH1.textContent = 'Get A News Reader';
|
||||||
elementDiv.appendChild(elementH1);
|
elementDiv.appendChild(elementH1);
|
||||||
let elementH2 = document.createElement('h2');
|
let elementH2 = document.createElement('h2');
|
||||||
elementH2.textContent = 'Install Feed Reader Apps For Desktop And Mobile';
|
elementH2.textContent = 'Install A Feed Reader For Desktop And Mobile';
|
||||||
elementDiv.appendChild(elementH2);
|
elementDiv.appendChild(elementH2);
|
||||||
const brands = Object.keys(selection);
|
const brands = Object.keys(selection);
|
||||||
let elementDivSel = document.createElement('div');
|
let elementDivSel = document.createElement('div');
|
||||||
elementDivSel.id = 'selection';
|
elementDivSel.id = 'selection';
|
||||||
for (let i = 0; i < brands.length; i++) {
|
for (let i = 0; i < brands.length; i++) {
|
||||||
let brand = brands[i];
|
let brand = brands[i];
|
||||||
elementSpan = document.createElement('span');
|
let elementSpan = document.createElement('span');
|
||||||
let elementA = document.createElement('a');
|
let elementA = document.createElement('a');
|
||||||
elementA.href = selection[brand].url;
|
elementA.href = selection[brand].url;
|
||||||
elementA.textContent = selection[brand].name;
|
elementA.textContent = selection[brand].name;
|
||||||
|
@ -162,20 +219,24 @@ window.onload = async function(){
|
||||||
elementDivSel.appendChild(elementSpan);
|
elementDivSel.appendChild(elementSpan);
|
||||||
elementDiv.appendChild(elementDivSel);
|
elementDiv.appendChild(elementDivSel);
|
||||||
}
|
}
|
||||||
let elementP = document.createElement('p');
|
let elementP1 = document.createElement('p');
|
||||||
elementP.textContent = '' +
|
elementP1.textContent = '' +
|
||||||
'This is a selection of desktop applications, mobile apps and online ' +
|
'This is a selection of desktop, mobile and HTML (sometimes referred to ' +
|
||||||
'services for you to choose from. This selection includes news ' +
|
'as "online") News Readers for you to choose from.';
|
||||||
'readers, podcast managers, torrent clients, chat bots, HTML browsers ' +
|
elementDiv.appendChild(elementP1);
|
||||||
'and plugins which support syndication feeds.';
|
let elementP2 = document.createElement('p');
|
||||||
elementDiv.appendChild(elementP);
|
elementP2.textContent = '' +
|
||||||
let elementDivReturn = document.createElement('div');
|
'This selection includes: Podcast Managers, Torrent ' +
|
||||||
elementDivReturn.id = 'return';
|
'Clients, Chat Bots, HTML Browsers and Plugins which support ' +
|
||||||
elementDivReturn.textContent = 'Return To PubSub...';
|
'syndication feeds.';
|
||||||
elementDivReturn.addEventListener ('click', function() {
|
elementDiv.appendChild(elementP2);
|
||||||
|
let elementSpan = document.createElement('span');
|
||||||
|
elementSpan.id = 'return';
|
||||||
|
elementSpan.textContent = 'Return To PubSub';
|
||||||
|
elementSpan.addEventListener ('click', function() {
|
||||||
document.querySelector('#selection-page').remove();
|
document.querySelector('#selection-page').remove();
|
||||||
});
|
});
|
||||||
elementDiv.appendChild(elementDivReturn);
|
elementDiv.appendChild(elementSpan);
|
||||||
document.body.appendChild(elementDiv);
|
document.body.appendChild(elementDiv);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
10
xsl/atom.xsl
10
xsl/atom.xsl
|
@ -1,17 +1,19 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2016 - 2017 Schimon Jehuda. Released under MIT license
|
Copyright (C) 2016 - 2024 Schimon Jehuda. Released under MIT license
|
||||||
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
|
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
|
||||||
include https://schimon.i2p/ in attribute name='generator' of
|
include https://schimon.i2p/ in attribute name='generator' of
|
||||||
element <meta/> inside of html element </head>
|
element <meta/> inside of html element </head>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
<xsl:output method = 'html'
|
<xsl:output encoding = 'UTF-8'
|
||||||
indent = 'yes'
|
indent = 'yes'
|
||||||
omit-xml-decleration='no' />
|
media-type = 'application/atom+xml'
|
||||||
<!-- Atom 1.0 Syndication Format -->
|
method = 'html'
|
||||||
|
version = '4.01' />
|
||||||
|
<!-- Atom Syndication Format 1.0 -->
|
||||||
<xsl:include href='atom_as_xhtml.xsl'/>
|
<xsl:include href='atom_as_xhtml.xsl'/>
|
||||||
<!-- extract filename from given url string -->
|
<!-- extract filename from given url string -->
|
||||||
<xsl:include href='extract-filename.xsl'/>
|
<xsl:include href='extract-filename.xsl'/>
|
||||||
|
|
|
@ -15,9 +15,6 @@ xmlns:georss='http://www.georss.org/georss'
|
||||||
xmlns:geo='http://www.w3.org/2003/01/geo/wgs84_pos#'
|
xmlns:geo='http://www.w3.org/2003/01/geo/wgs84_pos#'
|
||||||
xmlns:atom10='http://www.w3.org/2005/Atom'
|
xmlns:atom10='http://www.w3.org/2005/Atom'
|
||||||
xmlns:atom='http://www.w3.org/2005/Atom'>
|
xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
<!-- Atom 1.0 Syndication Format -->
|
|
||||||
<xsl:output
|
|
||||||
media-type='application/atom+xml' />
|
|
||||||
<xsl:template match='/atom:feed'>
|
<xsl:template match='/atom:feed'>
|
||||||
<!-- index right-to-left language codes -->
|
<!-- index right-to-left language codes -->
|
||||||
<!-- TODO http://www.w3.org/TR/xpath/#function-lang -->
|
<!-- TODO http://www.w3.org/TR/xpath/#function-lang -->
|
||||||
|
@ -38,7 +35,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
<xsl:call-template name='metadata'>
|
<xsl:call-template name='metadata'>
|
||||||
<xsl:with-param name='name' select='"generator"' />
|
<xsl:with-param name='name' select='"generator"' />
|
||||||
<xsl:with-param name='content' select='StreamBurner' />
|
<xsl:with-param name='content' select='Rivista' />
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
<xsl:call-template name='metadata'>
|
<xsl:call-template name='metadata'>
|
||||||
<xsl:with-param name='name' select='"mimetype"' />
|
<xsl:with-param name='name' select='"mimetype"' />
|
||||||
|
@ -52,7 +49,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
<xsl:when test='atom:entry'>
|
<xsl:when test='atom:entry'>
|
||||||
<xsl:value-of select='atom:entry/atom:title'/>
|
<xsl:value-of select='atom:entry/atom:title'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>StreamBurner</xsl:otherwise>
|
<xsl:otherwise>Rivista</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</title>
|
</title>
|
||||||
<!-- TODO media='print' -->
|
<!-- TODO media='print' -->
|
||||||
|
@ -90,15 +87,6 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
SubToMe
|
SubToMe
|
||||||
</a>
|
</a>
|
||||||
<a href='https://git.xmpp-it.net/sch/PubSubToAtom'
|
|
||||||
title='About PubSub To Atom.'>
|
|
||||||
About
|
|
||||||
</a>
|
|
||||||
<a href='https://aboutfeeds.com/'
|
|
||||||
title='Of the benefits of syndication feed.'
|
|
||||||
id='aboutfeeds'>
|
|
||||||
Feeds
|
|
||||||
</a>
|
|
||||||
<a href='https://xmpp.org/about/technology-overview/'
|
<a href='https://xmpp.org/about/technology-overview/'
|
||||||
title='Of the benefits of XMPP.'>
|
title='Of the benefits of XMPP.'>
|
||||||
XMPP
|
XMPP
|
||||||
|
@ -107,6 +95,11 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
title='Syndictaion and PubSub.'>
|
title='Syndictaion and PubSub.'>
|
||||||
Groupchat
|
Groupchat
|
||||||
</a>
|
</a>
|
||||||
|
<a href='https://aboutfeeds.com/'
|
||||||
|
title='Of the benefits of syndication feed.'
|
||||||
|
id='aboutfeeds'>
|
||||||
|
Help
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div id='feed'>
|
<div id='feed'>
|
||||||
<div id='header'>
|
<div id='header'>
|
||||||
|
@ -120,7 +113,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
<xsl:value-of select='atom:entry/atom:title'/>
|
<xsl:value-of select='atom:entry/atom:title'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
StreamBurner
|
No title
|
||||||
</xsl:otherwise>
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -138,6 +131,9 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
<xsl:attribute name='class'><xsl:text>date</xsl:text></xsl:attribute>
|
<xsl:attribute name='class'><xsl:text>date</xsl:text></xsl:attribute>
|
||||||
<xsl:value-of select='atom:entry/atom:published'/>
|
<xsl:value-of select='atom:entry/atom:published'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
Rivista XMPP Journal Publisher
|
||||||
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
@ -145,12 +141,12 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
<div id='menu'>
|
<div id='menu'>
|
||||||
<h3>Latest Posts</h3>
|
<h3>Latest Posts</h3>
|
||||||
<!-- xsl:for-each select='atom:entry[position() <21]' -->
|
<!-- xsl:for-each select='atom:entry[position() <21]' -->
|
||||||
<ul>
|
<ol>
|
||||||
<xsl:for-each select='atom:entry[not(position() > 20)]'>
|
<xsl:for-each select='atom:entry[not(position() > 20)]'>
|
||||||
<li>
|
<li>
|
||||||
<xsl:element name='a'>
|
<xsl:element name='a'>
|
||||||
<xsl:attribute name='href'>
|
<xsl:attribute name='href'>
|
||||||
<xsl:text>#stremburner-</xsl:text>
|
<xsl:text>#rivista-</xsl:text>
|
||||||
<xsl:value-of select='position()'/>
|
<xsl:value-of select='position()'/>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
|
@ -164,7 +160,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
</xsl:element>
|
</xsl:element>
|
||||||
</li>
|
</li>
|
||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
</ul>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
<div id='articles'>
|
<div id='articles'>
|
||||||
|
@ -180,19 +176,16 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
<xsl:element name='a'>
|
<xsl:element name='a'>
|
||||||
<xsl:attribute name='href'>
|
<xsl:attribute name='href'>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test='atom:link[contains(@rel,"alternate")]'>
|
<xsl:when test='atom:link[@rel="self"]'>
|
||||||
<xsl:value-of select='atom:link[contains(@rel,"alternate")]/@href'/>
|
<xsl:value-of select='atom:link[@rel="self"]/@href'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
<xsl:value-of select='atom:link/@href'/>
|
<xsl:value-of select='atom:link/@href'/>
|
||||||
</xsl:otherwise>
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<xsl:attribute name='title'>
|
|
||||||
<xsl:value-of select='atom:title'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
<xsl:attribute name='id'>
|
<xsl:attribute name='id'>
|
||||||
<xsl:text>stremburner-</xsl:text>
|
<xsl:text>rivista-</xsl:text>
|
||||||
<xsl:value-of select='position()'/>
|
<xsl:value-of select='position()'/>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
|
@ -230,60 +223,96 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
</span>
|
</span>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
<!-- div class='posted' -->
|
<!-- entry date -->
|
||||||
<!-- entry author -->
|
<xsl:element name='h4'>
|
||||||
<!-- xsl:if test='atom:author'>
|
|
||||||
<span class='author'>
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test='atom:author/atom:email'>
|
|
||||||
<xsl:element name='a'>
|
|
||||||
<xsl:attribute name='href'>
|
|
||||||
<xsl:text>mailto:</xsl:text>
|
|
||||||
<xsl:value-of select='atom:author/atom:email'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
<xsl:attribute name='title'>
|
|
||||||
<xsl:text>Send an Email to </xsl:text>
|
|
||||||
<xsl:value-of select='atom:author/atom:email'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
<xsl:value-of select='atom:author/atom:name'/>
|
|
||||||
</xsl:element>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test='atom:author/atom:uri'>
|
|
||||||
<xsl:element name='a'>
|
|
||||||
<xsl:attribute name='href'>
|
|
||||||
<xsl:value-of select='atom:author/atom:uri'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
<xsl:attribute name='title'>
|
|
||||||
<xsl:value-of select='atom:author/atom:summary'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
<xsl:value-of select='atom:author/atom:name'/>
|
|
||||||
</xsl:element>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
|
||||||
<xsl:value-of select='atom:name'/>
|
|
||||||
</xsl:otherwise>
|
|
||||||
</xsl:choose>
|
|
||||||
</span>
|
|
||||||
</xsl:if -->
|
|
||||||
<!-- entry date -->
|
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test='atom:updated'>
|
<xsl:when test='atom:updated'>
|
||||||
<h4 class='updated'>
|
<xsl:attribute name='class'>
|
||||||
<xsl:value-of select='atom:updated'/>
|
<xsl:text>updated</xsl:text>
|
||||||
</h4>
|
</xsl:attribute>
|
||||||
|
<xsl:value-of select='atom:updated'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test='atom:published'>
|
<xsl:when test='atom:published'>
|
||||||
<h4 class='published'>
|
<xsl:attribute name='class'>
|
||||||
<xsl:value-of select='atom:published'/>
|
<xsl:text>published</xsl:text>
|
||||||
</h4>
|
</xsl:attribute>
|
||||||
|
<xsl:value-of select='atom:published'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
<h4 class='warning atom1 published'></h4>
|
<h4 class='warning atom1 published'></h4>
|
||||||
</xsl:otherwise>
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
<!-- /div -->
|
</xsl:element>
|
||||||
|
<!-- entry author -->
|
||||||
|
<xsl:if test='atom:author'>
|
||||||
|
<h4 class='author'>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test='atom:author/atom:email'>
|
||||||
|
<xsl:element name='a'>
|
||||||
|
<xsl:attribute name='href'>
|
||||||
|
<xsl:text>mailto:</xsl:text>
|
||||||
|
<xsl:value-of select='atom:author/atom:email'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:attribute name='title'>
|
||||||
|
<xsl:text>Send an Email to </xsl:text>
|
||||||
|
<xsl:value-of select='atom:author/atom:email'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:value-of select='atom:author/atom:name'/>
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test='atom:author/atom:uri'>
|
||||||
|
<xsl:element name='a'>
|
||||||
|
<xsl:attribute name='href'>
|
||||||
|
<xsl:value-of select='atom:author/atom:uri'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:attribute name='title'>
|
||||||
|
<xsl:value-of select='atom:author/atom:summary'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:value-of select='atom:author/atom:name'/>
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test='atom:author/atom:name'>
|
||||||
|
<xsl:text>By </xsl:text>
|
||||||
|
<xsl:value-of select='atom:author/atom:name'/>
|
||||||
|
</xsl:when>
|
||||||
|
</xsl:choose>
|
||||||
|
</h4>
|
||||||
|
</xsl:if>
|
||||||
|
<h5 class='related'>
|
||||||
|
<xsl:if test='atom:link[@rel="alternate" and @type="x-scheme-handler/xmpp"]'>
|
||||||
|
<xsl:element name='a'>
|
||||||
|
<xsl:attribute name='href'>
|
||||||
|
<xsl:value-of select='atom:link[@rel="alternate" and @type="x-scheme-handler/xmpp"]/@href'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
💡️ XMPP
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test='atom:link[@rel="replies"]'>
|
||||||
|
<xsl:element name='a'>
|
||||||
|
<xsl:attribute name='href'>
|
||||||
|
<xsl:value-of select='atom:link[@rel="replies"]/@href'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
💬 Discussion
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test='atom:link[@rel="alternate" and @type="text/html"]'>
|
||||||
|
<xsl:element name='a'>
|
||||||
|
<xsl:attribute name='href'>
|
||||||
|
<xsl:value-of select='atom:link[@rel="alternate" and @type="text/html"]/@href'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
📜 HTML
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test='atom:link[@rel="related" and @type="text/html"]'>
|
||||||
|
<xsl:element name='a'>
|
||||||
|
<xsl:attribute name='href'>
|
||||||
|
<xsl:value-of select='atom:link[@rel="related" and @type="text/html"]/@href'/>
|
||||||
|
</xsl:attribute>
|
||||||
|
📜 HTML (Related)
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
</h5>
|
||||||
<!-- entry content -->
|
<!-- entry content -->
|
||||||
<!-- entry summary of GitLab Atom Syndication Feeds -->
|
|
||||||
<xsl:if test='atom:content or atom:summary'>
|
<xsl:if test='atom:content or atom:summary'>
|
||||||
<div class='content'>
|
<div class='content'>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
|
@ -331,75 +360,63 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
</div>
|
</div>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
<!-- entry enclosure -->
|
<!-- entry enclosure -->
|
||||||
<xsl:if test='atom:link[contains(@rel,"enclosure")]'>
|
<xsl:if test='atom:link[@rel="enclosure"]'>
|
||||||
<div class='enclosure' title='Right-click and Save link as…'>
|
<h4>Enclosures</h4>
|
||||||
<xsl:for-each select='atom:link[contains(@rel,"enclosure")]'>
|
<div class='enclosures' title='Right-click and Save link as…'>
|
||||||
<xsl:element name='span'>
|
<xsl:for-each select='atom:link[@rel="enclosure"]'>
|
||||||
<xsl:attribute name='icon'>
|
<div class='enclosure' title='Right-click and Save link as…'>
|
||||||
<xsl:value-of select='substring-before(@type,"/")'/>
|
<xsl:element name='span'>
|
||||||
</xsl:attribute>
|
<xsl:attribute name='icon'>
|
||||||
</xsl:element>
|
<xsl:value-of select='substring-before(@type,"/")'/>
|
||||||
<xsl:element name='a'>
|
</xsl:attribute>
|
||||||
<xsl:attribute name='href'>
|
</xsl:element>
|
||||||
<xsl:value-of select='@href'/>
|
<xsl:element name='a'>
|
||||||
</xsl:attribute>
|
<xsl:attribute name='href'>
|
||||||
<xsl:attribute name='download'/>
|
<xsl:value-of select='@href'/>
|
||||||
<xsl:call-template name='extract-filename'>
|
</xsl:attribute>
|
||||||
<xsl:with-param name='url' select='@href' />
|
<xsl:attribute name='download'/>
|
||||||
</xsl:call-template>
|
<xsl:call-template name='extract-filename'>
|
||||||
</xsl:element>
|
<xsl:with-param name='url' select='@href' />
|
||||||
<xsl:element name='span'>
|
</xsl:call-template>
|
||||||
<xsl:attribute name='class'>
|
</xsl:element>
|
||||||
<xsl:value-of select='substring-before(@type,"/")'/>
|
<xsl:element name='span'>
|
||||||
</xsl:attribute>
|
<xsl:attribute name='class'>
|
||||||
</xsl:element>
|
<xsl:value-of select='substring-before(@type,"/")'/>
|
||||||
<xsl:if test='@length > 0'>
|
</xsl:attribute>
|
||||||
<xsl:call-template name='transform-filesize'>
|
</xsl:element>
|
||||||
<xsl:with-param name='length' select='@length' />
|
<xsl:if test='@length > 0'>
|
||||||
</xsl:call-template>
|
<xsl:call-template name='transform-filesize'>
|
||||||
</xsl:if>
|
<xsl:with-param name='length' select='@length' />
|
||||||
<xsl:element name='br'/>
|
</xsl:call-template>
|
||||||
</xsl:for-each>
|
</xsl:if>
|
||||||
<xsl:for-each select='media:content'>
|
<br/>
|
||||||
<xsl:element name='span'>
|
</div>
|
||||||
<xsl:attribute name='icon'>
|
|
||||||
<xsl:value-of select='@medium'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
</xsl:element>
|
|
||||||
<xsl:element name='a'>
|
|
||||||
<xsl:attribute name='href'>
|
|
||||||
<xsl:value-of select='@url'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
<xsl:attribute name='download'/>
|
|
||||||
<xsl:call-template name='extract-filename'>
|
|
||||||
<xsl:with-param name='url' select='@url' />
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:element>
|
|
||||||
<xsl:element name='span'>
|
|
||||||
<xsl:attribute name='class'>
|
|
||||||
<xsl:value-of select='@medium'/>
|
|
||||||
</xsl:attribute>
|
|
||||||
</xsl:element>
|
|
||||||
<xsl:if test='@fileSize > 0'>
|
|
||||||
<xsl:call-template name='transform-filesize'>
|
|
||||||
<xsl:with-param name='length' select='@fileSize' />
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:if>
|
|
||||||
<xsl:element name='br'/>
|
|
||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
</div>
|
</div>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
</div>
|
</div>
|
||||||
<!-- entry id -->
|
<!-- entry id -->
|
||||||
<xsl:if test='not(atom:id)'>
|
<xsl:if test='not(atom:id)'>
|
||||||
<div class='warning atom1 id'></div>
|
<div class='warning atom1 id'>No entry ID</div>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
</li>
|
</li>
|
||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
</ul>
|
</ul>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
<h3 class='notice no-entry'>No content.</h3>
|
<ul>
|
||||||
|
<li>
|
||||||
|
<div class='entry'>
|
||||||
|
<h3 class='title'>
|
||||||
|
<a href='javascript:alert("Please check that the mother PubSub node is populated with content.")'>
|
||||||
|
No content
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
<h4>This entry is empty</h4>
|
||||||
|
<div class='content'>Please check that the mother PubSub node is populated with content.</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</xsl:otherwise>
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</div>
|
</div>
|
||||||
|
@ -417,8 +434,16 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
title='The Social Platform Shaped For Your Community.'>
|
title='The Social Platform Shaped For Your Community.'>
|
||||||
Movim
|
Movim
|
||||||
</a>
|
</a>
|
||||||
|
<a href='https://git.xmpp-it.net/sch/Rivista'
|
||||||
|
title='A Journal Publisher And Browser For XMPP.'>
|
||||||
|
Rivista
|
||||||
|
</a>
|
||||||
|
<a href='https://github.com/SeveFP/Reeder'
|
||||||
|
Title='An XMPP-Based Feed Reader.'>
|
||||||
|
Reeder
|
||||||
|
</a>
|
||||||
<a href='https://modernxmpp.org/'
|
<a href='https://modernxmpp.org/'
|
||||||
title='A Project To Improve The Quality Of User-To-User Messaging Applications That Use Xmpp.'>
|
title='A Project To Improve The Quality Of User-To-User Messaging Applications That Use XMPP.'>
|
||||||
Modern
|
Modern
|
||||||
</a>
|
</a>
|
||||||
<a href='https://xmpp.org/'
|
<a href='https://xmpp.org/'
|
||||||
|
@ -433,12 +458,15 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
||||||
<!-- note -->
|
<!-- note -->
|
||||||
<p id='note'>
|
<p id='note'>
|
||||||
<i>
|
<i>
|
||||||
This is an XMPP news feed which is conveyed as an XHTML
|
This is an Atom document which is conveyed as an XHTML
|
||||||
document, and it can even be viewed by a syndication
|
document;
|
||||||
feed reader which provides automated notifications on
|
This document can also be viewed with a Syndication Feed
|
||||||
desktop and mobile. <span id="selection-link">Click
|
Reader (also referred to as News Reader or RSS Reader)
|
||||||
here</span> for a selection of software and pick the
|
which provides automated news updates and notifications
|
||||||
ones that would fit you best!
|
on desktop and mobile.
|
||||||
|
<span id="selection-link">Click here</span> for a
|
||||||
|
selection of software and pick the ones that would fit
|
||||||
|
to you best!
|
||||||
</i>
|
</i>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
10
xsl/opml.xsl
10
xsl/opml.xsl
|
@ -1,17 +1,19 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2016 - 2017 Schimon Jehuda. Released under MIT license
|
Copyright (C) 2016 - 2024 Schimon Jehuda. Released under MIT license
|
||||||
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
|
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
|
||||||
include https://schimon.i2p/ in attribute name='generator' of
|
include https://schimon.i2p/ in attribute name='generator' of
|
||||||
element <meta/> inside of html element </head>
|
element <meta/> inside of html element </head>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
<xsl:output method = 'html'
|
<xsl:output encoding = 'UTF-8'
|
||||||
indent = 'yes'
|
indent = 'yes'
|
||||||
omit-xml-decleration='no' />
|
media-type = 'text/x-opml'
|
||||||
<!-- Atom 1.0 Syndication Format -->
|
method = 'html'
|
||||||
|
version = '4.01' />
|
||||||
|
<!-- Outline Processor Markup Language 1.0 -->
|
||||||
<xsl:include href='opml_as_xhtml.xsl'/>
|
<xsl:include href='opml_as_xhtml.xsl'/>
|
||||||
<!-- set page metadata -->
|
<!-- set page metadata -->
|
||||||
<xsl:include href='metadata.xsl'/>
|
<xsl:include href='metadata.xsl'/>
|
||||||
|
|
|
@ -10,9 +10,6 @@ element <meta/> inside of html element </head>
|
||||||
<xsl:stylesheet version='1.0'
|
<xsl:stylesheet version='1.0'
|
||||||
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
|
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
|
||||||
xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
<!-- Outline Processor Markup Language 1.0 -->
|
|
||||||
<xsl:output
|
|
||||||
media-type='text/x-opml' />
|
|
||||||
<xsl:template match='/opml'>
|
<xsl:template match='/opml'>
|
||||||
<!-- index right-to-left language codes -->
|
<!-- index right-to-left language codes -->
|
||||||
<!-- TODO http://www.w3.org/TR/xpath/#function-lang -->
|
<!-- TODO http://www.w3.org/TR/xpath/#function-lang -->
|
||||||
|
@ -33,7 +30,7 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
<xsl:call-template name='metadata'>
|
<xsl:call-template name='metadata'>
|
||||||
<xsl:with-param name='name' select='"generator"' />
|
<xsl:with-param name='name' select='"generator"' />
|
||||||
<xsl:with-param name='content' select='StreamBurner' />
|
<xsl:with-param name='content' select='Rivista' />
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
<xsl:call-template name='metadata'>
|
<xsl:call-template name='metadata'>
|
||||||
<xsl:with-param name='name' select='"mimetype"' />
|
<xsl:with-param name='name' select='"mimetype"' />
|
||||||
|
@ -41,10 +38,10 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
<title>
|
<title>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test='title and not(title="")'>
|
<xsl:when test='//head/title and not(//head/title="")'>
|
||||||
<xsl:value-of select='title'/>
|
<xsl:value-of select='//head/title'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>StreamBurner</xsl:otherwise>
|
<xsl:otherwise>Rivista OPML</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</title>
|
</title>
|
||||||
<!-- TODO media='print' -->
|
<!-- TODO media='print' -->
|
||||||
|
@ -54,20 +51,9 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
<xsl:if test='$rtl'>
|
<xsl:if test='$rtl'>
|
||||||
<link id='semitic' href='/css/stylesheet-rtl.css' rel='stylesheet' type='text/css' />
|
<link id='semitic' href='/css/stylesheet-rtl.css' rel='stylesheet' type='text/css' />
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
<script type='text/javascript' src='/script/marked.min.js'/>
|
|
||||||
<script type='text/javascript' src='/script/postprocess.js'/>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='actions'>
|
<div id='actions'>
|
||||||
<a href='https://git.xmpp-it.net/sch/PubSubToAtom'
|
|
||||||
title='About PubSub To Atom.'>
|
|
||||||
About
|
|
||||||
</a>
|
|
||||||
<a href='https://aboutfeeds.com/'
|
|
||||||
title='Of the benefits of syndication feed.'
|
|
||||||
id='aboutfeeds'>
|
|
||||||
Feeds
|
|
||||||
</a>
|
|
||||||
<a href='https://xmpp.org/about/technology-overview/'
|
<a href='https://xmpp.org/about/technology-overview/'
|
||||||
title='Of the benefits of XMPP.'>
|
title='Of the benefits of XMPP.'>
|
||||||
XMPP
|
XMPP
|
||||||
|
@ -76,6 +62,11 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
title='Syndictaion and PubSub.'>
|
title='Syndictaion and PubSub.'>
|
||||||
Groupchat
|
Groupchat
|
||||||
</a>
|
</a>
|
||||||
|
<a href='https://aboutfeeds.com/'
|
||||||
|
title='Of the benefits of syndication feed.'
|
||||||
|
id='aboutfeeds'>
|
||||||
|
Help
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div id='feed'>
|
<div id='feed'>
|
||||||
<div id='header'>
|
<div id='header'>
|
||||||
|
@ -85,11 +76,8 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
<xsl:when test='//head/title and not(//head/title="") and count(//outline) > 1'>
|
<xsl:when test='//head/title and not(//head/title="") and count(//outline) > 1'>
|
||||||
<xsl:value-of select='//head/title'/>
|
<xsl:value-of select='//head/title'/>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test='//outline'>
|
|
||||||
<xsl:value-of select='//outline/@text'/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
StreamBurner OPML Feed
|
Rivista OPML Collection
|
||||||
</xsl:otherwise>
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -109,12 +97,12 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
<div id='menu'>
|
<div id='menu'>
|
||||||
<h3>Subscriptions</h3>
|
<h3>Subscriptions</h3>
|
||||||
<!-- xsl:for-each select='outline[position() <21]' -->
|
<!-- xsl:for-each select='outline[position() <21]' -->
|
||||||
<ul>
|
<ol>
|
||||||
<xsl:for-each select='//outline[not(position() > 20)]'>
|
<xsl:for-each select='//outline[not(position() > 20)]'>
|
||||||
<li>
|
<li>
|
||||||
<xsl:element name='a'>
|
<xsl:element name='a'>
|
||||||
<xsl:attribute name='href'>
|
<xsl:attribute name='href'>
|
||||||
<xsl:text>#stremburner-</xsl:text>
|
<xsl:text>#rivista-</xsl:text>
|
||||||
<xsl:value-of select='position()'/>
|
<xsl:value-of select='position()'/>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
|
@ -128,7 +116,7 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
</xsl:element>
|
</xsl:element>
|
||||||
</li>
|
</li>
|
||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
</ul>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
<div id='articles'>
|
<div id='articles'>
|
||||||
|
@ -149,7 +137,7 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
<xsl:value-of select='@text'/>
|
<xsl:value-of select='@text'/>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<xsl:attribute name='id'>
|
<xsl:attribute name='id'>
|
||||||
<xsl:text>stremburner-</xsl:text>
|
<xsl:text>rivista-</xsl:text>
|
||||||
<xsl:value-of select='position()'/>
|
<xsl:value-of select='position()'/>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
|
@ -193,8 +181,16 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
title='The Social Platform Shaped For Your Community.'>
|
title='The Social Platform Shaped For Your Community.'>
|
||||||
Movim
|
Movim
|
||||||
</a>
|
</a>
|
||||||
|
<a href='https://git.xmpp-it.net/sch/Rivista'
|
||||||
|
title='A Journal Publisher And Browser For XMPP.'>
|
||||||
|
Rivista
|
||||||
|
</a>
|
||||||
|
<a href='https://github.com/SeveFP/Reeder'
|
||||||
|
Title='An XMPP-Based Feed Reader.'>
|
||||||
|
Reeder
|
||||||
|
</a>
|
||||||
<a href='https://modernxmpp.org/'
|
<a href='https://modernxmpp.org/'
|
||||||
title='A Project To Improve The Quality Of User-To-User Messaging Applications That Use Xmpp.'>
|
title='A Project To Improve The Quality Of User-To-User Messaging Applications That Use XMPP.'>
|
||||||
Modern
|
Modern
|
||||||
</a>
|
</a>
|
||||||
<a href='https://xmpp.org/'
|
<a href='https://xmpp.org/'
|
||||||
|
@ -209,15 +205,16 @@ xmlns:xml='http://www.w3.org/XML/1998/namespace'>
|
||||||
<!-- note -->
|
<!-- note -->
|
||||||
<p id='note'>
|
<p id='note'>
|
||||||
<i>
|
<i>
|
||||||
This is an
|
This is an OPML document which is conveyed as an XHTML
|
||||||
<b title ='Outline Processor Markup Language'>OPML</b>
|
document;
|
||||||
document which is conveyed as an XHTML document; This
|
This document includes a collection of subscriptions,
|
||||||
document includes a list of subscriptionsis and is
|
and it can be imported to a Syndication Feed Reader
|
||||||
intended to be imported to a syndication feed reader
|
(also referred to as News Reader or RSS Reader) reader
|
||||||
which provides automated notifications on desktop and
|
which provides automated news updates and notifications
|
||||||
mobile. <span id="selection-link">Click here</span> for
|
on desktop and mobile.
|
||||||
a selection of software and pick the ones that would fit
|
<span id="selection-link">Click here</span> for a
|
||||||
you best!
|
selection of software and pick the ones that would fit
|
||||||
|
to you best!
|
||||||
</i>
|
</i>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in a new issue