mirror of
https://github.com/aureliendavid/rsspreview.git
synced 2025-08-22 19:28:39 +00:00
initial commit
This commit is contained in:
commit
cdf84b50ee
23
background.js
Normal file
23
background.js
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
function detectFeed(event) {
|
||||
|
||||
// force application/rss+xml to text/xml so the browser displays it instead of downloading
|
||||
|
||||
for (var header of event.responseHeaders) {
|
||||
if (header.name.toLowerCase() == "content-type") {
|
||||
header.value = header.value.replace(/application\/(rss|atom)\+xml/,'text/xml');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
responseHeaders: event.responseHeaders
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
browser.webRequest.onHeadersReceived.addListener(
|
||||
detectFeed,
|
||||
{ urls: ["<all_urls>"], types: ["main_frame"] },
|
||||
["blocking", "responseHeaders"]
|
||||
)
|
BIN
icons/file.png
Normal file
BIN
icons/file.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
BIN
icons/rss-48.png
Normal file
BIN
icons/rss-48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
29
manifest.json
Normal file
29
manifest.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
|
||||
"manifest_version": 2,
|
||||
"name": "RSSPreview",
|
||||
"version": "1.0",
|
||||
|
||||
"description": "Preview RSS feeds in browser",
|
||||
|
||||
"icons": {
|
||||
"48": "icons/rss-48.png"
|
||||
},
|
||||
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
|
||||
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["rsspreview.js"]
|
||||
}
|
||||
],
|
||||
|
||||
"web_accessible_resources": ["preview.html", "preview.js", "preview.css", "rss.xsl", "icons/file.png"],
|
||||
|
||||
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
|
||||
|
||||
}
|
116
preview.css
Normal file
116
preview.css
Normal file
@ -0,0 +1,116 @@
|
||||
|
||||
|
||||
html {
|
||||
font: 3mm tahoma,arial,helvetica,sans-serif;
|
||||
background-color: rgb(240, 240, 240);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 3em;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 160%;
|
||||
border-bottom: 2px solid ThreeDLightShadow;
|
||||
margin: 0 0 .2em 0;
|
||||
}
|
||||
|
||||
h1 a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: GrayText;
|
||||
font-size: 110%;
|
||||
font-weight: normal;
|
||||
margin: 0 0 .6em 0;
|
||||
}
|
||||
|
||||
a[href] img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#feedBody {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 3em;
|
||||
padding-inline-start: 30px;
|
||||
margin: 2em auto;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#feedTitleLink {
|
||||
float: right;
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#feedTitleContainer {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: .6em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#feedTitleImage {
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
max-width: 300px;
|
||||
max-height: 150px;
|
||||
}
|
||||
|
||||
.feedEntryContent {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.link:hover:active {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.lastUpdated {
|
||||
font-size: 85%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.enclosures {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
background-color: rgb(240, 240, 240);
|
||||
}
|
||||
|
||||
.enclosure {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.enclosureIcon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 3px;
|
||||
}
|
17
preview.html
Normal file
17
preview.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="preview.css">
|
||||
<link rel="shortcut icon" type="image/png" href="icons/rss-48.png">
|
||||
<script src="preview.js" ></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="feedBody"></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
136
preview.js
Normal file
136
preview.js
Normal file
@ -0,0 +1,136 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
main();
|
||||
});
|
||||
|
||||
function getxml(url) {
|
||||
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.open("GET", url, false);
|
||||
xhttp.send(null);
|
||||
return xhttp.responseXML;
|
||||
}
|
||||
|
||||
|
||||
function xhrxml(url, cb) {
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
xhr.responseType = 'document';
|
||||
xhr.overrideMimeType('text/xml');
|
||||
|
||||
xhr.onload = function () {
|
||||
if (xhr.readyState === xhr.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
cb(xhr.responseXML);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send(null);
|
||||
|
||||
}
|
||||
|
||||
function applyxsl(xmlin, xsl, node) {
|
||||
|
||||
var xsltProcessor = new XSLTProcessor();
|
||||
xsltProcessor.importStylesheet(xsl);
|
||||
|
||||
var fragment = xsltProcessor.transformToFragment(xmlin, document);
|
||||
node.appendChild(fragment);
|
||||
|
||||
}
|
||||
|
||||
function formatdescriptions() {
|
||||
|
||||
// unescapes descriptions to html
|
||||
|
||||
var tohtml = document.getElementsByClassName("feedEntryContent");
|
||||
for (var i = 0; i<tohtml.length; i++) {
|
||||
tohtml[i].innerHTML = tohtml[i].innerText;
|
||||
}
|
||||
|
||||
var feed_desc = document.getElementById("feedSubtitleText");
|
||||
feed_desc.innerHTML = feed_desc.innerText;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function removeemptyenclosures() {
|
||||
|
||||
var encs = document.getElementsByClassName("enclosures");
|
||||
for (var i = 0; i<encs.length; i++) {
|
||||
|
||||
if (!encs[i].firstChild)
|
||||
encs[i].style.display = "none";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function formatfilenames() {
|
||||
|
||||
var encfn = document.getElementsByClassName("enclosureFilename");
|
||||
for (var i = 0; i<encfn.length; i++) {
|
||||
var url = new URL(encfn[i].innerText);
|
||||
if (url) {
|
||||
var fn = url.pathname.split("/").pop();
|
||||
if (fn != "") {
|
||||
encfn[i].innerText = fn;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function formatfilesizes() {
|
||||
|
||||
function humanfilesize(size) {
|
||||
console.log(size);
|
||||
var i = 0;
|
||||
if (size && size != "" && size > 0)
|
||||
i = Math.floor( Math.log(size) / Math.log(1024) );
|
||||
return ( size / Math.pow(1024, i) ).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
|
||||
};
|
||||
|
||||
var encsz = document.getElementsByClassName("enclosureSize");
|
||||
for (var i = 0; i<encsz.length; i++) {
|
||||
var hsize = humanfilesize(encsz[i].innerText);
|
||||
if (hsize) {
|
||||
encsz[i].innerText = hsize;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
|
||||
var query_string = location.search.substring(1).split("&");
|
||||
var feed_url = decodeURIComponent(query_string[0]);
|
||||
|
||||
xhrxml(feed_url, function(feed_xml) {
|
||||
|
||||
|
||||
xhrxml(chrome.extension.getURL("rss.xsl"), function(xsl_xml) {
|
||||
|
||||
applyxsl(feed_xml, xsl_xml, document.getElementById("feedBody"));
|
||||
|
||||
removeemptyenclosures();
|
||||
formatdescriptions();
|
||||
formatfilenames();
|
||||
formatfilesizes();
|
||||
|
||||
document.title = "RSSPreview: " + document.getElementById("feedTitleText").innerText;
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
77
rss.xsl
Normal file
77
rss.xsl
Normal file
@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom" exclude-result-prefixes="atom" >
|
||||
|
||||
<xsl:output method="html" indent="yes" encoding="utf-8" />
|
||||
|
||||
|
||||
<xsl:template match="channel | atom:feed">
|
||||
|
||||
|
||||
<div id="feedTitle">
|
||||
<a id="feedTitleLink">
|
||||
<img id="feedTitleImage" src="{image/url | atom:logo}" />
|
||||
</a>
|
||||
<div id="feedTitleContainer">
|
||||
<h1 id="feedTitleText" >
|
||||
<a href="{link | atom:link[@rel='alternate']/@href}" target="_blank">
|
||||
<xsl:value-of select="title | atom:title" />
|
||||
</a>
|
||||
</h1>
|
||||
<h2 id="feedSubtitleText" ><xsl:value-of select="description | atom:subtitle" /></h2>
|
||||
<!--div class="lastUpdated">Last updated: <xsl:value-of select="lastBuildDate | atom:updated" /></div-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="feedContent">
|
||||
|
||||
<xsl:for-each select="item | atom:entry">
|
||||
|
||||
<div class="entry">
|
||||
|
||||
<h3>
|
||||
<xsl:choose>
|
||||
<xsl:when test="link | atom:link[@rel='alternate']/@href">
|
||||
<a href="{link | atom:link[@rel='alternate']/@href}" target="_blank">
|
||||
<span><xsl:value-of select="title | atom:title" /></span>
|
||||
</a>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<span><xsl:value-of select="title | atom:title" /></span>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
|
||||
<div class="lastUpdated"><xsl:value-of select="pubDate | atom:updated" /></div>
|
||||
</h3>
|
||||
<div class="feedEntryContent">
|
||||
<xsl:value-of select="description | atom:summary" disable-output-escaping="yes" />
|
||||
</div>
|
||||
<div class="enclosures">
|
||||
<xsl:for-each select="enclosure | atom:link[@rel='enclosure']">
|
||||
|
||||
<div class="enclosure">
|
||||
<img src="icons/file.png" class="enclosureIcon" />
|
||||
<a href="{@url | @href}" target="_blank" class="enclosureFilename"><xsl:value-of select="@url | @href" /></a>
|
||||
(<xsl:value-of select="@type" />, <span class="enclosureSize"><xsl:value-of select="@length" /></span>)
|
||||
</div>
|
||||
|
||||
</xsl:for-each>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
</xsl:for-each>
|
||||
|
||||
</div>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:apply-templates select="//channel | //atom:feed" />
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
28
rsspreview.js
Normal file
28
rsspreview.js
Normal file
@ -0,0 +1,28 @@
|
||||
(function() {
|
||||
/**
|
||||
* Check and set a global guard variable.
|
||||
* If this content script is injected into the same page again,
|
||||
* it will do nothing next time.
|
||||
*/
|
||||
if (window.hasRun) {
|
||||
console.log("already run");
|
||||
return;
|
||||
}
|
||||
window.hasRun = true;
|
||||
|
||||
const rootName = document.getRootNode().documentElement.nodeName;
|
||||
|
||||
|
||||
if (rootName == "rss" || rootName == "channel" || rootName == "feed") {
|
||||
|
||||
var feed_url = window.location.href;
|
||||
|
||||
var url = "preview.html?" + encodeURIComponent(feed_url);
|
||||
url = chrome.extension.getURL(url);
|
||||
|
||||
// redirect to preview page with feed url as query string
|
||||
window.location.replace(url);
|
||||
|
||||
}
|
||||
|
||||
})();
|
Loading…
Reference in New Issue
Block a user