From d1f1edbaca09b80b18571c0acd67305ca87544e7 Mon Sep 17 00:00:00 2001 From: "Schimon Jehudah, Adv." Date: Fri, 12 Jul 2024 15:39:17 +0300 Subject: [PATCH] Add OPML support; Set a new default node (Thank you roughnecks); Improve CSS, JS, XSLT; Neglect external libraries to produce syndications. --- configuration.toml | 4 +- css/stylesheet.css | 25 ++- pubsub_to_atom.py | 256 +++++++++++++++++++------------ script/postprocess.js | 139 +++++++++-------- xsl/{stylesheet.xsl => atom.xsl} | 13 +- xsl/atom_as_xhtml.xsl | 23 ++- xsl/opml.xsl | 18 +++ xsl/opml_as_xhtml.xsl | 226 +++++++++++++++++++++++++++ 8 files changed, 519 insertions(+), 185 deletions(-) rename xsl/{stylesheet.xsl => atom.xsl} (86%) create mode 100644 xsl/opml.xsl create mode 100644 xsl/opml_as_xhtml.xsl diff --git a/configuration.toml b/configuration.toml index 06f20bb..e99e40a 100644 --- a/configuration.toml +++ b/configuration.toml @@ -5,8 +5,8 @@ pass = "" # Password. # A default node, when no arguments are set. [default] -pubsub = "blog.jmp.chat" # Jabber ID. -nodeid = "urn:xmpp:microblog:0" # Node ID. +pubsub = "pubsub.woodpeckersnest.space" # Jabber ID. +nodeid = "PlanetJabber" # Node ID. # Settings [settings] diff --git a/css/stylesheet.css b/css/stylesheet.css index a919cd0..e8a8ad2 100644 --- a/css/stylesheet.css +++ b/css/stylesheet.css @@ -7,6 +7,17 @@ body { background: #000; } +code, pre { + overflow: auto; + display: inline-block; + max-height: 500px; + max-width: 100%; } + +img, video { + width: auto; + height: auto; +} + h1#title, h2#subtitle, #actions, #references { text-align: center; text-transform: uppercase; @@ -64,6 +75,7 @@ h1#title, h2#subtitle, #actions, #references { width: 20%; } +#articles #journal ol, #articles #journal ul { /* height: 500px; */ line-height: 160%; @@ -74,24 +86,25 @@ h1#title, h2#subtitle, #actions, #references { font-weight: bold; } -#articles > ul > li > div > p.content { +#articles div.content { font-size: 120%; - line-height: 30px; + line-height: 200%; margin: auto; padding-left: 2%; padding-right: 10%; /* text-align: justify; */ + word-wrap: break-word; } -#articles > ul > li > div.entry { +#articles div.entry { padding-bottom: 0.67em; } -#articles > ul > li > div.entry h1 { +#articles div.entry h1 { font-size: 2vw; } -#articles > ul > li > div.entry h2 { +#articles div.entry h2 { font-size: 1.5vw; } @@ -138,7 +151,7 @@ h1#title, h2#subtitle, #actions, #references { text-decoration: underline; } -@media (max-width: 950px) { +@media (max-width: 1525px) { #articles { display: unset; } diff --git a/pubsub_to_atom.py b/pubsub_to_atom.py index ccb4e3c..475eea2 100644 --- a/pubsub_to_atom.py +++ b/pubsub_to_atom.py @@ -2,10 +2,10 @@ # -*- coding: utf-8 -*- import datetime +from dateutil import parser from fastapi import FastAPI, Request, Response from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles -import feedgenerator import json from slixmpp import ClientXMPP from slixmpp.exceptions import IqError, IqTimeout @@ -57,12 +57,11 @@ async def view_pubsub(request: Request): if pubsub and node and item_id: iq = await get_node_item(pubsub, node, item_id) if iq: - link = 'xmpp:{pubsub}?;node={node};item={item}'.format( - pubsub=pubsub, node=node, item=item_id) - xml_atom = generate_rfc_4287(iq, link) + link = form_an_item_link(pubsub, node, item_id) + xml_atom = generate_atom(iq, link) iq = await get_node_items(pubsub, node) if iq: - generate_json(iq, node) + generate_json(iq) else: operator = get_configuration('settings')['operator'] json_data = [{'title' : 'Error retrieving items list.', @@ -79,7 +78,8 @@ async def view_pubsub(request: Request): else: text = 'Please check that PubSub node and item are valid and accessible.' xml_atom = error_message(text) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') # try: # iq = await get_node_items(pubsub, node) @@ -94,32 +94,37 @@ async def view_pubsub(request: Request): elif pubsub and node: iq = await get_node_items(pubsub, node) if iq: - link = form_a_link(pubsub, node) - xml_atom = generate_rfc_4287(iq, link) + link = form_a_node_link(pubsub, node) + xml_atom = generate_atom(iq, link) else: text = 'Please check that PubSub node is valid and accessible.' xml_atom = error_message(text) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') elif pubsub: iq = await get_nodes(pubsub) if iq: link = 'xmpp:{pubsub}'.format(pubsub=pubsub) - result = pubsub_to_opml(iq) + xml_opml = generate_opml(iq) + result = append_stylesheet(xml_opml, 'opml.xsl') else: text = 'Please check that PubSub Jabber ID is valid and accessible.' xml_atom = error_message(text) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') elif node: text = 'PubSub parameter is missing.' xml_atom = error_message(text) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') # else: # result = ('Mandatory parameter PubSub and ' # 'optional parameter Node are missing.') else: text = 'The given domain {} is not allowed.'.format(pubsub) xml_atom = error_message(text) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') default = get_configuration('default') if not result: if default['pubsub'] and default['nodeid']: @@ -127,20 +132,23 @@ async def view_pubsub(request: Request): pubsub = default['pubsub'] node = default['nodeid'] iq = await get_node_items(pubsub, node) - link = form_a_link(pubsub, node) + link = form_a_node_link(pubsub, node) xml_atom = generate_rfc_4287(iq, link) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') elif not settings['service']: pubsub = default['pubsub'] node = default['nodeid'] iq = await get_node_items(pubsub, node) - link = form_a_link(pubsub, node) + link = form_a_node_link(pubsub, node) xml_atom = generate_rfc_4287(iq, link) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') else: text = 'Please contact the administrator and ask him to set default PubSub and Node ID.' xml_atom = error_message(text) - result = append_stylesheet(xml_atom) + result = append_stylesheet( + xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom') response = Response(content=result, media_type="application/xml") return response @@ -166,104 +174,125 @@ async def get_node_items(pubsub, node): async def get_nodes(pubsub): try: - await xmpp.plugin['xep_0060'].get_nodes(pubsub, timeout=5) + iq = await xmpp.plugin['xep_0060'].get_nodes(pubsub, timeout=5) return iq except (IqError, IqTimeout) as e: print(e) -def form_a_link(pubsub, node): +def form_a_node_link(pubsub, node): link = 'xmpp:{pubsub}?;node={node}'.format(pubsub=pubsub, node=node) return link +def form_an_item_link(pubsub, node, item_id): + link = 'xmpp:{pubsub}?;node={node};item={item}'.format( + pubsub=pubsub, node=node, item=item_id) + return link + def error_message(text): """Error message in RFC 4287: The Atom Syndication Format.""" - feed = feedgenerator.Atom1Feed( - description = ('This is a syndication feed generated with XMPP Journal ' - 'Publisher (XJP), which conveys XEP-0060: Publish-' - 'Subscribe nodes to standard RFC 4287: The Atom ' - 'Syndication Format.'), - language = 'en', - link = '', - subtitle = 'XMPP Journal Publisher', - title = 'StreamBurner') - namespace = '{http://www.w3.org/2005/Atom}' - feed_url = 'gemini://schimon.i2p/' - # create entry - feed.add_item( - description = text, - # enclosure = feedgenerator.Enclosure(enclosure, enclosure_size, enclosure_type) if args.entry_enclosure else None, - link = '', - # pubdate = updated, - title = 'Error', - # unique_id = '' - ) - xml_atom = feed.writeString('utf-8') - xml_atom_extended = append_element( - xml_atom, - 'generator', - 'XMPP Journal Publisher (XJP)') - return xml_atom_extended + title = 'StreamBurner' + subtitle = 'XMPP Journal Publisher' + description = ('This is a syndication feed generated with XMPP Journal ' + 'Publisher, which conveys XEP-0060: Publish-Subscribe ' + 'nodes to standard RFC 4287: The Atom Syndication Format.') + language = 'en' + feed = ET.Element("feed") + feed.set('xmlns', 'http://www.w3.org/2005/Atom') + ET.SubElement(feed, 'title', {'type': 'text'}).text = title + ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle + ET.SubElement(feed, 'author', {'name':'XMPP Journal Publisher','email':'xjp@schimon.i2p'}) + ET.SubElement(feed, 'generator', { + 'uri': 'https://git.xmpp-it.net/sch/XMPPJournalPublisher', + 'version': '0.1'}).text = 'XMPP Journal Publisher (XJP)' + ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat() + entry = ET.SubElement(feed, 'entry') + ET.SubElement(entry, 'title').text = 'Error' + ET.SubElement(entry, 'id').text = 'xjp-error' + 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, 'summary', {'type': summary_type_text}).text = summary_text + ET.SubElement(entry, 'content', {'type': 'text'}).text = text + return ET.tostring(feed, encoding='unicode') -def generate_rfc_4287(iq, link): - """Convert XEP-0060: Publish-Subscribe to RFC 4287: The Atom Syndication Format.""" - feed = feedgenerator.Atom1Feed( - description = ('This is a syndication feed generated with PubSub To ' - 'Atom, which conveys XEP-0060: Publish-Subscribe nodes ' - 'to standard RFC 4287: The Atom Syndication Format.'), - language = iq['pubsub']['items']['lang'], - link = link, - subtitle = 'XMPP PubSub Syndication Feed', - title = iq['pubsub']['items']['node']) - # See also iq['pubsub']['items']['substanzas'] - entries = iq['pubsub']['items'] - for entry in entries: - item = entry['payload'] +# generate_rfc_4287 +def generate_atom(iq, link): + """Generate an Atom Syndication Format (RFC 4287) from a Publish-Subscribe (XEP-0060) node items.""" + pubsub = iq['from'].bare + node = iq['pubsub']['items']['node'] + title = node + link = link + # link = form_a_node_link(pubsub, node) + subtitle = 'XMPP PubSub Syndication Feed' + description = ('This is a syndication feed generated with XMPP Journal ' + 'Publisher, which conveys XEP-0060: Publish-Subscribe ' + 'nodes to standard RFC 4287: The Atom Syndication Format.') + language = iq['pubsub']['items']['lang'] + items = iq['pubsub']['items'] + feed = ET.Element("feed") + feed.set('xmlns', 'http://www.w3.org/2005/Atom') + ET.SubElement(feed, 'title', {'type': 'text'}).text = title + ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle + ET.SubElement(feed, 'link', {'rel': 'self', 'href': link}) + ET.SubElement(feed, 'generator', { + 'uri': 'https://git.xmpp-it.net/sch/XMPPJournalPublisher', + 'version': '0.1'}).text = 'XMPP Journal Publisher (XJP)' + ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat() + for item in items: + item_id = item['id'] + item_payload = item['payload'] namespace = '{http://www.w3.org/2005/Atom}' - title = item.find(namespace + 'title') - title = None if title == None else title.text - updated = item.find(namespace + 'updated') - updated = None if updated == None else updated.text - published = item.find(namespace + 'published') - published = None if published == None else published.text - if not updated and not published: updated = datetime.datetime.utcnow().isoformat() - content = item.find(namespace + 'content') - content = 'No content' if content == None else content.text - link = item.find(namespace + 'link') - link = '' if link == None else link.attrib['href'] - author = item.find(namespace + 'author') + title = item_payload.find(namespace + 'title') + title_text = None if title == None else title.text + # link = item_payload.find(namespace + 'link') + # link_href = '' if link == None else link.attrib['href'] + link_href = form_an_item_link(pubsub, node, item_id) + if not title_text or not link_href: continue + content = item_payload.find(namespace + 'content') + content_text = 'No content' if content == None else content.text + if content.attrib: + content_type = content.attrib['type'] if 'type' in content.attrib else 'text' + content_type_text = 'html' if 'html' in content_type else 'text' + published = item_payload.find(namespace + 'published') + published_text = None if published == None else published.text + if published: published_dt = parser.parse(published_text) + updated = item_payload.find(namespace + 'updated') + updated_text = None if updated == None else updated.text + author = item_payload.find(namespace + 'author') if author and author.attrib: print(author.attrib) - author = 'None' if author == None else author.text - # create entry - feed.add_item( - description = content, - # enclosure = feedgenerator.Enclosure(enclosure, enclosure_size, enclosure_type) if args.entry_enclosure else None, - link = link, - pubdate = published or updated, - title = title, - unique_id = link) - xml_atom = feed.writeString('utf-8') - xml_atom_extended = append_element( - xml_atom, - 'generator', - 'XMPP Journal Publisher (XJP)') - return xml_atom_extended + author_text = 'None' if author == None else author.text + identifier = item_payload.find(namespace + 'id') + if identifier and identifier.attrib: print(identifier.attrib) + identifier_text = 'None' if identifier == None else identifier.text + entry = ET.SubElement(feed, 'entry') + ET.SubElement(entry, 'title').text = title_text + ET.SubElement(entry, 'link', {'href': link_href}) + ET.SubElement(entry, 'id').text = identifier_text + 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, node): +def generate_json(iq): """Create a JSON file from node items.""" json_data = [] + pubsub = iq['from'].bare + node = iq['pubsub']['items']['node'] entries = iq['pubsub']['items'] for entry in entries: - item = entry['payload'] + item_id = entry['id'] + item_payload = entry['payload'] namespace = '{http://www.w3.org/2005/Atom}' - title = item.find(namespace + 'title') - title = None if title == None else title.text + title = item_payload.find(namespace + 'title') + title_text = None if title == None else title.text # updated = item.find(namespace + 'updated') # updated = None if updated == None else updated.text # if updated: updated = datetime.datetime.fromisoformat(updated) - link = item.find(namespace + 'link') - link = '' if link == None else link.attrib['href'] - json_data_entry = {'title' : title, - 'link' : link} + link_href = form_an_item_link(pubsub, node, item_id) + # link = item.find(namespace + 'link') + # link_href = '' if link == None else link.attrib['href'] + json_data_entry = {'title' : title_text, + 'link' : link_href} json_data.append(json_data_entry) if len(json_data) > 6: break filename = 'data/{}.json'.format(node) @@ -286,15 +315,40 @@ def append_element(xml_data, element, text): """Patch function to append XSLT reference to XML""" """Why is not this a built-in function of ElementTree or LXML""" -def append_stylesheet(xml_data): +def append_stylesheet(xml_data, filename, namespace=None): # Register namespace in order to avoide ns0: - ET.register_namespace("", "http://www.w3.org/2005/Atom") + if namespace: ET.register_namespace("", namespace) # Load XML from string tree = ET.fromstring(xml_data) # The following direction removes the XML declaration - xml_data_no_declaration = ET.tostring(tree, encoding='unicode') + xml_data_without_a_declaration = ET.tostring(tree, encoding='unicode') # Add XML declaration and stylesheet - xml_data_declaration = ('' - '' + - xml_data_no_declaration) + xml_data_declaration = ( + '' + ''.format(filename) + + xml_data_without_a_declaration) return xml_data_declaration + +def generate_opml(iq): + pubsub = iq['from'].bare + items = iq['disco_items']['items'] + opml = ET.Element("opml") + opml.set("version", "1.0") + head = ET.SubElement(opml, "head") + ET.SubElement(head, "title").text = pubsub + ET.SubElement(head, "description").text = ( + "PubSub Nodes of {}").format(pubsub) + ET.SubElement(head, "generator").text = "XMPP Journal Publisher (XJP)" + ET.SubElement(head, "urlPublic").text = ( + "https://git.xmpp-it.net/sch/XMPPJournalPublisher") + time_stamp = datetime.datetime.now(datetime.UTC).isoformat() + ET.SubElement(head, "dateCreated").text = time_stamp + ET.SubElement(head, "dateModified").text = time_stamp + body = ET.SubElement(opml, "body") + for item in items: + pubsub, node, title = item + uri = form_a_node_link(pubsub, node) + outline = ET.SubElement(body, "outline") + outline.set("text", title or node) + outline.set("xmlUrl", uri) + return ET.tostring(opml, encoding='unicode') diff --git a/script/postprocess.js b/script/postprocess.js index 342b44c..c04ca0d 100644 --- a/script/postprocess.js +++ b/script/postprocess.js @@ -1,84 +1,99 @@ window.onload = async function(){ - // Fix button follow - let follow = document.querySelector('#follow'); - //let feedUrl = location.href.replace(/^https?:/, 'feed:'); let locationHref = new URL(location.href); let node = locationHref.searchParams.get('node') let pubsub = locationHref.searchParams.get('pubsub') - let feedUrl = `feed://${location.host}/atom?pubsub=${pubsub}&node=${node}`; - follow.href = feedUrl; - follow.addEventListener ('click', function() { - window.open(feedUrl, "_self"); - }); - // Fix button subtome - document.querySelector('#subtome').href='https://www.subtome.com/#/subscribe?feeds=' + feedUrl; + // Fix button follow + let follow = document.querySelector('#follow'); + if (follow) { + //let feedUrl = location.href.replace(/^https?:/, 'feed:'); + let feedUrl = `feed://${location.host}/atom?pubsub=${pubsub}&node=${node}`; + follow.href = feedUrl; + follow.addEventListener ('click', function() { + window.open(feedUrl, "_self"); + }); + // Fix button subtome + document.querySelector('#subtome').href='https://www.subtome.com/#/subscribe?feeds=' + feedUrl; + } // Convert ISO8601 To UTC - for (let element of document.querySelectorAll('#articles > ul > li > div > h4, #feed > #header > h2#subtitle.date')) { + for (let element of document.querySelectorAll( + '#articles > ul > li > div > h4.published,' + + '#articles > ul > li > div > h4.updated, ' + + '#feed > #header > h2#subtitle.date')) { let timeStamp = new Date(element.textContent); element.textContent = timeStamp.toUTCString(); } // Parse Markdown - for (let element of document.querySelectorAll('#articles > ul > li > div > p')) { + for (let element of document.querySelectorAll('#articles > ul > li > div > p[type="text"]')) { let markDown = element.textContent element.innerHTML = marked.parse(markDown); } // Build a journal list - itemsList = await openJson(node) - if (itemsList && locationHref.searchParams.get('item')) { - node = locationHref.searchParams.get('node') - pubsub = locationHref.searchParams.get('pubsub') - let elementDiv = document.createElement('div'); - elementDiv.id = 'journal'; - let elementH3 = document.createElement('h3'); - elementH3.textContent = 'Journal'; - elementDiv.appendChild(elementH3); - let elementH4 = document.createElement('h4'); - elementH4.textContent = node; - elementDiv.appendChild(elementH4); - let elementUl = document.createElement('ul'); - elementDiv.appendChild(elementUl); - for (let item of itemsList) { - let elementLi = document.createElement('li'); - let elementA = document.createElement('a'); - elementA.textContent = item.title; - elementA.href = item.link; - elementLi.appendChild(elementA); - elementUl.appendChild(elementLi); + if (node) { + itemsList = await openJson(node) + if (itemsList && locationHref.searchParams.get('item')) { + node = locationHref.searchParams.get('node') + pubsub = locationHref.searchParams.get('pubsub') + let elementDiv = document.createElement('div'); + elementDiv.id = 'journal'; + let elementH3 = document.createElement('h3'); + elementH3.textContent = 'Journal'; + elementDiv.appendChild(elementH3); + let elementH4 = document.createElement('h4'); + elementH4.textContent = node; + elementDiv.appendChild(elementH4); + let elementUl = document.createElement('ol'); + elementDiv.appendChild(elementUl); + for (let item of itemsList) { + let elementLi = document.createElement('li'); + let elementA = document.createElement('a'); + elementA.textContent = item.title; + elementA.href = item.link; + elementLi.appendChild(elementA); + elementUl.appendChild(elementLi); + } + let elementB = document.createElement('b'); + elementB.textContent = 'Actions'; + elementDiv.appendChild(elementB); + let elementUl2 = document.createElement('ul'); + elementDiv.appendChild(elementUl2); + links = [ + {'text' : 'Subscribe from an XMPP client.', + 'href' : `xmpp:${pubsub}?pubsub;action=subscribe;node=${node}`}, + {'text' : 'Subscribe with a News Reader.', + 'href' : `feed://${location.host}/atom?pubsub=${pubsub}&node=${node}`}, + {'text' : 'Browse the journal.', + 'href' : `atom?pubsub=${pubsub}&node=${node}`}, + {'text' : 'Browse the portal.', + 'href' : `atom?pubsub=${pubsub}`} + ] + for (let link of links) { + let elementLi = document.createElement('li'); + let elementA = document.createElement('a'); + elementA.textContent = link.text; + elementA.href = link.href; + elementLi.appendChild(elementA); + elementUl2.appendChild(elementLi); + } + elementDiv.appendChild(elementUl2); + // document.querySelector('#feed').appendChild(elementDiv); // This would result in a combination of Title, Article, and Journal + document.querySelector('#articles').appendChild(elementDiv); } - let elementB = document.createElement('b'); - elementB.textContent = 'Actions'; - elementDiv.appendChild(elementB); - let elementUl2 = document.createElement('ul'); - elementDiv.appendChild(elementUl2); - links = [ - {'text' : 'Subscribe from an XMPP client.', - 'href' : `xmpp:${pubsub}?pubsub;action=subscribe;node=${node}`}, - {'text' : 'Subscribe with a News Reader.', - 'href' : `feed://${location.host}/atom?pubsub=${pubsub}&node=${node}`}, - {'text' : 'Browse the journal.', - 'href' : `atom?pubsub=${pubsub}&node=${node}`} - ] - for (let link of links) { - let elementLi = document.createElement('li'); - let elementA = document.createElement('a'); - elementA.textContent = link.text; - elementA.href = link.href; - elementLi.appendChild(elementA); - elementUl2.appendChild(elementLi); - } - elementDiv.appendChild(elementUl2); - // document.querySelector('#feed').appendChild(elementDiv); // This would result in a combination of Title, Article, and Journal - document.querySelector('#articles').appendChild(elementDiv); } // Convert URI xmpp: to URI http: links. - for (let xmppLink of document.querySelectorAll('a[href^="xmpp:"]')) { + for (let xmppLink of document.querySelectorAll('#articles > ul a[href^="xmpp:"], ol a[href^="xmpp:"]')) { xmppUri = new URL(xmppLink); let parameters = xmppUri.search.split(';'); try { - let node = parameters.find(parameter => parameter.startsWith('node=')).split('=')[1]; - let item = parameters.find(parameter => parameter.startsWith('item=')).split('=')[1]; - let pubsub = xmppUri.pathname; - xmppLink.href = `atom?pubsub=${pubsub}&node=${node}&item=${item}` + try { + let node = parameters.find(parameter => parameter.startsWith('node=')).split('=')[1]; + let item = parameters.find(parameter => parameter.startsWith('item=')).split('=')[1]; + let pubsub = xmppUri.pathname; + xmppLink.href = `atom?pubsub=${pubsub}&node=${node}&item=${item}` + } catch { + let node = parameters.find(parameter => parameter.startsWith('node=')).split('=')[1]; + let pubsub = xmppUri.pathname; + xmppLink.href = `atom?pubsub=${pubsub}&node=${node}` + } } catch (err) { console.warn(err) } diff --git a/xsl/stylesheet.xsl b/xsl/atom.xsl similarity index 86% rename from xsl/stylesheet.xsl rename to xsl/atom.xsl index 6b8c5b6..72c1dd2 100644 --- a/xsl/stylesheet.xsl +++ b/xsl/atom.xsl @@ -8,22 +8,15 @@ element inside of html element --> - - - + - - - - diff --git a/xsl/atom_as_xhtml.xsl b/xsl/atom_as_xhtml.xsl index 725c3b7..6d8ba89 100644 --- a/xsl/atom_as_xhtml.xsl +++ b/xsl/atom_as_xhtml.xsl @@ -1,7 +1,7 @@ -

+

@@ -290,6 +293,12 @@ xmlns:atom='http://www.w3.org/2005/Atom'> + + + + + + @@ -299,6 +308,12 @@ xmlns:atom='http://www.w3.org/2005/Atom'> + + + + + + @@ -313,7 +328,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'> -

+
diff --git a/xsl/opml.xsl b/xsl/opml.xsl new file mode 100644 index 0000000..9c57a4f --- /dev/null +++ b/xsl/opml.xsl @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/xsl/opml_as_xhtml.xsl b/xsl/opml_as_xhtml.xsl new file mode 100644 index 0000000..6304ef6 --- /dev/null +++ b/xsl/opml_as_xhtml.xsl @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:choose> + <xsl:when test='title and not(title="")'> + <xsl:value-of select='title'/> + </xsl:when> + <xsl:otherwise>StreamBurner</xsl:otherwise> + </xsl:choose> + + + + + + + + +