sjehuda Author

Hello,

I've made a Userscript inspired by a Userscript by @raingart.
I need help with MutationObserver.
This is the Userscript

Please don't write the name of the website, the brand name starts with A and ends with N.

Kindly,
Schimon


This is my attempt to apply your solution on another website:

//regex = '/^\s*\n/gm'
// .replace(regex, '');

function sumUp() {
//sumUp = (function sumUp(){
//sumUp = (function(){
// Uncaught TypeError: sumUp is not a function

  let
    tag, fee, sum;

  const
    // /questions/1183903/regex-using-javascript-to-return-just-numbers
    regex = /[-]{0,1}[\d]*[.]{0,1}[\d]+/g,
    prices = [],
    selectors = [
      '.a-price-whole',
      '.a-price-fraction',
      '.a-size-base.a-color-secondary',
      ],
    priceConfig = {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2
      };

  for (let i = 0; i < selectors.length; i++) {
    try {
      prices[i] = document
        .querySelector(selectors[i])
        .textContent
        .trim();
    } catch {
      console.log(`No ${selectors[i]}`);
    }
  }

  tag = prices[0] + prices[1];
  tag = tag.match(regex).join('');
  tag = parseFloat(tag);
  fee = parseFloat(prices[2].match(regex).join(''));

  sum = tag + fee
  // Method .toFixed(2) might be preferable. See raingart.
  sum = sum.toLocaleString(navigator.language, priceConfig);

  priceSum = document.createElement('span');
  priceSum.style.fontWeight = 'bold';
  priceSum.style.padding = '6px';
  priceSum.style.margin = '20px';
  priceSum.style.outline = 'auto';
  priceSum.innerHTML = `โˆ‘${sum}`;
  document.querySelector('.priceToPay > span:nth-child(2)').append(priceSum);

  //for (const val of document.querySelectorAll('.a-price-whole')) {
  //  val.innerHTML = `${sum}<b>โˆ‘</b><sup><sup>(<sup>$</sup>${tag} + <sup>$</sup>${fee})</sup></sup>`;
  //}

//})();
}

sumUp()

/*
// define the target node
var targetNode = document.querySelector('.a-price-whole');
// configuration of the observer
const config = { childList: false, characterData: true, subtree: true, attributes: false, };

// callback function
const callback = function (mutationsList, observer) {
  console.log('Changes Detected');
  if (!targetNode.outerText.includes(' + ')) {
    sumUp();
  }
};
// Create observer instance
const observer = new MutationObserver(callback);

// pass in the target node and configuration observer.observe(targetNode, config);
observer.observe(targetNode, config);
*/

const observerConfig = { childList: false, characterData: true, subtree: true, attributes: false, };
new window.MutationObserver(sumUp).observe(document.querySelector('.a-price-whole'), observerConfig);


Please document your script.

I want to learn MutationObserver, yet all of the documentations I've read thus far are either not clear or over complicated.

Your script seems to be a good example for people who are new to MutationObserver.






This script works and uses localStorage.

Is it wise to use localStorage over GM.getValue/GM.setValue?

I guess a given website can read the localStorage value set by a userscript.

Can websites read values of GM.getValue?






Hello,

I've decided to rebrand FREEdirector to Proxy Redirect.

Is there an automated manner to do so?

Currently, I've changed the older program to direct users to it's project page, in the hope they will see the message and install the new one, but it doesn't seem to work as the installation amount of the older programs keeps growing.

Please advise,
Schimon



This is clearly an attempt to sabotage web feeds, as this article suggests.

To prove my claim, copy and paste one of these scripts to Console and execute.

https://openuserjs.org/scripts/sjehuda/Newspaper
https://openuserjs.org/scripts/sjehuda/Newspaper_(XMLHttpRequest)

Falkon, Otter, Qutebrowser etc. WILL render the XML file into an HTML.

Firefox, however, will produce the following error:

// ==UserScript== 
// @name        Newspaper (XMLHttpRequest)
// @namespace   io.github.sjehuda.syndication4human
// @description Native Feed Viewer. Render syndication web feeds (supports Atom, RDF and RSS)
// @homepageURL https://sjehuda.github.io/newspaper.htmlโ€ฆ
undefined
Uncaught 
Exception { name: "", message: "", result: 2153775105, filename: "debugger eval code", lineNumber: 210, columnNumber: 0, data: null, stack: "renderFeed@debugger eval code:210:4\ncheckMediaType@debugger eval code:157:13\nhttpGetAsync/xmlHTTPRequest.onreadystatechange@debugger eval code:97:15\nEventHandlerNonNull*httpGetAsync@debugger eval code:77:3\n@debugger eval code:57:13\n" }
debugger eval code:210
    renderFeed debugger eval code:210
    checkMediaType debugger eval code:157
    onreadystatechange debugger eval code:97
    (Async: EventHandlerNonNull)
    httpGetAsync debugger eval code:77
    <anonymous> debugger eval code:57
    getEvalResult resource://devtools/server/actors/webconsole/eval-with-debugger.js:251
    evalWithDebugger resource://devtools/server/actors/webconsole/eval-with-debugger.js:172
    evaluateJS resource://devtools/server/actors/webconsole.js:974
    evaluateJSAsync resource://devtools/server/actors/webconsole.js:865
    makeInfallible resource://devtools/shared/ThreadSafeDevToolsUtils.js:103

A specific mistake of such is very likely intentional, not accidental.

Of note: When I began with XSLT and Javascript (i.e. XSLTProcessor) the MDM documentations were the worst of all others I've found, as if it is intentional by MDM to make people reluctant to XSLT and eventually its great usefulness.

Mozilla officers are welcome to provide an explanation to the above.

Kindly,
Schimon


I need help making image loading better.

Concerning to userscript Newspaper.

Since document is processed while is "on load" (aka "on the fly"), I want to replace all attributes of src to src-data while program processes the document.

I've attempted to do so by adding to function renderFeed the following code which doesn't work for all images, or is it? (I might need to check again)

  for (const image of newDocument.querySelectorAll('img')) {
    //source = image.src;
    //image.removeAttribute('src');
    //image.setAttribute('src-data', source);
    image.setAttribute('src-data', image.src);
    image.removeAttribute('src');
  }

Yet, below the execution of code document.replaceChild(insertDocument,removeDocument); I've added this code:

  for (const image of document.querySelectorAll('img')) {
    image.addEventListener('mouseover', loadImage(image))
    image.onmouseover = () => {
      image.removeEventListener('mouseover',loadImage(image))
    }
  }

Which causes the infinite loop if the line of function loadImage is not commented out.

function loadImage(image) {
  console.log('onmouseover')
  source = image.getAttribute('src-data');
  image.removeAttribute('src-data');
  image.src = source;
  //image.removeEventListener('mouseover',loadImage(image)) // This line causes infinite loop.
}

Note that I use mouseover event so it would be easier to test, though I want the event to trigger when an image element is inside or close to viewport.

P.S.
"Provident Image Load" (PIL) is a better name, eh?
Much better than the stupid phrase "Lazy (so called) Load".




Reference: https://otter-browser.org/feed/

Failed to load resource: net::ERR_INCOMPLETE_CHUNKED_ENCODING
GET https://otter-browser.org/feed/ net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)
(anonymous)	@	VM43 Newspaper:169
(anonymous)	@	VM43 Newspaper:156
(anonymous)	@	VM43 Newspaper:429

Of course not, the program never gets to

if (document.protocol == 'file:') {
  alert(document.protocol)
  mimeType = document.contentType;
} else {
  mimeType =
    request
    .getResponseHeader('Content-Type');
}

For some reason, this implementation doesn't works with file://


var
  xmlHTTPRequest, xmlFile,
  mimeType, isFeed;

const mimeArray = [
  'application/atom+xml',
  'application/stream+json',
  'application/rss+xml',
  'application/rdf+xml'
];
/*
httpGetAsync(
  document.documentURI,
  checkMediaType
);

xmlFile = httpGetAsync(document.documentURI, checkMediaType)

if (xmlFile) {
  renderFeed(
    xmlFile
  );
}

function httpGetAsync(uri, callback) {
  var xmlHTTPRequest = new XMLHttpRequest();
  xmlHTTPRequest.onreadystatechange = function() { 
    if (xmlHTTPRequest.readyState === 4) {
      xmlFile = xmlHTTPRequest.responseText;
      //console.log('xmlHTTPRequest.responseText')
      //console.log(xmlHTTPRequest.responseText)
      if (document.URL.startsWith('file:')) {
        mimeType = document.contentType;
      } else {
          mimeType =
            xmlHTTPRequest
            .getResponseHeader('Content-Type');
        }
      // FIXME
      // Not a good practice
      // Passing a file via a function
      // that returns true or false.
      // NOTE
      // Strangely enough, xmlFile
      // passes via the function even
      // without an explicit mention.
      callback(mimeType);
    };
  }
  xmlHTTPRequest.open("GET", uri, true); // true for asynchronous 
  xmlHTTPRequest.send(null);
}

fetch(document.documentURI)
  .then(checkStatus)
  .then(checkMediaType)

fetch(document.documentURI)
  .then((response) => {
     const contentType = response.headers.get('content-type');
     if (checkMediaType(contentType)) {
       return response.text();
     }
  })
  .then((data) => {
      renderFeed(data)
  })

fetch(document.documentURI)
  .then((response) => {
     const contentType = response.headers.get('content-type');
     if (!checkMediaType(contentType)) {
       throw new TypeError("Page does not seem to be a feed!");
     }
     return response.arrayBuffer();
  })
  .then((data) => {
    let decoder = new TextDecoder(document.characterSet);
    let text = decoder.decode(data);
    renderFeed(text)
  })
*/

let myPromise = new Promise(function(myResolve, myReject) {
  let request = new XMLHttpRequest();
  //request.onprogress = function(){pageLoader()};
  request.open('GET', document.documentURI);
  request.onload = function() {
    if (request.status == 200) {
      myResolve(request);
    } else {
      myReject("File not Found");
    }
  };
  request.send();
});

myPromise.then(
  function(request) {
      if (document.URL.startsWith('file:')) {
        mimeType = document.contentType;
      } else {
          mimeType =
            request
            .getResponseHeader('Content-Type');
        }
      if (checkMediaType(mimeType)) {
        request.onprogress = pageLoader(); // in case we have a larger xml file
        //setTimeout(function(){renderFeed(request.response)}, 1500); // timeout for testing
        renderFeed(request.response)
      }
  },
  function(error) {checkMediaType(error);}
);

function pageLoader() {
  // https://ao.foss.wtf/questions/6464592/how-to-align-entire-html-body-to-the-center
  const loadPage = '<html><head><link type="image/svg+xml" rel="shortcut icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>๐Ÿ“ฐ</text></svg>"><title>Newspaper</title><style>html,body{height:100%;}html{display:table;margin:auto;}body{display:table-cell;vertical-align:middle;}body{background-color:#f1f1f1;font-family:"Helvetica Neue", Helvetica,Arial,sans-serif;cursor:default;user-select:none;max-height:100%;max-width:100%;}div{font-size:2.3em;font-weight:bold;}#icon-tc{font-size:2em;position:relative;text-align:center;}#loader{animation:flickerAnimation 1s infinite;}.centerm{display:block;margin-left:auto;margin-right:auto;width:100%;}.center{padding:1em 0px 1em 0px;text-align:center;}@keyframes flickerAnimation{0%{opacity:1;}50%{opacity:0;}100%{opacity:1;}}.flip{display:inline-block;transform:scaleX(-1);-moz-transform:scaleX(-1);-o-transform:scaleX(-1);-webkit-transform:scaleX(-1);filter:FlipH;-ms-filter:FlipH;}</style></head><body><div id="icon-tc" class="centerm"><?xml version="1.0"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="128px" height="128px" id="RSSicon" viewBox="0 0 256 256"><defs><linearGradient x1="0.085" y1="0.085" x2="0.915" y2="0.915" id="RSSg"><stop  offset="0.0" stop-color="#E3702D"/><stop  offset="0.1071" stop-color="#EA7D31"/><stop  offset="0.3503" stop-color="#F69537"/><stop  offset="0.5" stop-color="#FB9E3A"/><stop  offset="0.7016" stop-color="#EA7C31"/><stop  offset="0.8866" stop-color="#DE642B"/><stop  offset="1.0" stop-color="#D95B29"/></linearGradient></defs><rect width="256" height="256" rx="55" ry="55" x="0"  y="0"  fill="#CC5D15"/><rect width="246" height="246" rx="50" ry="50" x="5"  y="5"  fill="#F49C52"/><rect width="236" height="236" rx="47" ry="47" x="10" y="10" fill="url(#RSSg)"/><circle cx="68" cy="189" r="24" fill="#FFF"/><path d="M160 213h-34a82 82 0 0 0 -82 -82v-34a116 116 0 0 1 116 116z" fill="#FFF"/><path d="M184 213A140 140 0 0 0 44 73 V 38a175 175 0 0 1 175 175z" fill="#FFF"/></svg></div><div id="message" class="center"></div><div id="loader" class="center">Loading</div></body></html>'
  const domParser = new DOMParser();
  const newDocument = domParser.parseFromString(loadPage, 'text/html');
  insertDocument = document.importNode(newDocument.documentElement, true);
  removeDocument = document.documentElement;
  document.replaceChild(insertDocument, removeDocument);
}

// Check if is of type syndication feed
function checkMediaType(mimeType) {
  //console.log(mimeType);
  
  // TODO Reorder if statements below
  if (!mimeType) {
    mimeType = 'text/plain';
  }

  for (let i = 0; i < mimeArray.length; i++) {
    if (mimeType.includes(mimeArray[i])
       ) {
      return true;
    }
    // Check if is application/xml or text/xml
    else
    if (mimeType.includes('/xml') || mimeType.includes('/html')) {
      // We do not use forEach, because we need to break out once at least on tag is found
      // List array by most commonly used formats and tags
      const tagArray = ['feed', 'atom:link', 'rss', 'rdf:RDF'];
      for (let i = 0; i < tagArray.length; i++) {
        var query = document.getElementsByTagName(tagArray[i]);
        if (query.length) {
          return true;
        }
      }
    }
    // Check if is plain text (XPath only is usable)
    else
    if (mimeType.match('text/plain')) {
      const tagArray = ['<feed', '<atom:link', '<rss', '<rdf:RDF'];
      for (let i = 0; i < tagArray.length; i++) {
        query = ['//*[contains(text(), "' + tagArray[i] + '")]'];
        query = queryByXPath(query);
        if (query.length) {
          return true;
        }
      }
    }
  }
}

// Begin processing
function renderFeed(xmlFile) {

  var
    domParser,
    xmlDocument, xsltProcessor,
    newDocument, head, style, isRTL,
    stylesheet_ltr, stylesheet_rtl,
    insertDocument, removeDocument;
    

  // FIXME
  // Make this function to work
  // function domParser(xmlDoc, xmlType) {
  //   domParser = new DOMParser();
  //   domParser.parseFromString(xmlDoc, xmlType);
  // }

  xmlFile =
    xmlFile
    .trim();

  domParser = new DOMParser();

  xmlDocument =
    domParser
    .parseFromString(
      xmlFile,
      'text/xml'
    );

  // NOTE
  // Consider migration to SaxonJS XSLT 3.0 Processor
  xsltProcessor = new XSLTProcessor();

  xslFile = '<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet xmlns="http://purl.org/rss/1.0/" xmlns:admin="http://webns.net/mvcb/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:atom10="http://www.w3.org/2005/Atom" xmlns:c="http://s.opencalais.com/1/pred/" xmlns:cc="http://web.resource.org/cc/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dct="http://purl.org/dc/terms/" xmlns:dbo="http://dbpedia.org/ontology/" xmlns:dbp="http://dbpedia.org/property/" xmlns:enc="http://purl.oclc.org/net/rss_2.0/enc#" xmlns:fh="http://purl.org/syndication/history/1.0" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:foo="http://purl.org/rss/1.0/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:georss="http://www.georss.org/georss" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns:prov="http://www.w3.org/ns/prov#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:sioc="http://rdfs.org/sioc/ns#" xmlns:sioct="http://rdfs.org/sioc/types#" xmlns:skos="http://www.w3.org/2004/02/skos/core#" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:output method="html" indent="yes" omit-xml-decleration="no"/><xsl:output media-type="application/atom+xml"/><xsl:template match="/atom:feed"><xsl:variable name="rtl" select="@xml:lang[ contains(self::node(),&quot;ar&quot;) or contains(self::node(),&quot;fa&quot;) or contains(self::node(),&quot;he&quot;) or contains(self::node(),&quot;ji&quot;) or contains(self::node(),&quot;ku&quot;) or contains(self::node(),&quot;ur&quot;) or contains(self::node(),&quot;yi&quot;)]"/><html><head><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;description&quot;"/><xsl:with-param name="content" select="atom:subtitle"/></xsl:call-template><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;generator&quot;"/><xsl:with-param name="content" select="&quot;syndication4humans https://sjehuda.github.io/&quot;"/></xsl:call-template><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;mimetype&quot;"/><xsl:with-param name="content" select="&quot;application/atom+xml&quot;"/></xsl:call-template><title><xsl:choose><xsl:when test="atom:title and not(atom:title=&quot;&quot;)"><xsl:value-of select="atom:title"/></xsl:when><xsl:otherwise>Streamburner News Reader</xsl:otherwise></xsl:choose></title><xsl:if test="$rtl"><meta name="semitic" content="true"/></xsl:if></head><body><div id="feed"><header><div id="title"><xsl:choose><xsl:when test="atom:title and not(atom:title=&quot;&quot;)"><xsl:attribute name="title"><xsl:value-of select="atom:title"/></xsl:attribute><xsl:value-of select="atom:title"/></xsl:when><xsl:otherwise><div class="empty"/></xsl:otherwise></xsl:choose></div><div id="subtitle"><xsl:attribute name="title"><xsl:value-of select="atom:subtitle"/></xsl:attribute><xsl:value-of select="atom:subtitle"/></div></header><section id="links"><a title="Click to get the latest updates and news" onclick="location.href = &quot;feed:&quot; + location.href"></a><a title="Subscribe via SubToMe"><xsl:attribute name="href">https://www.subtome.com/#/subscribe?feeds=<xsl:value-of select="atom:link[@rel=&quot;self&quot;]/@href"/></xsl:attribute><xsl:attribute name="onclick">(function(btn){var z=document.createElement(&quot;script&quot;);document.subtomeBtn=btn;z.src=&quot;https://www.subtome.com/load.js&quot;;document.body.appendChild(z);})(this);return false;</xsl:attribute></a><a title="Learn about syndication feed" onclick="document.getElementById(&quot;aboutfeed&quot;).classList.toggle(&quot;show&quot;);" class="popup"><span class="popuptext" id="aboutfeed"/></a><a href="https://wikiless.org/wiki/Template:Aggregators" title="Get a feed reader for desktop and mobile"/><a href="https://wikiless.org/wiki/RSS" title="Learn the benefits of using feeds for personal and corporates"/></section><xsl:choose><xsl:when test="atom:entry"><div id="toc"><xsl:for-each select="atom:entry[not(position() &gt;20)]"><xsl:if test="atom:title"><xsl:element name="a"><xsl:attribute name="href"><xsl:text>#newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="atom:title"/></xsl:element></xsl:if></xsl:for-each></div></xsl:when></xsl:choose><section id="articles"><xsl:choose><xsl:when test="atom:entry"><xsl:for-each select="atom:entry[not(position() &gt;20)]"><div class="entry"><xsl:if test="atom:title"><div class="title"><xsl:element name="a"><xsl:attribute name="href"><xsl:choose><xsl:when test="atom:link[contains(@rel,&quot;alternate&quot;)]"><xsl:value-of select="atom:link[contains(@rel,&quot;alternate&quot;)]/@href"/></xsl:when><xsl:otherwise><xsl:value-of select="atom:link/@href"/></xsl:otherwise></xsl:choose></xsl:attribute><xsl:attribute name="title"><xsl:value-of select="atom:title"/></xsl:attribute><xsl:attribute name="id"><xsl:text>newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="atom:title"/></xsl:element></div></xsl:if><xsl:choose><xsl:when test="geo:lat and geo:long"><xsl:variable name="lat" select="geo:lat"/><xsl:variable name="lng" select="geo:long"/><span class="geolocation"><a href="geo:{$lat},{$lng}">๐Ÿ“</a></span></xsl:when><xsl:when test="geo:Point"><xsl:variable name="lat" select="geo:Point/geo:lat"/><xsl:variable name="lng" select="geo:Point/geo:long"/><span class="geolocation"><a href="geo:{$lat},{$lng}">๐Ÿ“</a></span></xsl:when><xsl:when test="georss:point"><xsl:variable name="lat" select="substring-before(georss:point, &quot; &quot;)"/><xsl:variable name="lng" select="substring-after(georss:point, &quot; &quot;)"/><xsl:variable name="name" select="georss:featurename"/><span class="geolocation"><a href="geo:{$lat},{$lng}" title="{$name}">๐Ÿ“</a></span></xsl:when></xsl:choose><xsl:choose><xsl:when test="atom:updated"><div class="updated"><xsl:value-of select="atom:updated"/></div></xsl:when><xsl:when test="atom:published"><div class="published"><xsl:value-of select="atom:published"/></div></xsl:when><xsl:otherwise><div class="warning atom1 published"/></xsl:otherwise></xsl:choose><xsl:if test="atom:content or atom:summary"><div class="content"><xsl:choose><xsl:when test="atom:summary[contains(@type,&quot;text&quot;)]"><xsl:attribute name="type"><xsl:value-of select="atom:summary/@type"/></xsl:attribute><xsl:value-of select="atom:summary"/></xsl:when><xsl:when test="atom:summary[contains(@type,&quot;base64&quot;)]"></xsl:when><xsl:when test="atom:content[contains(@type,&quot;text&quot;)]"><xsl:attribute name="type"><xsl:value-of select="atom:content/@type"/></xsl:attribute><xsl:value-of select="atom:content"/></xsl:when><xsl:when test="atom:content[contains(@type,&quot;base64&quot;)]"></xsl:when><xsl:otherwise><xsl:choose><xsl:when test="atom:summary and not(atom:summary=&quot;&quot;)"><xsl:value-of select="atom:summary" disable-output-escaping="yes"/></xsl:when><xsl:otherwise><xsl:value-of select="atom:content" disable-output-escaping="yes"/></xsl:otherwise></xsl:choose></xsl:otherwise></xsl:choose></div></xsl:if><xsl:if test="atom:link[contains(@rel,&quot;enclosure&quot;)]"><div class="enclosure" title="Right-click and Save link asโ€ฆ"><xsl:for-each select="atom:link[contains(@rel,&quot;enclosure&quot;)]"><xsl:element name="span"><xsl:attribute name="icon"><xsl:value-of select="substring-before(@type,&quot;/&quot;)"/></xsl:attribute></xsl:element><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="@href"/></xsl:attribute><xsl:attribute name="download"/><xsl:call-template name="extract-filename"><xsl:with-param name="url" select="@href"/></xsl:call-template></xsl:element><xsl:element name="span"><xsl:attribute name="class"><xsl:value-of select="substring-before(@type,&quot;/&quot;)"/></xsl:attribute></xsl:element><xsl:if test="@length &gt; 0"><xsl:call-template name="transform-filesize"><xsl:with-param name="length" select="@length"/></xsl:call-template></xsl:if><xsl:element name="br"/></xsl:for-each><xsl:for-each select="media:content"><xsl:element name="span"><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 &gt; 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></div></xsl:if></div><xsl:if test="not(atom:id)"><div class="warning atom1 id"/></xsl:if></xsl:for-each></xsl:when><xsl:otherwise><div class="notice no-entry"/></xsl:otherwise></xsl:choose></section></div></body></html></xsl:template><xsl:output media-type="application/rdf+xml"/><xsl:template match="/rdf:RDF"><xsl:variable name="rtl" select="channel/language[ contains(text(),&quot;ar&quot;) or contains(text(),&quot;fa&quot;) or contains(text(),&quot;he&quot;) or contains(text(),&quot;ji&quot;) or contains(text(),&quot;ku&quot;) or contains(text(),&quot;ur&quot;) or contains(text(),&quot;yi&quot;)]"/><html><head><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;description&quot;"/><xsl:with-param name="content" select="foo:channel/foo:description"/></xsl:call-template><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;generator&quot;"/><xsl:with-param name="content" select="&quot;syndication4humans https://sjehuda.github.io/&quot;"/></xsl:call-template><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;mimetype&quot;"/><xsl:with-param name="content" select="&quot;application/rdf+xml&quot;"/></xsl:call-template><title><xsl:choose><xsl:when test="foo:channel/foo:title and not(foo:channel/foo:title=&quot;&quot;)"><xsl:value-of select="foo:channel/foo:title"/></xsl:when><xsl:otherwise>Streamburner News Reader</xsl:otherwise></xsl:choose></title><xsl:if test="$rtl"><meta name="semitic" content="true"/></xsl:if></head><body><div id="feed"><header><div id="title"><xsl:choose><xsl:when test="foo:channel/foo:title and not(foo:channel/foo:title=&quot;&quot;)"><xsl:attribute name="title"><xsl:value-of select="foo:channel/foo:title"/></xsl:attribute><xsl:value-of select="foo:channel/foo:title"/></xsl:when><xsl:otherwise><div class="empty"/></xsl:otherwise></xsl:choose></div><xsl:choose><xsl:when test="foo:channel/itunes:subtitle"><div id="subtitle"><xsl:attribute name="title"><xsl:value-of select="foo:channel/itunes:subtitle"/></xsl:attribute><xsl:value-of select="foo:channel/itunes:subtitle"/></div></xsl:when><xsl:when test="foo:channel/foo:description"><div id="subtitle"><xsl:attribute name="title"><xsl:value-of select="foo:channel/foo:description"/></xsl:attribute><xsl:value-of select="foo:channel/foo:description"/></div></xsl:when></xsl:choose></header><section id="links"><a title="Click to get the latest updates and news" onclick="location.href = &quot;feed:&quot; + location.href"></a><a title="Subscribe via SubToMe"><xsl:attribute name="href">https://www.subtome.com/#/subscribe?feeds=<xsl:value-of select="atom:link[@rel=&quot;self&quot;]/@href"/></xsl:attribute><xsl:attribute name="onclick">(function(btn){var z=document.createElement(&quot;script&quot;);document.subtomeBtn=btn;z.src=&quot;https://www.subtome.com/load.js&quot;;document.body.appendChild(z);})(this);return false;</xsl:attribute></a><a title="Learn about syndication feed" onclick="document.getElementById(&quot;aboutfeed&quot;).classList.toggle(&quot;show&quot;);" class="popup"><span class="popuptext" id="aboutfeed"/></a><a href="https://wikiless.org/wiki/Template:Aggregators" title="Get a feed reader for desktop and mobile"/><a href="https://wikiless.org/wiki/RSS" title="Learn the benefits of using feeds for personal and corporates"/></section><xsl:choose><xsl:when test="foo:item"><div id="toc"><xsl:for-each select="foo:item[not(position() &gt;20)]"><xsl:choose><xsl:when test="itunes:subtitle"><xsl:element name="a"><xsl:attribute name="href"><xsl:text>#newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="itunes:subtitle"/></xsl:element></xsl:when><xsl:when test="foo:title"><xsl:element name="a"><xsl:attribute name="href"><xsl:text>#newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="foo:title"/></xsl:element></xsl:when></xsl:choose></xsl:for-each></div></xsl:when></xsl:choose><section id="articles"><xsl:choose><xsl:when test="foo:item"><xsl:for-each select="foo:item[not(position() &gt;20)]"><div class="entry"><xsl:choose><xsl:when test="itunes:subtitle"><div class="title"><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="foo:link"/></xsl:attribute><xsl:attribute name="title"><xsl:value-of select="itunes:subtitle"/></xsl:attribute><xsl:attribute name="id"><xsl:text>newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="itunes:subtitle"/></xsl:element></div></xsl:when><xsl:when test="foo:title"><div class="title"><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="foo:link"/></xsl:attribute><xsl:attribute name="title"><xsl:value-of select="foo:title"/></xsl:attribute><xsl:attribute name="id"><xsl:text>newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="foo:title"/></xsl:element></div></xsl:when><xsl:otherwise><div class="warning rss title"/></xsl:otherwise></xsl:choose><xsl:choose><xsl:when test="geo:lat and geo:long"><xsl:variable name="lat" select="geo:lat"/><xsl:variable name="lng" select="geo:long"/><span class="geolocation"><a href="geo:{$lat},{$lng}">๐Ÿ“</a></span></xsl:when><xsl:when test="geo:Point"><xsl:variable name="lat" select="geo:Point/geo:lat"/><xsl:variable name="lng" select="geo:Point/geo:long"/><span class="geolocation"><a href="geo:{$lat},{$lng}">๐Ÿ“</a></span></xsl:when><xsl:when test="georss:point"><xsl:variable name="lat" select="substring-before(georss:point, &quot; &quot;)"/><xsl:variable name="lng" select="substring-after(georss:point, &quot; &quot;)"/><xsl:variable name="name" select="georss:featurename"/><span class="geolocation"><a href="geo:{$lat},{$lng}" title="{$name}">๐Ÿ“</a></span></xsl:when></xsl:choose><xsl:if test="dc:date"><div class="published"><xsl:value-of select="dc:date"/></div></xsl:if><xsl:choose><xsl:when test="content:encoded"><div class="content"><xsl:value-of select="content:encoded" disable-output-escaping="yes"/></div></xsl:when><xsl:when test="foo:description"><div class="content"><xsl:value-of select="foo:description" disable-output-escaping="yes"/></div></xsl:when><xsl:when test="itunes:summary"><div class="content"><xsl:value-of select="itunes:summary" disable-output-escaping="yes"/></div></xsl:when><xsl:otherwise><div class="warning rss description"/></xsl:otherwise></xsl:choose><xsl:if test="enc:enclosure"><div class="enclosure" title="Right-click and Save link asโ€ฆ"><xsl:for-each select="enc:enclosure"><xsl:element name="span"><xsl:attribute name="icon"><xsl:value-of select="substring-before(@enc:type,&quot;/&quot;)"/></xsl:attribute></xsl:element><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="@rdf:resource"/></xsl:attribute><xsl:attribute name="download"/><xsl:call-template name="extract-filename"><xsl:with-param name="url" select="@rdf:resource"/></xsl:call-template></xsl:element><xsl:element name="span"><xsl:attribute name="class"><xsl:value-of select="substring-before(@enc:type,&quot;/&quot;)"/></xsl:attribute></xsl:element><xsl:if test="@enc:length &gt; 0"><xsl:call-template name="transform-filesize"><xsl:with-param name="length" select="@enc:length"/></xsl:call-template></xsl:if><xsl:element name="br"/></xsl:for-each></div></xsl:if></div></xsl:for-each></xsl:when><xsl:otherwise><div class="notice no-entry"/></xsl:otherwise></xsl:choose></section></div></body></html></xsl:template><xsl:output media-type="application/rss+xml"/><xsl:template match="/rss"><xsl:variable name="rtl" select="channel/language[ contains(text(),&quot;ar&quot;) or contains(text(),&quot;fa&quot;) or contains(text(),&quot;he&quot;) or contains(text(),&quot;ji&quot;) or contains(text(),&quot;ku&quot;) or contains(text(),&quot;ur&quot;) or contains(text(),&quot;yi&quot;)]"/><html><head><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;description&quot;"/><xsl:with-param name="content" select="channel/description"/></xsl:call-template><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;generator&quot;"/><xsl:with-param name="content" select="&quot;syndication4humans https://sjehuda.github.io/&quot;"/></xsl:call-template><xsl:call-template name="metadata"><xsl:with-param name="name" select="&quot;mimetype&quot;"/><xsl:with-param name="content" select="&quot;application/rss+xml&quot;"/></xsl:call-template><title><xsl:choose><xsl:when test="channel/title and not(channel/title=&quot;&quot;)"><xsl:value-of select="channel/title"/></xsl:when><xsl:otherwise>Streamburner News Reader</xsl:otherwise></xsl:choose></title><xsl:if test="$rtl"><meta name="semitic" content="true"/></xsl:if></head><body><div id="feed"><header><div id="title"><xsl:choose><xsl:when test="channel/title and not(channel/title=&quot;&quot;)"><xsl:attribute name="title"><xsl:value-of select="channel/title"/></xsl:attribute><xsl:value-of select="channel/title"/></xsl:when><xsl:otherwise><div class="empty"/></xsl:otherwise></xsl:choose></div><xsl:choose><xsl:when test="channel/itunes:subtitle"><div id="subtitle"><xsl:attribute name="title"><xsl:value-of select="channel/itunes:subtitle"/></xsl:attribute><xsl:value-of select="channel/itunes:subtitle"/></div></xsl:when><xsl:when test="channel/description"><div id="subtitle"><xsl:attribute name="title"><xsl:value-of select="channel/description"/></xsl:attribute><xsl:value-of select="channel/description"/></div></xsl:when></xsl:choose></header><section id="links"><a title="Click to get the latest updates and news" onclick="location.href = &quot;feed:&quot; + location.href"></a><a title="Subscribe via SubToMe"><xsl:attribute name="href">https://www.subtome.com/#/subscribe?feeds=<xsl:value-of select="atom:link[@rel=&quot;self&quot;]/@href"/></xsl:attribute><xsl:attribute name="onclick">(function(btn){var z=document.createElement(&quot;script&quot;);document.subtomeBtn=btn;z.src=&quot;https://www.subtome.com/load.js&quot;;document.body.appendChild(z);})(this);return false;</xsl:attribute></a><a title="Learn about syndication feed" onclick="document.getElementById(&quot;aboutfeed&quot;).classList.toggle(&quot;show&quot;);" class="popup"><span class="popuptext" id="aboutfeed"/></a><a href="https://wikiless.org/wiki/Template:Aggregators" title="Get a feed reader for desktop and mobile"/><a href="https://wikiless.org/wiki/RSS" title="Learn the benefits of using feeds for personal and corporates"/></section><xsl:choose><xsl:when test="channel/item"><div id="toc"><xsl:for-each select="channel/item[not(position() &gt;20)]"><xsl:choose><xsl:when test="itunes:subtitle"><xsl:element name="a"><xsl:attribute name="href"><xsl:text>#newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="itunes:subtitle"/></xsl:element></xsl:when><xsl:when test="title"><xsl:element name="a"><xsl:attribute name="href"><xsl:text>#newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="title"/></xsl:element></xsl:when></xsl:choose></xsl:for-each></div></xsl:when></xsl:choose><section id="articles"><xsl:choose><xsl:when test="channel/item"><xsl:for-each select="channel/item[not(position() &gt;20)]"><div class="entry"><xsl:choose><xsl:when test="itunes:subtitle"><div class="title"><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="link"/></xsl:attribute><xsl:attribute name="title"><xsl:value-of select="itunes:subtitle"/></xsl:attribute><xsl:attribute name="id"><xsl:text>newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="itunes:subtitle"/></xsl:element></div></xsl:when><xsl:when test="title"><div class="title"><xsl:element name="a"><xsl:attribute name="href"><xsl:value-of select="link"/></xsl:attribute><xsl:attribute name="title"><xsl:value-of select="title"/></xsl:attribute><xsl:attribute name="id"><xsl:text>newspaper-oujs-</xsl:text><xsl:value-of select="position()"/></xsl:attribute><xsl:value-of select="title"/></xsl:element></div></xsl:when><xsl:otherwise><div class="warning rss2 title"/></xsl:otherwise></xsl:choose><xsl:choose><xsl:when test="geo:lat and geo:long"><xsl:variable name="lat" select="geo:lat"/><xsl:variable name="lng" select="geo:long"/><span class="geolocation"><a href="geo:{$lat},{$lng}">๐Ÿ“</a></span></xsl:when><xsl:when test="geo:Point"><xsl:variable name="lat" select="geo:Point/geo:lat"/><xsl:variable name="lng" select="geo:Point/geo:long"/><span class="geolocation"><a href="geo:{$lat},{$lng}">๐Ÿ“</a></span></xsl:when><xsl:when test="georss:point"><xsl:variable name="lat" select="substring-before(georss:point, &quot; &quot;)"/><xsl:variable name="lng" select="substring-after(georss:point, &quot; &quot;)"/><xsl:variable name="name" select="georss:featurename"/><span class="geolocation"><a href="geo:{$lat},{$lng}" title="{$name}">๐Ÿ“</a></span></xsl:when></xsl:choose><xsl:if test="pubDate"><div class="published"><xsl:value-of select="pubDate"/></div></xsl:if><xsl:choose><xsl:when test="content:encoded"><div class="content"><xsl:value-of select="content:encoded" disable-output-escaping="yes"/></div></xsl:when><xsl:when test="description"><div class="content"><xsl:value-of select="description" disable-output-escaping="yes"/></div></xsl:when><xsl:when test="itunes:summary"><div class="content"><xsl:value-of select="itunes:summary" disable-output-escaping="yes"/></div></xsl:when><xsl:otherwise><div class="warning rss2 description"/></xsl:otherwise></xsl:choose><xsl:if test="enclosure or media:content"><div class="enclosure" title="Right-click and Save link asโ€ฆ"><xsl:for-each select="enclosure"><xsl:element name="span"><xsl:attribute name="icon"><xsl:value-of select="substring-before(@type,&quot;/&quot;)"/></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="substring-before(@type,&quot;/&quot;)"/></xsl:attribute></xsl:element><xsl:if test="@length &gt; 0"><xsl:call-template name="transform-filesize"><xsl:with-param name="length" select="@length"/></xsl:call-template></xsl:if><xsl:element name="br"/></xsl:for-each><xsl:for-each select="media:content"><xsl:element name="span"><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 &gt; 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></div></xsl:if></div></xsl:for-each></xsl:when><xsl:otherwise><div class="notice no-entry"/></xsl:otherwise></xsl:choose></section></div></body></html></xsl:template><xsl:template name="metadata"><xsl:param name="name"/><xsl:param name="content"/><xsl:if test="$content and not($content=&quot;&quot;)"><xsl:element name="meta"><xsl:attribute name="name"><xsl:value-of select="$name"/></xsl:attribute><xsl:attribute name="content"><xsl:value-of select="$content"/></xsl:attribute></xsl:element></xsl:if></xsl:template><xsl:template name="extract-filename"><xsl:param name="url"/><xsl:choose><xsl:when test="substring($url, string-length($url) - string-length(&quot;/&quot;) + 1) = &quot;/&quot;"><xsl:value-of select="substring-after(substring($url, 1, string-length($url) - 1),&quot;://&quot;)"/></xsl:when><xsl:otherwise><xsl:choose><xsl:when test="contains($url,&quot;/&quot;) and contains(substring-after($url,&quot;/&quot;),&quot;.&quot;)"><xsl:call-template name="extract-filename"><xsl:with-param name="url" select="substring-after($url,&quot;/&quot;)"/></xsl:call-template></xsl:when><xsl:otherwise><xsl:value-of select="$url"/></xsl:otherwise></xsl:choose></xsl:otherwise></xsl:choose></xsl:template><xsl:template name="transform-filesize"><xsl:param name="length"/><xsl:choose><xsl:when test="$length &lt; 2"><xsl:value-of select="$length"/>Byte</xsl:when><xsl:when test="floor($length div 1024) &lt; 1"><xsl:value-of select="$length"/>Bytes</xsl:when><xsl:when test="floor($length div (1024 * 1024)) &lt; 1"><xsl:value-of select="floor($length div 1024)"/>.<xsl:value-of select="substring($length mod 1024,0,2)"/>KiB</xsl:when><xsl:when test="floor($length div (1024 * 1024 * 1024)) &lt; 1"><xsl:value-of select="floor($length div (1024 * 1024))"/>.<xsl:value-of select="substring($length mod (1024 * 1024),0,2)"/>MiB</xsl:when><xsl:otherwise><xsl:value-of select="floor($length div (1024 * 1024 * 1024))"/>.<xsl:value-of select="substring($length mod (1024 * 1024 * 1024),0,2)"/>GiB</xsl:otherwise></xsl:choose></xsl:template></xsl:stylesheet>';

  xsltStylesheet =
    domParser
    .parseFromString(
      xslFile, 'application/xml' // application/xslt+xml or text/xsl are Not Valid
    );

  xsltProcessor
  .importStylesheet(
    xsltStylesheet
  );

  newDocument =
    xsltProcessor
    .transformToDocument(
      xmlDocument
    );

  // FIXME
  // Blocked due to server policy
  // https://archlinux.org/feeds/packages/
  // https://www.openstreetmap.org/traces/rss
  // NOTE
  // We can use inline style (i.e. style="")
  // but that would make the code lesser manageable
  stylesheet_ltr = "html,body{padding:0;margin:0}body{background:WhiteSmoke;color:#333;hyphens:auto}header{margin:0 -1em 1em -1em;margin-bottom:1em;padding:1em 1em 0 1em}#feed{min-width:400px;overflow:auto;position:relative}*{max-width:97%;object-fit:contain;height:auto}#logo{display:inline-block;float:left;overflow:hidden;position:relative;height:60px;width:60px;margin-right:9;padding-top:12}#logo>a>img{margin:auto;max-width:100%;position:absolute;width:5em;bottom:0;right:0;left:0;top:0}#title{font-variant:small-caps;text-align:center}#title{font-weight:bold;margin-bottom:0;overflow:hidden;-webkit-line-clamp:2;white-space:nowrap;margin:0;font-size:2.2em}#title .empty:before{font-variant:small-caps;content:'Streamburner News Dashboard';text-align:center}#subtitle{overflow:hidden;-webkit-line-clamp:2;white-space:wrap;font-weight:bold;font-size:1.5em;text-align:center;font-variant:small-caps}.container{display:flex}#links{border-top:.1em solid;margin:auto;width:50%;text-align:center;direction:ltr}#links>a{padding:10px;text-decoration:none;font-size:70%}#links>a:nth-child(1):after{content:'Follow';cursor:pointer;border-color:grey;border-left-style:solid;border-radius:1px;padding:6px;background:#eee !important}#links>a:nth-child(2):after{content:'SubToMe';cursor:pointer}#links>a:nth-child(3):after{content:'Whatโ€™s This?';cursor:help}#links>a:nth-child(4):after{content:'Get a News Reader'}#links>a:nth-child(5):after{content:'More Info...'}#toc{margin-left:3%;padding:5px}#toc:before{content:'Latest Updates';font-size:76%;font-weight:bold}#toc>a{text-decoration:none;font-size:66%;display:block;padding:5px 0;margin-left:1%}#toc>a:hover{text-decoration:underline}#toc>a:visited{text-decoration:line-through}.popup{position:relative;display:inline-block;cursor:pointer}.popup .popuptext{visibility:hidden;width:160px;color:#fff;border-radius:6px;padding:18px;position:absolute;z-index:1;background-color:#555;position:absolute;right:4%;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:50%;text-align:left}.popup .popuptext:after{content:'๐Ÿ“ฐ Web Syndication News Feed \\A\\A ' ' Syndication Feed is a mean for content and media publishers ' 'to reach a wider audience easily. ' ' It allows you to receive information directly without the ' 'going from site to site. \\A\\A ' ' Essentially, a feed is a function that allows โ€œFeed Readersโ€ ' 'to access multiple websites automatically looking for new ' 'content and then posting the information about new content ' 'and updates to another website, mobile app or desktop software ' 'at the office. \\A\\A ' ' Feeds provide a way for users to keep up with the latest ' 'news, events and package and delivery status information ' 'posted on different websites such as social networks, torrent ' 'indexers or podcasts in one spot.';white-space:pre-wrap;line-height:1.8;font-size:150%}.popup .show{visibility:visible;-webkit-animation:fadeIn 1s;animation:fadeIn 1s}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}#articles{justify-content:space-between;max-width:90%;margin:0 auto;padding:10px 0}#articles>*{margin:.5em;white-space:normal;vertical-align:top;margin-bottom:50px}.entry{border-bottom:inset;margin-left:auto;margin-right:auto;overflow:auto;line-height:1.6;font-size:85%;overflow-x:hidden}.entry:hover{background:#f8f9fa}.entry *{max-width:98%}.entry>a{white-space:normal}.title{cursor:pointer;display:inline-block;font-size:110%;font-weight:bold;text-decoration:underline;overflow:visible;text-overflow:ellipsis;white-space:nowrap;font-variant:small-caps}a{color:#333;display:inline-block}.geolocation>a{text-decoration:none;padding-left:6px}.author{font-size:75%;margin:0 auto 0 auto}.author:before{content:'By '}.author:after{content:' / '}.published,.updated{font-size:75%;margin:0 auto 0 auto}.content{margin:15px auto 15px 1%;inline-size:95%;text-indent:3px}.content[type='text']{font-family:monospace}code{overflow:auto;display:block;max-height:300px;border-radius:4px}.enclosure{background:#eee;border:1px solid GrayText;border-radius:4px;clear:both;color:#525c66;cursor:help;direction:ltr;font-size:.8em;margin:5px auto 15px 1%;padding:15px;vertical-align:middle;border:1px solid #aaa;border-radius:.5em;max-width:100%;moz-border-radius:.5em;padding:1em}.enclosure>span:after{content:' (Document file) '}.enclosure>span.executable:after{content:' (Executable file) '}.enclosure>span.image:after{content:' (Image file) '}.enclosure>span.audio:after{content:' (Audio file) '}.enclosure>span.video:after{content:' (Video file) '}.enclosure>span[icon]:after{content:'๐Ÿ“„๏ธ';margin:3px}.enclosure>span[icon='executable']:after{content:'๐Ÿ“ฆ๏ธ';margin:3px}.enclosure>span[icon='image']:after{content:'๐Ÿ–ผ๏ธ';margin:3px}.enclosure>span[icon='audio']:after{content:'๐ŸŽผ๏ธ';margin:3px}.enclosure>span[icon='video']:after{content:'๐Ÿ“ฝ๏ธ';margin:3px}.notice{text-align:center;display:block;font-size:130%;font-weight:lighter;font-variant-caps:small-caps;font-style:oblique;color:FireBrick}.warning{display:block;font-size:60%;font-weight:bold;color:DarkRed}.no-entry:after{content:'This news feed is empty'}.atom1.author:after{content:'Atom 1.0 Warning: Element </author> is missing'}.atom1.id:after{content:'Atom 1.0 Warning: Element </id> is missing'}.atom1.link:after{content:'Atom 1.0 Warning: Element </link> is missing'}.atom1.published:after{content:'Atom 1.0 Warning: Element </published> is missing'}.atom1.title:after{content:'Atom 1.0 Warning: Element </title> is missing'}.rss2.description:after{content:'RSS 2.0 Warning: Element </description> is missing'}.rss2.link:after{content:'RSS 2.0 Warning: Element </link> is missing'}.rss2.title:after{content:'RSS 2.0 Warning: Element </title> is missing'}abbr,acronym{border-bottom:1px dotted #c30}dt{font-weight:bold}";
  stylesheet_rtl = "html,body{text-align:right}#feed{direction:rtl}#logo{float:right;margin-left:9}.geolocation>a{padding-right:6px}.image{float:right;margin-left:40px;margin-right:auto}"
  style = newDocument.createElement('style');
  newDocument.head.append(style);
  style.type = 'text/css';

  // NOTE
  // Because we use JS, maybe it is better to set direction by
  // the letters of the initial set of words.
  var isRTL =
    newDocument
    .querySelector(
      'meta[name="semitic"]'
    );

  if (isRTL) {
    style.innerHTML =
      stylesheet_ltr +
      stylesheet_rtl;
  } else {
    style.innerHTML =
      stylesheet_ltr;
  }

  for (const image of newDocument.querySelectorAll('img')) {
    //source = image.src;
    //image.removeAttribute('src');
    //image.setAttribute('src-data', source);
    image.setAttribute('src-data', image.src);
    image.removeAttribute('src');
  }

  //var newDoc = document.adoptNode(newDoc.documentElement, true);
  insertDocument =
    document
    .importNode(
      newDocument
      .documentElement,
      true
    );

  removeDocument =
    document
    .documentElement;

  document
  .replaceChild(
    insertDocument,
    removeDocument
  );

  /*
  document.body.addEventListener ("mouseover", function(e) {
    if (e.target && e.target.nodeName == "IMG" && !e.target.src) {
      console.log('DELEGATED')
      source = e.target.getAttribute('src-data');
      e.target.removeAttribute('src-data');
      e.target.src = source;
    }
  });
  */

  for (const image of newDocument.querySelectorAll('img')) {
    image.onmouseover = () => {
      console.log('onmouseover')
      source = image.getAttribute('src-data');
      image.removeAttribute('src-data');
      image.src = source;
    }
  }

  /*
  for (const image of document.querySelectorAll('img')) {
    image.addEventListener('focus',event => {
    //image.addEventListener('mouseover',event => {
      if (image.getAttribute('src-data')) {
        //toggleAttribute(image)
        source = image.getAttribute('src-data');
        image.removeAttribute('src-data');
        image.src = source;
      }
    }, {passive: true});
    image.onmouseover = () => {
      if (image.getAttribute('src-data')) {
        //toggleAttribute(image)
        source = image.getAttribute('src-data');
        image.removeAttribute('src-data');
        image.src = source;
      }
    };
  }
  */

}

function toggleAttribute(image) {
    source = image.getAttribute('src-data');
    image.removeAttribute('src-data');
    image.src = source;
}

function queryByXPath(queries) {
  var result;
  let i = 0;
  do {
    result = document.evaluate(
      queries[i], document,
      null, XPathResult.STRING_TYPE);
    i = i + 1;
    result = result.stringValue;
  } while (!result && i < queries.length);
  return result;
}

I've written a userscript that redirects to proxy addresses, and another userscript that changes URL; both use the same dataset.

The code seems to be done for both programs, and no technical updates are expected to occur.

However, the only frequent update that these userscripts are subjected to is database update.

How should @require be utilized to achieve dataset update or should we have a @data metablock to handle this task?


You tell us. :)

It's a difficult question. I'm not sure.

As with Tampermonkey for Android you might run the risk of it's base core, Chromium, being out of date. i.e. possible browser security vulnerabilities.

Is this so for Mull too?


Synchronize url list with a remote database using:

  • @require; or
  • @resource; or
  • DHT with BitTorrent, ed2K, IPFS etc.

๏ฟผ