diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e81bf30 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea/ +/ignore/ diff --git a/LICENCE.md b/LICENCE.md new file mode 100644 index 0000000..8092e7d --- /dev/null +++ b/LICENCE.md @@ -0,0 +1,7 @@ +Copyright 2013-2018 Josh Deltener + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 01bf5a5..9b3d5fa 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Welcome to Slick RSS -###The news reader extension for Google Chrome. +### The news reader extension for Google Chrome. -####As of 2014 Slick is no longer under active development. Why? +#### As of 2014 Slick is no longer under active development. Why? 1) There are plenty of other kick ass news readers out there, many with more features that are cross device capable. @@ -12,7 +12,7 @@ 4) RSS is a dieing technology. This may be a little "out there", but if you ask me, RSS is showing some age. Now days, people get their data from a wide variety of sources. RSS, Facebook, Tweets, Pins etc.. RSS seems to be the old way of sharing data. -######I'm including the source to V2 of Slick. Keep in mind, this was my very first Google Chrome Extension, and the code is a bit sloppy. I started it before I got into jQuery, so.. Have fun :) +###### I'm including the source to V2 of Slick. Keep in mind, this was my very first Google Chrome Extension, and the code is a bit sloppy. I started it before I got into jQuery, so.. Have fun :) If for some reason you decide to do something with this code, it's licensed under MIT License. http://opensource.org/licenses/MIT diff --git a/background.js b/background.js index 19fad6f..061a6a2 100644 --- a/background.js +++ b/background.js @@ -1,5 +1,4 @@ - -var manifest = GetManifest(); +var manifest = chrome.runtime.getManifest(); var options = GetOptions(); var unreadInfo = GetUnreadCounts(); var unreadTotal = 0; @@ -26,73 +25,58 @@ chrome.bookmarks.onMoved.addListener(CheckFeedChange); chrome.bookmarks.onRemoved.addListener(CheckFeedChange); DoUpgrades(); -GetFeeds(function() -{ +GetFeeds(function () { CleanUpUnreadOrphans(); CheckForUnreadStart(); }); // communicate with other pages -function InternalConnection(port) -{ - if(port.name == "viewerPort") - { +function InternalConnection(port) { + if (port.name == "viewerPort") { viewerPort = port; - port.onDisconnect.addListener(function(port){ viewerPort = null; }); + port.onDisconnect.addListener(function (port) { + viewerPort = null; + }); } } // tells viewer to reload, a feed changed -function ReloadViewer() -{ +function ReloadViewer() { CleanUpUnreadOrphans(); - if(viewerPort != null) - { + if (viewerPort != null) { viewerPort.postMessage({type: "feedschanged"}); } } // manage viewer spawning or focus -function ButtonClicked (tab) -{ - if(viewerPort == null) - { - chrome.tabs.create({url:"viewer.html"}, function(tab) - { - viewerPortTabID = tab.id; +function ButtonClicked(tab) { + if (viewerPort == null) { + chrome.tabs.create({url: "viewer.html"}, function (tab) { + viewerPortTabID = tab.id; }); - } - else - { - chrome.tabs.update(viewerPortTabID, {selected : true}); + } else { + chrome.tabs.update(viewerPortTabID, {selected: true}); } } -function ExternalRequest(request, sender, sendResponse) -{ - if(request.type == "addfeed") - { - if(options.feedsource == 1) - { +function ExternalRequest(request, sender, sendResponse) { + if (request.type == "addfeed") { + if (options.feedsource == 1) { chrome.bookmarks.create({parentId: options.feedfolderid, title: request.title, url: request.url}, null); - } - else - { + } else { var maxOrder = 0; - var order = 0; + var order = 0; - for(var i = 0;i < feeds.length; i++) - { - order = parseInt(feeds[i].order); + for (var i = 0; i < feeds.length; i++) { + order = parseInt(feeds[i].order); - if(order > maxOrder) - { + if (order > maxOrder) { maxOrder = order; } } - maxOrder ++; + maxOrder++; feeds.push(CreateNewFeed(request.title, request.url, options.maxitems, maxOrder)); localStorage["feeds"] = JSON.stringify(feeds); @@ -103,18 +87,12 @@ function ExternalRequest(request, sender, sendResponse) sendResponse({}); } - if(request.type == "deletefeed") - { - for(var i=0;i < feeds.length;i++) - { - if(feeds[i].url == request.url) - { - if(options.feedsource == 1) - { + if (request.type == "deletefeed") { + for (var i = 0; i < feeds.length; i++) { + if (feeds[i].url == request.url) { + if (options.feedsource == 1) { chrome.bookmarks.remove(feeds[i].id); - } - else - { + } else { feeds.splice(i, 1); localStorage["feeds"] = JSON.stringify(feeds); UpdateSniffer(); @@ -126,8 +104,7 @@ function ExternalRequest(request, sender, sendResponse) sendResponse({}); } - if(request.type == "updateme") - { + if (request.type == "updateme") { sendResponse({confirmed: true, version: manifest.version, name: manifest.name}); snifferID = sender.id; @@ -139,24 +116,18 @@ function ExternalRequest(request, sender, sendResponse) } // gets all or some options, filling in defaults when needed -function GetOptions() -{ +function GetOptions() { var options; var defaultOptions = GetDefaultOptions(); - if(localStorage["options"] == null) - { + if (localStorage["options"] == null) { options = GetDefaultOptions(); - } - else - { + } else { options = JSON.parse(localStorage["options"]); // fill in defaults for new options - for (key in defaultOptions) - { - if(options[key] == undefined) - { + for (key in defaultOptions) { + if (options[key] == undefined) { options[key] = defaultOptions[key]; } } @@ -166,70 +137,63 @@ function GetOptions() } // used to get defaults to help fill in missing pieces as I add more options -function GetDefaultOptions() -{ -return { "lastversion" : manifest.version, - "feedsource" : 0, - "feedfolderid" : "", - "maxitems" : 15, - "showdescriptions" : true, - "dateformat" : "[w], [mmmm] [ddd], [yyyy] [12h]:[nn] [a]", - "showfeedimages" : true, - "showfeedobjects" : true, - "showfeediframes" : false, - "showfeedcontent" : true, - "checkinterval" : 60, - "markreadonclick" : false, - "markreadafter" : 0, - "readitemdisplay" : 0, - "unreaditemtotaldisplay" : true, - "unreadtotaldisplay" : 3, - "columns" : 2, - "readlaterenabled" : true, - "readlaterremovewhenviewed" : true, - "readlaterincludetotal" : true, - "loadlinksinbackground": false - }; +function GetDefaultOptions() { + return { + "lastversion": manifest.version, + "feedsource": 0, + "feedfolderid": "", + "maxitems": 15, + "showdescriptions": true, + "dateformat": "[w], [mmmm] [ddd], [yyyy] [12h]:[nn] [a]", + "showfeedimages": true, + "showfeedobjects": true, + "showfeediframes": false, + "showfeedcontent": true, + "checkinterval": 60, + "markreadonclick": false, + "markreadafter": 0, + "readitemdisplay": 0, + "unreaditemtotaldisplay": true, + "unreadtotaldisplay": 3, + "columns": 2, + "readlaterenabled": true, + "readlaterremovewhenviewed": true, + "readlaterincludetotal": true, + "loadlinksinbackground": false + }; } // gets the feed array for everyone to use -function GetFeeds(callBack) -{ +function GetFeeds(callBack) { feeds = []; getFeedsCallBack = callBack; - if(options.feedsource == "0") - { - if(localStorage["feeds"] != null) - { - feeds = JSON.parse(localStorage["feeds"]).sort(function (a, b){ return a.order - b.order; }); + if (options.feedsource == "0") { + if (localStorage["feeds"] != null) { + feeds = JSON.parse(localStorage["feeds"]).sort(function (a, b) { + return a.order - b.order; + }); UpdateSniffer(); } feeds.unshift(GetReadLaterFeed()); getFeedsCallBack(); - } - else - { + } else { chrome.bookmarks.getChildren(options.feedfolderid, GetFeedFolderChildren); } } -function GetReadLaterFeed() -{ +function GetReadLaterFeed() { return CreateNewFeed("Read Later", "about:blank", 99999, -9, readLaterFeedID); } // fills feeds with bookmark items, for now it's not recursive -function GetFeedFolderChildren(nodeChildren) -{ +function GetFeedFolderChildren(nodeChildren) { feeds = []; // if via sniffer you remove a link and that link is in your bookmarks more than once, you get double the list because of multi-threading feeds.push(GetReadLaterFeed()); - for(var i=0;i < nodeChildren.length; i++) - { - if(nodeChildren[i].url != "") - { + for (var i = 0; i < nodeChildren.length; i++) { + if (nodeChildren[i].url != "") { feeds.push(CreateNewFeed(nodeChildren[i].title, nodeChildren[i].url, options.maxitems, i, nodeChildren[i].id)); } } @@ -238,22 +202,24 @@ function GetFeedFolderChildren(nodeChildren) getFeedsCallBack(); } -function GetReadLaterItems() -{ - if(localStorage["readlater"] == null) - { - localStorage["readlater"] = JSON.stringify({title: "Read Later", description: "Items you marked to read later", loading: false, items: [], error: ""}); +function GetReadLaterItems() { + if (localStorage["readlater"] == null) { + localStorage["readlater"] = JSON.stringify({ + title: "Read Later", + description: "Items you marked to read later", + loading: false, + items: [], + error: "" + }); } return JSON.parse(localStorage["readlater"]); } + // send new feeds to sniffer -function UpdateSniffer() -{ - if(snifferID != null) - { - chrome.extension.sendRequest(snifferID, feeds, function(response) - { +function UpdateSniffer() { + if (snifferID != null) { + chrome.extension.sendRequest(snifferID, feeds, function (response) { snifferName = response.name; snifferVersion = response.version; }); @@ -261,16 +227,11 @@ function UpdateSniffer() } // if a bookmark changes and it's one of our feeds then refresh -function BookmarkChanged(id, changeInfo) -{ - if(options.feedsource == 1) - { - chrome.bookmarks.get(id, function(node) - { - for(var i = 0;i < feeds.length; i++) - { - if(node[0].url == feeds[i].url) - { +function BookmarkChanged(id, changeInfo) { + if (options.feedsource == 1) { + chrome.bookmarks.get(id, function (node) { + for (var i = 0; i < feeds.length; i++) { + if (node[0].url == feeds[i].url) { GetFeeds(ReloadViewer); return; } @@ -280,26 +241,22 @@ function BookmarkChanged(id, changeInfo) } // checks for a bookmark change and reloads viewer if needed -function CheckFeedChange(id, notUsed) -{ - if(options.feedsource == 1) - { +function CheckFeedChange(id, notUsed) { + if (options.feedsource == 1) { var oldCount = feeds.length; - GetFeeds(function() - { - if(oldCount != feeds.length) - {ReloadViewer();} + GetFeeds(function () { + if (oldCount != feeds.length) { + ReloadViewer(); + } }); } } // helper function for creating new feeds -function CreateNewFeed(title, url, maxitems, order, id) -{ +function CreateNewFeed(title, url, maxitems, order, id) { // managed feed doesn't have an id yet - if(id == null) - { - id = GetRandomID(); + if (id == null) { + id = GetRandomID(); } return {title: title, url: url, maxitems: maxitems, order: order, id: id}; @@ -307,61 +264,42 @@ function CreateNewFeed(title, url, maxitems, order, id) } // converts the text date into a formatted one if possible -function GetFormattedDate(txtDate) -{ - var myDate = GetDate(txtDate); +function GetFormattedDate(txtDate) { + var myDate = GetDate(txtDate); - if(myDate == null) - { - return txtDate; - } + if (myDate == null) { + return txtDate; + } - return FormatDate(myDate, options.dateformat); + return FormatDate(myDate, options.dateformat); } // gets random numbers for managed feed ids -function GetRandomID() -{ +function GetRandomID() { var chars = "0123456789"; - var str = ""; - var rnum; - - for (var i=0; i < 10; i++) - { - rnum = Math.floor(Math.random() * chars.length); - str += chars.charAt(rnum); - } - - return str; -} - -// gets manifest information to send to Sniffer -function GetManifest() -{ - var req = new XMLHttpRequest(); - req.open("GET", chrome.extension.getURL("manifest.json"), false); - req.send(null); + var str = ""; + var rnum; - if(req.readyState == 4) - { - return JSON.parse(req.responseText); + for (var i = 0; i < 10; i++) { + rnum = Math.floor(Math.random() * chars.length); + str += chars.charAt(rnum); } + + return str; } // as this project gets larger there will be upgrades to storage items this will help -function DoUpgrades() -{ +function DoUpgrades() { var lastVersion = parseFloat(options.lastversion); // since 2.0 requires ids for feeds, lets make sure they have them - if(localStorage["feeds"] != null && lastVersion < 2.0) - { - var feeds = JSON.parse(localStorage["feeds"]).sort(function (a, b){ return a.order - b.order; }); - - for(var key in feeds) - { - if(feeds[key].id == null) - { + if (localStorage["feeds"] != null && lastVersion < 2.0) { + var feeds = JSON.parse(localStorage["feeds"]).sort(function (a, b) { + return a.order - b.order; + }); + + for (var key in feeds) { + if (feeds[key].id == null) { feeds[key].id = GetRandomID(); } } @@ -370,59 +308,50 @@ function DoUpgrades() } // 2.6 makes unread key MD5(title + date) - if(lastVersion < 2.6) - { + if (lastVersion < 2.6) { alert("Sorry, I have to nuke your unread information for this upgrade. Trust me, it's for the best."); delete localStorage["unreadinfo"]; unreadInfo = GetUnreadCounts(); } - if(lastVersion == 2.97) - { + if (lastVersion == 2.97) { var result = confirm("Ok, last time I'll bug you.\n\nSlick RSS now has a Google Group for news and support. Help shape Slick 3.0! Do you want to check it out now?\n\nhttps://groups.google.com/d/forum/slick-rss"); - - localStorage["alerted_group"] = 1; - - if(result) - { - chrome.tabs.create({url:"https://groups.google.com/d/forum/slick-rss"}); + + localStorage["alerted_group"] = 1; + + if (result) { + chrome.tabs.create({url: "https://groups.google.com/d/forum/slick-rss"}); } } - + // update the last version to now options.lastversion = manifest.version; localStorage["options"] = JSON.stringify(options); } // updates, shows and hides the badge -function UpdateUnreadBadge() -{ - if(unreadInfo == null) - { +function UpdateUnreadBadge() { + if (unreadInfo == null) { return; } var total = 0; var str = ""; - for(var key in unreadInfo) - { + for (var key in unreadInfo) { total = total + unreadInfo[key].unreadtotal; } - if(!options.readlaterincludetotal && unreadInfo[readLaterFeedID] != null) - { + if (!options.readlaterincludetotal && unreadInfo[readLaterFeedID] != null) { total = total - unreadInfo[readLaterFeedID].unreadtotal; } - if(total > 0) - { + if (total > 0) { str = total + ""; } // they don't want toolbar unread updates - if(options.unreadtotaldisplay == 0 || options.unreadtotaldisplay == 2) - { + if (options.unreadtotaldisplay == 0 || options.unreadtotaldisplay == 2) { str = ""; } @@ -432,18 +361,15 @@ function UpdateUnreadBadge() chrome.browserAction.setBadgeText({text: str}); // update title - if(viewerPort != null) - { + if (viewerPort != null) { viewerPort.postMessage({type: "unreadtotalchanged"}); } } // returns a dictionary of unread counts {bookmarkid} = unreadtotal, readitems{} // may need a way to clean this if they delete feeds -function GetUnreadCounts() -{ - if(localStorage["unreadinfo"] == null) - { +function GetUnreadCounts() { + if (localStorage["unreadinfo"] == null) { localStorage["unreadinfo"] = JSON.stringify({}); } @@ -452,10 +378,8 @@ function GetUnreadCounts() // starts the checking for unread (and now loading of data) // if key is filled in, then only that feed will be refreshed -function CheckForUnreadStart(key) -{ - if(checkingForUnread || feeds.length == 0) - { +function CheckForUnreadStart(key) { + if (checkingForUnread || feeds.length == 0) { return; } @@ -463,18 +387,14 @@ function CheckForUnreadStart(key) checkingForUnread = true; // keep timer going on "refresh" - if(key == null) - { + if (key == null) { clearTimeout(checkForUnreadTimerID); checkForUnreadTimerID = setTimeout(CheckForUnreadStart, options.checkinterval * 1000 * 60); - if(viewerPort != null) - { + if (viewerPort != null) { viewerPort.postMessage({type: "refreshallstarted"}); } - } - else - { + } else { refreshFeed = true; } @@ -482,8 +402,7 @@ function CheckForUnreadStart(key) } // goes through each feed and gets how many you haven't read since last time you were there -function CheckForUnread() -{ +function CheckForUnread() { var req = new XMLHttpRequest(); var toID = setTimeout(req.abort, 60000); var feedID = feeds[checkForUnreadCounter].id; @@ -491,101 +410,79 @@ function CheckForUnread() feedInfo[feedID] = {title: "", description: "", loading: true, items: [], error: ""}; - if(viewerPort != null) - { + if (viewerPort != null) { viewerPort.postMessage({type: "feedupdatestarted", id: feedID}); } - try - { + try { // get data and be nice to mac rss feeds req.open("get", feeds[checkForUnreadCounter].url.replace(/feed:\/\//i, "http://"), true); req.overrideMimeType('text/xml'); - req.onreadystatechange = function() - { - if(req.readyState == 4) - { + req.onreadystatechange = function () { + if (req.readyState == 4) { clearTimeout(toID); var doc = req.responseXML; // initialize unread object if not setup yet - if(unreadInfo[feedID] == null) - { + if (unreadInfo[feedID] == null) { unreadInfo[feedID] = {unreadtotal: 0, readitems: {}}; } unreadInfo[feedID].unreadtotal = 0; - if(req.status == 200) - { - if(doc) - { + if (req.status == 200) { + if (doc) { var readItemCount = 0; var item = null; var entryID = null; var entryIDs = {}; - var entries = GetElementsByTagName(doc, [], "entry", "item"); + var entries = GetElementsByTagName(doc, [], "entry", "item"); var rootNode = GetElementByTagName(doc, null, "feed", "rss", "rdf:RDF"); var author = null; var name = null; - if(rootNode != null) - { - if(rootNode.nodeName == "feed") - { + if (rootNode != null) { + if (rootNode.nodeName == "feed") { feedInfo[feedID].title = GetNodeTextValue(GetElementByTagName(rootNode, null, "title")); feedInfo[feedID].description = GetNodeTextValue(GetElementByTagName(rootNode, null, "subTitle", "description")); - } - else - { + } else { var channel = GetElementByTagName(rootNode, null, "channel"); - if(channel != null) - { + if (channel != null) { feedInfo[feedID].title = GetNodeTextValue(GetElementByTagName(channel, null, "title")); feedInfo[feedID].description = GetNodeTextValue(GetElementByTagName(channel, null, "description", "subTitle")); } } } - for(var e=0;e < entries.length;e++) - { + for (var e = 0; e < entries.length; e++) { item = {}; item.title = GetNodeTextValue(GetElementByTagName(entries[e], null, "title"), "No Title"); item.date = GetNodeTextValue(GetElementByTagName(entries[e], null, "pubDate", "updated", "dc:date", "date", "published")); // not sure if date is even needed anymore item.content = ""; // don't bother storing extra stuff past max.. only title for Mark All Read - if(e <= feeds[checkForUnreadCounter].maxitems) - { + if (e <= feeds[checkForUnreadCounter].maxitems) { item.url = GetFeedLink(entries[e]); - if(options.showfeedcontent) - { + if (options.showfeedcontent) { item.content = GetNodeTextValue(GetElementByTagName(entries[e], null, "content:encoded", "content")); // only guessing on just "content" } - if(item.content == "") - { + if (item.content == "") { item.content = GetNodeTextValue(GetElementByTagName(entries[e], null, "description", "summary")); } author = GetElementByTagName(entries[e], null, "author", "dc:creator"); - if(author != null) - { + if (author != null) { name = GetElementByTagName(author, null, "name"); - if(name != null) - { + if (name != null) { item.author = GetNodeTextValue(name); - } - else - { + } else { item.author = GetNodeTextValue(author); } - } - else - { // for some reason the author gets funky with floats if it's empty.. so whatever + } else { // for some reason the author gets funky with floats if it's empty.. so whatever item.author = " "; } } @@ -595,37 +492,25 @@ function CheckForUnread() } // count read that are in current feed - for(var key in unreadInfo[feedID].readitems) - { - if(entryIDs[key] == null) - { + for (var key in unreadInfo[feedID].readitems) { + if (entryIDs[key] == null) { // if the read item isn't in the current feed and it's past it's expiration date, nuke it - if(now > new Date(unreadInfo[feedID].readitems[key])) - { + if (now > new Date(unreadInfo[feedID].readitems[key])) { delete unreadInfo[feedID].readitems[key]; } - } - else - { + } else { readItemCount++; } } unreadInfo[feedID].unreadtotal = entries.length - readItemCount; - } - else - { - feedInfo[feedID].error = "The response didn't have a valid responseXML property."; - } - } - else - { - if(feedID != readLaterFeedID) - { - feedInfo[feedID].error = "Status wasn't 200. It was " + req.status + " and frankly I don't know how to handle that. If it helps, the status text was '" + req.statusText + "'."; + } else { + feedInfo[feedID].error = "The response didn't have a valid responseXML property."; } - else - { + } else { + if (feedID != readLaterFeedID) { + feedInfo[feedID].error = "Status wasn't 200. It was " + req.status + " and frankly I don't know how to handle that. If it helps, the status text was '" + req.statusText + "'."; + } else { // cheat the system, fill in read later info feedInfo[feedID] = GetReadLaterItems(); unreadInfo[feedID].unreadtotal = feedInfo[feedID].items.length; @@ -634,8 +519,7 @@ function CheckForUnread() localStorage["unreadinfo"] = JSON.stringify(unreadInfo); - if(viewerPort != null) - { + if (viewerPort != null) { viewerPort.postMessage({type: "feedupdatecomplete", id: feedID}); } @@ -646,31 +530,24 @@ function CheckForUnread() feedInfo[feedID].loading = false; - if(checkForUnreadCounter >= feeds.length || refreshFeed) - { + if (checkForUnreadCounter >= feeds.length || refreshFeed) { CheckForUnreadComplete(); - } - else - { + } else { CheckForUnread(); } } } req.send(null); - } - catch(err) - { - // onreadystate should already be called, so don't do anything! + } catch (err) { + // onreadystate should already be called, so don't do anything! } } // ran after checking for unread is done -function CheckForUnreadComplete() -{ - if(viewerPort != null && !refreshFeed) - { +function CheckForUnreadComplete() { + if (viewerPort != null && !refreshFeed) { viewerPort.postMessage({type: "refreshallcomplete"}); } @@ -680,19 +557,15 @@ function CheckForUnreadComplete() } // since the key for unread is the feed id, it's possible that you removed some, as such we should update and clean house -function CleanUpUnreadOrphans() -{ +function CleanUpUnreadOrphans() { var feedIDs = {}; - for(var key in feeds) - { + for (var key in feeds) { feedIDs[feeds[key].id] = 1; } - for(var key in unreadInfo) - { - if(feedIDs[key] == null) - { + for (var key in unreadInfo) { + if (feedIDs[key] == null) { delete unreadInfo[key]; } } @@ -702,19 +575,15 @@ function CleanUpUnreadOrphans() } // to help with master title & description getting -function GetNodeTextValue(node, defaultValue) -{ - if(node == null || node.childNodes.length == 0) - { +function GetNodeTextValue(node, defaultValue) { + if (node == null || node.childNodes.length == 0) { return (defaultValue == null) ? "" : defaultValue; } var str = ""; - for(var i = 0; i < node.childNodes.length;i++) - { - if(node.childNodes[i].nodeValue != null) - { + for (var i = 0; i < node.childNodes.length; i++) { + if (node.childNodes[i].nodeValue != null) { str += node.childNodes[i].nodeValue; } } @@ -722,17 +591,14 @@ function GetNodeTextValue(node, defaultValue) return str; } -function GetFeedLink(node) -{ +function GetFeedLink(node) { var links = node.getElementsByTagName("link"); - if(links.length == 0) - { + if (links.length == 0) { // is yet another way of saying link var guids = node.getElementsByTagName("guid"); - if(guids.length == 0 || guids[0].getAttribute("ispermalink") == "false") - { + if (guids.length == 0 || guids[0].getAttribute("ispermalink") == "false") { return ""; } @@ -740,17 +606,14 @@ function GetFeedLink(node) } - for(var i = 0;i < links.length;i++) - { + for (var i = 0; i < links.length; i++) { // in atom feeds alternate is the default so if something else is there then skip - if(links[i].getAttribute("href") != null && (links[i].getAttribute("rel") == "alternate" || links[i].getAttribute("rel") == null)) - { + if (links[i].getAttribute("href") != null && (links[i].getAttribute("rel") == "alternate" || links[i].getAttribute("rel") == null)) { return links[i].getAttribute("href"); } // text node or CDATA node - if(links[i].childNodes.length == 1 && (links[i].childNodes[0].nodeType == 3 || links[i].childNodes[0].nodeType == 4)) - { + if (links[i].childNodes.length == 1 && (links[i].childNodes[0].nodeType == 3 || links[i].childNodes[0].nodeType == 4)) { return links[i].childNodes[0].nodeValue; } } @@ -760,16 +623,12 @@ function GetFeedLink(node) // since node.getElementsByTag name is recursive and sometimes we don't want that // GetElementByTagName(node, defaultValue, target1, target2) -function GetElementByTagName() -{ +function GetElementByTagName() { var node = arguments[0]; - for(var i = 0; i < node.childNodes.length; i++) - { - for(e = 2;e < arguments.length;e++) - { - if(node.childNodes[i].nodeName.toUpperCase() == arguments[e].toUpperCase()) - { + for (var i = 0; i < node.childNodes.length; i++) { + for (e = 2; e < arguments.length; e++) { + if (node.childNodes[i].nodeName.toUpperCase() == arguments[e].toUpperCase()) { return node.childNodes[i]; } } @@ -779,18 +638,15 @@ function GetElementByTagName() } // node, defaultValue, list of tags -function GetElementsByTagName() -{ +function GetElementsByTagName() { var node = arguments[0]; var defaultValue = arguments[1]; var item; - for(var i = 2;i < arguments.length; i++) - { + for (var i = 2; i < arguments.length; i++) { item = node.getElementsByTagName(arguments[i]); - if(item.length > 0) - { + if (item.length > 0) { return item; } } diff --git a/common.css b/common.css index c181869..02b6483 100644 --- a/common.css +++ b/common.css @@ -1,70 +1,60 @@ -html -{ - height: 100%; +html { + height: 100%; } -body -{ +body { margin: 0px; padding: 0px; - font-family: tahoma, arial, sans-serif; + font-family: sans-serif; font-size: 11px; color: Black; background-color: white; width: 100%; - height: 100%; + height: 100%; } -#header -{ - font-size: 20px; +#header { + font-size: 20px; /*border-bottom: 1px solid #DEDEDE;*/ - background-color: #454D5E; - color: White; + background-color: #454d5e; + color: White; } -#headerMessage span -{ - font-size: smaller; +#headerMessage span { + font-size: smaller; } -#header td -{ +#header td { width: 1%; vertical-align: middle; } -#header tr > td:first-child -{ +#header tr > td:first-child { min-width: 26px; height: 26px; background-image: url("rss.png"); background-repeat: no-repeat; - background-position: center; + background-position: center; } -#header td+td -{ +#header td + td { width: 98%; } -#header td+td+td -{ - text-align: right; +#header td + td + td { + text-align: right; white-space: nowrap; font-size: 14px; - color: #AAAAAA; + color: #aaa; padding-right: 10px; } -#header a -{ +#header a { font-size: 12px; color: white; - text-decoration: none; + text-decoration: none; } -#header a:hover -{ - text-decoration: underline; -} \ No newline at end of file +#header a:hover { + text-decoration: underline; +} diff --git a/manifest.json b/manifest.json index afa2c44..8cb5701 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,25 @@ { "manifest_version": 2, - "name" : "Slick RSS", - "version" : "2.993", - "description" : "A full featured RSS reader that's fully contained within the browser.", - "options_page" : "options.html", - "icons": { "128" : "icon_128.png", "16":"transmit.png"}, - "browser_action" : {"default_icon": "transmit.png", "default_title": "Slick RSS"}, - "background" : {"page": "background.html"}, - "permissions" : ["http://*/", "https://*/", "tabs", "bookmarks"] -} \ No newline at end of file + "name": "Slick RSS", + "version": "2.993", + "description": "A full featured RSS reader that's fully contained within the browser.", + "options_page": "options.html", + "icons": { + "128": "icon_128.png", + "16": "transmit.png" + }, + "browser_action": { + "default_icon": "transmit.png", + "default_title": "Slick RSS" + }, + "background": { + "page": "background.html" + }, + "permissions": [ + "http://*/", + "https://*/", + "tabs", + "bookmarks" + ], + "content_security_policy": "script-src 'self'; object-src 'self'" +} diff --git a/viewer.css b/viewer.css index 6b13d12..7984cbb 100644 --- a/viewer.css +++ b/viewer.css @@ -1,209 +1,185 @@ -body -{ - overflow: hidden; +body { + overflow: hidden; } -#containerArea -{ - width: 100%; +#containerArea { + width: 100%; height: 100%; } -#feedScroller -{ +#feedScroller { overflow-y: auto; overflow-x: hidden; - background-color: #FCFCFC; - border-right: 1px solid #DEDEDE; + background-color: #fcfcfc; + border-right: 1px solid #dedede; } -#feedPreviewScroller -{ +#feedPreviewScroller { overflow: auto; + width: 100% !important; } -#feedHeader -{ - font-size: 15px; +#feedHeader { + font-size: 15px; background-color: #666d7c; - color: #AAAAAA; - padding-left: 10px; + color: #aaa; + padding-left: 10px; } -#feedHeader a -{ +#feedHeader a { font-size: 12px; color: white; - text-decoration: none; + text-decoration: none; } -#feedHeader a:hover -{ - text-decoration: underline; +#feedHeader a:hover { + text-decoration: underline; } -#feedList -{ +#feedList { list-style-type: none; margin: 0px; padding: 10px; } -#feedList li -{ +#feedList li { padding: 3px; white-space: nowrap; - cursor: pointer; - border: 1px solid #FCFCFC; + cursor: pointer; + border: 1px solid #fcfcfc; margin-bottom: 1px; } -#feedList li:hover -{ - border: 1px solid #D8D8D8; +#feedList li:hover { + border: 1px solid #d8d8d8; } -#feedArea, #workArea -{ - vertical-align: top; +#feedArea, #workArea { + vertical-align: top; height: 99%; /* keeps headers on top when there isn't enough content since master table is 100% height */ } -#feedsLoading -{ - display: none; +#feedsLoading { + display: none; width: 99%; color: White; - font-size: small; + font-size: small; } -#feedsLoading td+td -{ +#feedsLoading td + td { width: 99%; padding: 10px; } -#feedsLoadingProgressBox -{ - border: 1px solid #AAAAAA; +#feedsLoadingProgressBox { + border: 1px solid #aaa; width: 100%; } -#feedsLoadingProgress -{ +#feedsLoadingProgress { width: 0%; height: 5px; - background-color: #EEEEEE; + background-color: #eee; } -#feedsOptions -{ - white-space: nowrap; +#feedsOptions { + white-space: nowrap; } -.loading tr > td:first-child -{ +.loading tr > td:first-child { background-image: url("loading.gif") !important; } - -#feedPreview -{ - font-family: Verdana, Arial, sans-serif; +#feedPreview { font-size: 12px; - width: 100%; + outline: none; + width: 100%; } - -#feedPreview td -{ - vertical-align: top; +#feedPreview td { + vertical-align: top; + word-break: break-word; } - -.feedPreviewContainerCondensed .feedPreviewSummary, .feedPreviewContainerCondensed .feedPreviewDate, .feedPreviewContainerCondensed .feedPreviewAuthor -{ - display: none; +.feedPreviewContainerCondensed .feedPreviewSummary, .feedPreviewContainerCondensed .feedPreviewDate, .feedPreviewContainerCondensed .feedPreviewAuthor { + display: none; } -.feedPreviewContainerRead -{ - border: 1px solid #D0D0D0 !important; +.feedPreviewContainerRead { + border: 1px solid #d0d0d0 !important; } -.feedPreviewContainerRead .feedPreviewTitle -{ - background-color: #EFEFEF; +.feedPreviewContainerRead .feedPreviewTitle { + background-color: #efefef; } -.feedPreviewContainerRead .feedPreviewMarkRead, .feedPreviewContainerRead .feedPreviewReadLater -{ - display: none; +.feedPreviewContainerRead .feedPreviewMarkRead, .feedPreviewContainerRead .feedPreviewReadLater { + display: none; } -.feedPreviewContainer -{ - border: 1px solid #96B6DF; +.feedPreviewContainer { + border: 1px solid #96b6df; } /* And the king decreed, let there be wrapping for all */ -.feedPreviewContainer * -{ - white-space: normal; +.feedPreviewContainer * { + white-space: normal; } -.feedPreviewTitle -{ - background-color: #D7E6F8; +.feedPreviewTitle { + background-color: #d7e6f8; margin: 0px; padding: 5px; } -.feedPreviewTitle a -{ +.feedPreviewTitle a { text-decoration: none; - color: Black; + color: Black; font-size: 12px; } -.feedPreviewTitle a:hover -{ - text-decoration: underline; +.feedPreviewTitle a:hover { + text-decoration: underline; +} + +.feedPreviewSummary { + padding: 5px; + max-height: 200px; + overflow: auto; } -.feedPreviewSummary -{ - padding: 5px; +.feedPreviewSummary table { + width: auto; } -.feedPreviewDate -{ - padding: 5px; - font-size: smaller; +blockquote > blockquote > blockquote > blockquote { + display: none; +} + +.feedPreviewDate { + padding: 5px; + font-size: smaller; float: left; white-space: nowrap; width: 1%; } -.feedPreviewAuthor -{ - padding: 5px; - font-size: smaller; - text-align: right; +.feedPreviewAuthor { + padding: 5px; + font-size: smaller; + text-align: right; } -.feedPreviewMarkRead -{ +.feedPreviewMarkRead { float: right; - border: 1px solid transparent; + border: 1px solid transparent; cursor: pointer; width: 12px; height: 12px; } -.feedPreviewReadLater -{ +.feedPreviewReadLater { float: right; margin-top: -1px; margin-right: 7px; @@ -212,50 +188,41 @@ body height: 16px; } -.selectedFeed -{ - background-color: #E5EEFA; - border: 1px solid #A9CAF8 !important; +.selectedFeed { + background-color: #e5eefa; + border: 1px solid #a9caf8 !important; color: #285491; } -#noFeedsManaged, #noFeedsBookmarks -{ - font-size: 12px; +#noFeedsManaged, #noFeedsBookmarks { + font-size: 12px; padding: 5px; } -#feedError -{ +#feedError { font-size: 12px; - padding: 5px; + padding: 5px; } -#feedErrorDetail -{ - font-weight: bold; +#feedErrorDetail { + font-weight: bold; } -#feedErrorMessage -{ +#feedErrorMessage { color: Red; - font-weight: normal; + font-weight: normal; } - -#feedTitle9999999999 -{ - border-bottom: 1px solid #DEDEDE !important; +#feedTitle9999999999 { + border-bottom: 1px solid #dedede !important; } -#feedTitle9999999999[class=selectedFeed] -{ - border-bottom: 1px solid #A9CAF8 !important; +#feedTitle9999999999[class=selectedFeed] { + border-bottom: 1px solid #a9caf8 !important; } -#noItems -{ +#noItems { padding: 5px; - font-size: 12px; + font-size: 12px; } diff --git a/viewer.html b/viewer.html index 9d405da..930f6be 100644 --- a/viewer.html +++ b/viewer.html @@ -1,77 +1,76 @@ - - - - - - - - - - - - + + + + + + + - - + - - - - - + - + +
+
- - - - -
Refreshing
+ + + + + +
Refreshing +
+
+
+
- - Refresh All | Mark All Read + + Refresh All | Mark All Read -
- + + + - - - - -
+ -
-
    -
    -
    +
    +
      +
      +
      - + - + - + - + -
      -
      -
      +
      +
      +
      -
      - - - diff --git a/viewer.js b/viewer.js index b222111..b2616fb 100644 --- a/viewer.js +++ b/viewer.js @@ -1,13 +1,23 @@ - // to prevent XSS :( -$(document).ready(function() -{ - $('#refreshAll').click(function(){bgPage.CheckForUnreadStart();}); - $('#markAllRead').click(function(){MarkAllFeedsRead();}); - $('#refreshButton').click(function(){bgPage.CheckForUnreadStart(selectedFeedKey);}); - $('#markFeedReadButton').click(function(){MarkFeedRead(feeds[selectedFeedKey].id);}); - $('#showOptions').click(function(){chrome.tabs.create({url:'options.html'});}); - $('#addFeeds').click(function(){window.location = 'manage.html';}); +$(document).ready(function () { + $('#refreshAll').click(function () { + bgPage.CheckForUnreadStart(); + }); + $('#markAllRead').click(function () { + MarkAllFeedsRead(); + }); + $('#refreshButton').click(function () { + bgPage.CheckForUnreadStart(selectedFeedKey); + }); + $('#markFeedReadButton').click(function () { + MarkFeedRead(feeds[selectedFeedKey].id); + }); + $('#showOptions').click(function () { + chrome.tabs.create({url: 'options.html'}); + }); + $('#addFeeds').click(function () { + window.location = 'manage.html'; + }); }); var bgPage = chrome.extension.getBackgroundPage(); @@ -18,52 +28,42 @@ var feedReadToID = null; var port = chrome.extension.connect({name: "viewerPort"}); -port.onMessage.addListener(function(msg) -{ - if(msg.type == "feedschanged") - { - location = 'viewer.html'; +port.onMessage.addListener(function (msg) { + if (msg.type == "feedschanged") { + location = 'viewer.html'; } - - if(msg.type == "refreshallstarted") - { - document.getElementById("feedsLoadingProgress").style.width = "0%"; + + if (msg.type == "refreshallstarted") { + document.getElementById("feedsLoadingProgress").style.width = "0%"; } - - if(msg.type == "refreshallcomplete") - { + + if (msg.type == "refreshallcomplete") { document.getElementById("feedsOptions").style.display = ""; - document.getElementById("feedsLoading").style.display = "none"; + document.getElementById("feedsLoading").style.display = "none"; } - - if(msg.type == "feedupdatestarted") - { - if(!bgPage.refreshFeed) - { + + if (msg.type == "feedupdatestarted") { + if (!bgPage.refreshFeed) { UpdateRefreshAllProgress(); } - - if(msg.id == feeds[selectedFeedKey].id) - { - document.getElementById("header").className = "loading"; + + if (msg.id == feeds[selectedFeedKey].id) { + document.getElementById("header").className = "loading"; } } - - if(msg.type == "feedupdatecomplete") - { - UpdateFeedUnread(msg.id); - + + if (msg.type == "feedupdatecomplete") { + UpdateFeedUnread(msg.id); + // refresh page if you are on the one that changed - if(msg.id == feeds[selectedFeedKey].id) - { - SelectFeed(selectedFeedKey); - document.getElementById("header").className = ""; - } + if (msg.id == feeds[selectedFeedKey].id) { + SelectFeed(selectedFeedKey); + document.getElementById("header").className = ""; + } } - - if(msg.type == "unreadtotalchanged") - { - UpdateTitle(); + + if (msg.type == "unreadtotalchanged") { + UpdateTitle(); } }); @@ -71,336 +71,304 @@ window.onload = ShowFeeds; window.onresize = FixFeedList; -function UpdateRefreshAllProgress() -{ +function UpdateRefreshAllProgress() { document.getElementById("feedsOptions").style.display = "none"; document.getElementById("feedsLoading").style.display = "block"; - + document.getElementById("feedsLoadingProgress").style.width = Math.round(((bgPage.checkForUnreadCounter + 1) / feeds.length) * 100) + "%"; } -function UpdateTitle() -{ - var title = "Slick RSS"; - - if((options.unreadtotaldisplay == 2 || options.unreadtotaldisplay == 3) && bgPage.unreadTotal > 0) - { - title += " (" + bgPage.unreadTotal + ")"; +function UpdateTitle() { + var title = "Slick RSS" + (feeds[selectedFeedKey] ? " [" + feeds[selectedFeedKey].title + "]" : ""); + + if ((options.unreadtotaldisplay == 2 || options.unreadtotaldisplay == 3) && bgPage.unreadTotal > 0) { + title += " (" + bgPage.unreadTotal + ")"; } - - document.title = title; + + document.title = title; document.getElementById("markAllRead").style.display = (bgPage.unreadTotal > 0) ? "" : "none"; } -function ShowFeeds() -{ +function ShowFeeds() { var feedArea = null; var selectKey = null; var lastSelectedID = localStorage["lastSelectedFeedID"]; - - UpdateTitle(); - - for(key in feeds) - { - if(key == 0 && !options.readlaterenabled) - { - continue; + + UpdateTitle(); + + for (key in feeds) { + if (key == 0 && !options.readlaterenabled) { + continue; } - - ShowFeed(key); - - if(selectKey == null) - { + + ShowFeed(key); + + if (selectKey == null) { selectKey = key; } - - if(feeds[key].id == lastSelectedID) - { + + if (feeds[key].id == lastSelectedID) { selectKey = key; - } + } } - - if(feeds.length == 0 || (feeds.length == 1 && bgPage.feedInfo[bgPage.readLaterFeedID].items.length == 0)) - { - if(options.feedsource == "0") - { + + if (feeds.length == 0 || (feeds.length == 1 && bgPage.feedInfo[bgPage.readLaterFeedID].items.length == 0)) { + if (options.feedsource == "0") { document.getElementById("noFeedsManaged").style.display = ""; - } - else - { + } else { document.getElementById("noFeedsBookmarks").style.display = ""; } - - document.getElementById("headerMessage").innerText = "Feed Me"; + + document.getElementById("headerMessage").innerText = "Feed Me"; document.getElementById("feedHeader").style.display = "none"; document.getElementById("feedArea").style.display = "none"; - document.getElementById("refresh").style.display = "none"; - document.getElementById("markFeedRead").style.display = "none"; - } - else - { - SelectFeed(selectKey); - } + document.getElementById("refresh").style.display = "none"; + document.getElementById("markFeedRead").style.display = "none"; + } else { + SelectFeed(selectKey); + } // in the middle of refresh all, show progress but wait a little so feed content pushes the feed list to the right size // this is only here to show progress on load when current loading feed is slow, otherwise the next feed will update the progress - if(bgPage.checkingForUnread && !bgPage.refreshFeed) - { + if (bgPage.checkingForUnread && !bgPage.refreshFeed) { setTimeout(UpdateRefreshAllProgress, 500); } - - document.getElementById("manage").style.display = (options.feedsource != 0) ? "none" : ""; + + document.getElementById("manage").style.display = (options.feedsource != 0) ? "none" : ""; + focusFeed(); } -function FixFeedList() -{ +function FixFeedList() { var feedScroller = document.getElementById("feedScroller"); var feedPreviewScroller = document.getElementById("feedPreviewScroller"); - var header = document.getElementById("header"); - + var header = document.getElementById("header"); + feedPreviewScroller.style.height = (document.body.offsetHeight - header.offsetHeight) + "px"; feedPreviewScroller.style.width = (window.innerWidth - feedScroller.offsetWidth) + "px"; // some feeds don't wrap well so we must force a strict width - - feedScroller.style.height = document.body.offsetHeight - document.getElementById("feedHeader").offsetHeight + "px"; - feedScroller.style.overflowY = (feedScroller.offsetHeight < feedScroller.scrollHeight) ? "scroll" : "hidden"; + + feedScroller.style.height = document.body.offsetHeight - document.getElementById("feedHeader").offsetHeight + "px"; + feedScroller.style.overflowY = (feedScroller.offsetHeight < feedScroller.scrollHeight) ? "scroll" : "hidden"; } -function ShowFeed(key) -{ +function ShowFeed(key) { var li = document.createElement("li"); var span = document.createElement("span"); - - li.innerText = feeds[key].title; + + li.innerText = feeds[key].title; li.setAttribute("id", "feedTitle" + feeds[key].id); span.setAttribute("id", "feedUnread" + feeds[key].id); - - $(li).click(function(){SelectFeed(key);return false;}); + + $(li).click(function () { + SelectFeed(key); + focusFeed(); + UpdateTitle(); + return false; + }); //ClickBuilder(li, "SelectFeed('" + key + "')"); - - li.appendChild(span); - + + li.appendChild(span); + document.getElementById("feedList").appendChild(li); - - UpdateFeedUnread(feeds[key].id); + + UpdateFeedUnread(feeds[key].id); +} + +function focusFeed() { + var feedPreview = document.getElementById("feedPreview"); + feedPreview.focus(); } // updates a feed item's unread count -function UpdateFeedUnread(id) -{ - if(bgPage.unreadInfo[id] == null || !options.unreaditemtotaldisplay) - { +function UpdateFeedUnread(id) { + if (bgPage.unreadInfo[id] == null || !options.unreaditemtotaldisplay) { return; } - + var count = bgPage.unreadInfo[id].unreadtotal; - - if(count > 0) - { + + if (count > 0) { document.getElementById("feedTitle" + id).style.fontWeight = "bold"; - document.getElementById("feedUnread" + id).innerText = " (" + count + ")"; - } - else - { + document.getElementById("feedUnread" + id).innerText = " (" + count + ")"; + } else { document.getElementById("feedTitle" + id).style.fontWeight = "normal"; - document.getElementById("feedUnread" + id).innerText = ""; - } - - FixFeedList(); + document.getElementById("feedUnread" + id).innerText = ""; + } + + FixFeedList(); } -function UpdateReadAllIcon() -{ - var count = 0; - - if(bgPage.unreadInfo != null && bgPage.unreadInfo[feeds[selectedFeedKey].id] != null) - { - count = bgPage.unreadInfo[feeds[selectedFeedKey].id].unreadtotal; - } - - document.getElementById("markFeedRead").style.display = (count > 0) ? "" : "none"; - - +function UpdateReadAllIcon() { + var count = 0; + + if (bgPage.unreadInfo != null && bgPage.unreadInfo[feeds[selectedFeedKey].id] != null) { + count = bgPage.unreadInfo[feeds[selectedFeedKey].id].unreadtotal; + } + + document.getElementById("markFeedRead").style.display = (count > 0) ? "" : "none"; + + } // marks everything but ReadLater read -function MarkAllFeedsRead() -{ +function MarkAllFeedsRead() { var id; - - for(var i = 0; i < feeds.length;i++) - { + + for (var i = 0; i < feeds.length; i++) { id = feeds[i].id; - - if(id != bgPage.readLaterFeedID) - { + + if (id != bgPage.readLaterFeedID) { MarkFeedRead(id); - } + } } - + // this helps the refresh all progress bar be the right width FixFeedList(); } // marks a feed read. -function MarkFeedRead(feedID) -{ +function MarkFeedRead(feedID) { var container = null; var itemID = null; var className = (options.readitemdisplay == 0) ? " feedPreviewContainerRead" : " feedPreviewContainerRead feedPreviewContainerCondensed"; var expireMs = new Date().getTime() + 5184000000; // 2 months; - - if(bgPage.unreadInfo[feedID].unreadtotal == 0) - { + + if (bgPage.unreadInfo[feedID].unreadtotal == 0) { return; } - + bgPage.unreadInfo[feedID].unreadtotal = 0; - + // for read later feeds, nuke the items instead of mark read - if(feedID == bgPage.readLaterFeedID) - { - bgPage.feedInfo[bgPage.readLaterFeedID].items = []; - localStorage["readlater"] = JSON.stringify(bgPage.feedInfo[bgPage.readLaterFeedID]); + if (feedID == bgPage.readLaterFeedID) { + bgPage.feedInfo[bgPage.readLaterFeedID].items = []; + localStorage["readlater"] = JSON.stringify(bgPage.feedInfo[bgPage.readLaterFeedID]); SelectFeed(0); - } - else - { - for(var i = 0; i < bgPage.feedInfo[feedID].items.length;i++) - { - itemID = MD5(bgPage.feedInfo[feedID].items[i].title + bgPage.feedInfo[feedID].items[i].date); + } else { + for (var i = 0; i < bgPage.feedInfo[feedID].items.length; i++) { + itemID = MD5(bgPage.feedInfo[feedID].items[i].title + bgPage.feedInfo[feedID].items[i].date); bgPage.unreadInfo[feedID].readitems[itemID] = expireMs; container = document.getElementById("item_" + feedID + "_" + itemID); - - if(container != null) - { + + if (container != null) { container.className = container.className + className; } } } - + localStorage["unreadinfo"] = JSON.stringify(bgPage.unreadInfo); - + UpdateFeedUnread(feedID); UpdateReadAllIcon(); bgPage.UpdateUnreadBadge(); } -function MarkItemRead(itemID) -{ - var feedID = feeds[selectedFeedKey].id; +function MarkItemRead(itemID) { + var feedID = feeds[selectedFeedKey].id; var className = (options.readitemdisplay == 0) ? " feedPreviewContainerRead" : " feedPreviewContainerRead feedPreviewContainerCondensed"; var expireMs = new Date().getTime() + 5184000000; // 2 months; - - if(bgPage.unreadInfo[feedID].readitems[itemID] == null) - { + + if (bgPage.unreadInfo[feedID].readitems[itemID] == null) { document.getElementById("item_" + feedID + "_" + itemID).className += className; - + bgPage.unreadInfo[feedID].unreadtotal--; bgPage.unreadInfo[feedID].readitems[itemID] = expireMs; - + localStorage["unreadinfo"] = JSON.stringify(bgPage.unreadInfo); - + UpdateFeedUnread(feedID); UpdateReadAllIcon(); - bgPage.UpdateUnreadBadge(); + bgPage.UpdateUnreadBadge(); } } -function MarkItemReadLater(feedID, itemIndex) -{ +function MarkItemReadLater(feedID, itemIndex) { var itemID = MD5(bgPage.feedInfo[feedID].items[itemIndex].title + bgPage.feedInfo[feedID].items[itemIndex].date); - + bgPage.feedInfo[bgPage.readLaterFeedID].items.push(bgPage.feedInfo[feedID].items[itemIndex]); - bgPage.unreadInfo[bgPage.readLaterFeedID].unreadtotal ++; + bgPage.unreadInfo[bgPage.readLaterFeedID].unreadtotal++; - MarkItemRead(itemID); + MarkItemRead(itemID); UpdateFeedUnread(bgPage.readLaterFeedID); - + localStorage["readlater"] = JSON.stringify(bgPage.feedInfo[bgPage.readLaterFeedID]); } -function UnMarkItemReadLater(itemIndex) -{ - bgPage.unreadInfo[bgPage.readLaterFeedID].unreadtotal --; - bgPage.feedInfo[bgPage.readLaterFeedID].items.splice(itemIndex, 1); +function UnMarkItemReadLater(itemIndex) { + bgPage.unreadInfo[bgPage.readLaterFeedID].unreadtotal--; + bgPage.feedInfo[bgPage.readLaterFeedID].items.splice(itemIndex, 1); bgPage.UpdateUnreadBadge(); - + localStorage["readlater"] = JSON.stringify(bgPage.feedInfo[bgPage.readLaterFeedID]); - + UpdateFeedUnread(bgPage.readLaterFeedID); SelectFeed(0); } -function SelectFeed(key) -{ +function SelectFeed(key) { localStorage["lastSelectedFeedID"] = bgPage.feeds[key].id; - + document.getElementById("feedPreviewScroller").scrollTop = 0; - - clearTimeout(feedReadToID); - if(selectedFeedKey != null) - { + clearTimeout(feedReadToID); + + if (selectedFeedKey != null) { document.getElementById("feedTitle" + feeds[selectedFeedKey].id).setAttribute("class", ""); } - + document.getElementById("feedTitle" + feeds[key].id).setAttribute("class", "selectedFeed"); - - selectedFeedKey = key; - + + selectedFeedKey = key; + UpdateTitle(); + // clear the slate var el = document.getElementById("feedPreview"); - - while ( el.childNodes.length >= 1 ) - { - el.removeChild( el.firstChild ); - } - + + while (el.childNodes.length >= 1) { + el.removeChild(el.firstChild); + } + // clear the slate document.getElementById("markFeedRead").style.display = "none"; document.getElementById("header").className = ""; document.getElementById("feedError").style.display = "none"; document.getElementById("refresh").style.display = (feeds[selectedFeedKey].id != bgPage.readLaterFeedID) ? "" : "none"; document.getElementById("noItems").style.display = "none"; - + // feed isn't ready yet - if(bgPage.feedInfo[feeds[key].id] == null || bgPage.feedInfo[feeds[key].id].loading) - { + if (bgPage.feedInfo[feeds[key].id] == null || bgPage.feedInfo[feeds[key].id].loading) { document.getElementById("headerMessage").innerText = "Loading Feed ..."; document.getElementById("header").className = "loading"; document.getElementById("refresh").style.display = "none"; - + // must be a new feed with no content yet - if(bgPage.feedInfo[feeds[key].id] == null && !bgPage.checkingForUnread) - { - bgPage.CheckForUnreadStart(key); + if (bgPage.feedInfo[feeds[key].id] == null && !bgPage.checkingForUnread) { + bgPage.CheckForUnreadStart(key); } - + return; - } - + } + // feed loaded, but had an error - if(bgPage.feedInfo[feeds[key].id].error != "") - { + if (bgPage.feedInfo[feeds[key].id].error != "") { ShowFeedError(bgPage.feedInfo[feeds[key].id].error); return; - } - - document.getElementById("noItems").style.display = (bgPage.feedInfo[feeds[key].id].items.length == 0) ? "" : "none"; - - RenderFeed(); - UpdateReadAllIcon(); - FixFeedList(); // in case header wraps - - if(options.markreadafter > 0 && key != 0) - { - feedReadToID = setTimeout(function(){MarkFeedRead(feeds[key].id)}, options.markreadafter * 1000); - } - + } + + document.getElementById("noItems").style.display = (bgPage.feedInfo[feeds[key].id].items.length == 0) ? "" : "none"; + + RenderFeed(); + UpdateReadAllIcon(); + FixFeedList(); // in case header wraps + + if (options.markreadafter > 0 && key != 0) { + feedReadToID = setTimeout(function () { + MarkFeedRead(feeds[key].id) + }, options.markreadafter * 1000); + } + } -function RenderFeed() -{ +function RenderFeed() { var masterSummary = null; var masterTitle = null; var itemID = null; @@ -416,253 +384,249 @@ function RenderFeed() var link = null; var summaryLinks = null; var summaryImages = null; - var summaryObjects = null; + var summaryObjects = null; var item = null; - var feedID = feeds[selectedFeedKey].id; + var feedID = feeds[selectedFeedKey].id; var currentTr = null; var columnCount = 0; var colWidth = null; var feedTd = null; var href = ""; - - document.getElementById("headerMessage").innerText = bgPage.feedInfo[feedID].title; - - if(bgPage.feedInfo[feedID].description != "" && options.showdescriptions) - { + + document.getElementById("headerMessage").innerText = bgPage.feedInfo[feedID].title; + + if (bgPage.feedInfo[feedID].description != "" && options.showdescriptions) { document.getElementById("headerMessage").innerHTML += " - " + bgPage.feedInfo[feedID].description + ""; - } - - switch(options.columns) - { - case "1": colWidth = "100%";break; - case "2": colWidth = "50%";break; - case "3": colWidth = "33%";break; - case "4": colWidth = "25%";break; } - - for(var i=0;i < bgPage.feedInfo[feedID].items.length && i< feeds[selectedFeedKey].maxitems;i++) - { - item = bgPage.feedInfo[feedID].items[i]; + + switch (options.columns) { + case "1": + colWidth = "100%"; + break; + case "2": + colWidth = "50%"; + break; + case "3": + colWidth = "33%"; + break; + case "4": + colWidth = "25%"; + break; + } + var feedBaseUrl = (new URL(feeds[selectedFeedKey].url)).origin; + + for (var i = 0; i < bgPage.feedInfo[feedID].items.length && i < feeds[selectedFeedKey].maxitems; i++) { + item = bgPage.feedInfo[feedID].items[i]; itemID = MD5(item.title + item.date); - + feedMarkRead = null; feedMarkRead = document.createElement("img"); feedMarkRead.setAttribute("src", "x_blue.gif"); //feedMarkRead.setAttribute("id", 'markItemRead' + itemID); - - if(feedID == bgPage.readLaterFeedID) - { - $(feedMarkRead).click({i:i},function(event){UnMarkItemReadLater(event.data.i);return false;}); + + if (feedID == bgPage.readLaterFeedID) { + $(feedMarkRead).click({i: i}, function (event) { + UnMarkItemReadLater(event.data.i); + return false; + }); //ClickBuilder(feedMarkRead, "UnMarkItemReadLater(" + i + ");"); - } - else - { - $(feedMarkRead).click({itemID: itemID}, function(event) - { - MarkItemRead(event.data.itemID); - return false; - }); + } else { + $(feedMarkRead).click({itemID: itemID}, function (event) { + MarkItemRead(event.data.itemID); + return false; + }); //ClickBuilder(feedMarkRead, "MarkItemRead(\"" + itemID + "\");"); } - + feedMarkRead.title = "Mark read"; - feedMarkRead.setAttribute("class", "feedPreviewMarkRead"); - + feedMarkRead.setAttribute("class", "feedPreviewMarkRead"); + feedLink = document.createElement("a"); - feedLink.setAttribute("href", item.url); - feedLink.innerHTML = (i+1) + ".  " + item.title; - - $(feedLink).click({url:item.url}, function(event){LinkProxy(event.data.url);return false;}); + href = item.url; + href.startsWith("/") && !href.startsWith("//") && (href = feedBaseUrl + href); + feedLink.setAttribute("href", href); + feedLink.innerText = (i + 1) + ". " + item.title; + + $(feedLink).click({url: href}, function (event) { + LinkProxy(event.data.url); + return false; + }); //ClickBuilder(feedLink, "LinkProxy('" + item.url + "');return false;"); - - if(feedID == bgPage.readLaterFeedID) - { - if(options.readlaterremovewhenviewed) - { - $(feedLink).click({i:i}, function(event){UnMarkItemReadLater(event.data.i);return false;}); + + if (feedID == bgPage.readLaterFeedID) { + if (options.readlaterremovewhenviewed) { + $(feedLink).click({i: i}, function (event) { + UnMarkItemReadLater(event.data.i); + return false; + }); //ClickBuilder(feedLink, "UnMarkItemReadLater(" + i + ");"); } - } - else - { - $(feedLink).click({feedID:feedID, itemID:itemID},function(event){MarkItemRead(event.data.itemID);if(options.markreadonclick){MarkFeedRead(event.data.feedID);} return false;}); + } else { + $(feedLink).click({feedID: feedID, itemID: itemID}, function (event) { + MarkItemRead(event.data.itemID); + if (options.markreadonclick) { + MarkFeedRead(event.data.feedID); + } + return false; + }); //ClickBuilder(feedLink, "MarkItemRead(\"" + itemID + "\");if(options.markreadonclick){MarkFeedRead(" + feedID + ");}"); } - + feedTitle = document.createElement("h2"); - feedTitle.setAttribute("class", "feedPreviewTitle"); + feedTitle.setAttribute("class", "feedPreviewTitle"); feedTitle.appendChild(feedMarkRead); - - if(options.readlaterenabled && feedID != bgPage.readLaterFeedID) - { + + if (options.readlaterenabled && feedID != bgPage.readLaterFeedID) { feedReadLater = document.createElement("img"); feedReadLater.setAttribute("src", "star.gif"); feedReadLater.setAttribute("class", "feedPreviewReadLater"); - feedReadLater.setAttribute("title", "Read later"); - $(feedReadLater).click({feedID: feedID, i:i}, function(event){MarkItemReadLater(event.data.feedID, event.data.i);return false;}); + feedReadLater.setAttribute("title", "Read later"); + $(feedReadLater).click({feedID: feedID, i: i}, function (event) { + MarkItemReadLater(event.data.feedID, event.data.i); + return false; + }); //ClickBuilder(feedReadLater, "MarkItemReadLater(\"" + feedID + "\", " + i + ");"); feedTitle.appendChild(feedReadLater); - } - + } + feedTitle.appendChild(feedLink); - + feedPublished = document.createElement("div"); feedPublished.setAttribute("class", "feedPreviewDate"); - feedPublished.appendChild(document.createTextNode(bgPage.GetFormattedDate(item.date))); + feedPublished.appendChild(document.createTextNode(bgPage.GetFormattedDate(item.date))); feedAuthor = document.createElement("div"); feedAuthor.setAttribute("class", "feedPreviewAuthor"); - feedAuthor.innerText = item.author; - + feedAuthor.innerText = item.author; + feedSummary = document.createElement("div"); feedSummary.setAttribute("class", "feedPreviewSummary"); - feedSummary.innerHTML = item.content; - + feedSummary.innerHTML = item.content.replace(/style/g, 'style').replace(/width/g, 'width'); + feedContainer = document.createElement("div"); - feedContainer.setAttribute("id", "item_" + feedID + "_" + itemID); - - - if(bgPage.unreadInfo[feeds[selectedFeedKey].id] != null && bgPage.unreadInfo[feeds[selectedFeedKey].id].readitems != null && bgPage.unreadInfo[feeds[selectedFeedKey].id].readitems[itemID] != null) - { - if(options.readitemdisplay == 0) - { + feedContainer.setAttribute("id", "item_" + feedID + "_" + itemID); + + + if (bgPage.unreadInfo[feeds[selectedFeedKey].id] != null && bgPage.unreadInfo[feeds[selectedFeedKey].id].readitems != null && bgPage.unreadInfo[feeds[selectedFeedKey].id].readitems[itemID] != null) { + if (options.readitemdisplay == 0) { feedContainer.setAttribute("class", "feedPreviewContainer feedPreviewContainerRead"); - } - else - { + } else { feedContainer.setAttribute("class", "feedPreviewContainer feedPreviewContainerRead feedPreviewContainerCondensed"); } - } - else - { + } else { feedContainer.setAttribute("class", "feedPreviewContainer"); } - + // make all summary links open a new tab - summaryLinks = feedSummary.getElementsByTagName("a"); - for(var l = 0; l < summaryLinks.length; l++) - { - href = summaryLinks[l].getAttribute("href"); - - $(summaryLinks[l]).click({href:href},function(event){LinkProxy(event.data.href);return false;}); + summaryLinks = feedSummary.getElementsByTagName("a"); + for (var l = 0; l < summaryLinks.length; l++) { + href = summaryLinks[l].getAttribute("href"); + + $(summaryLinks[l]).click({href: href}, function (event) { + LinkProxy(event.data.href); + return false; + }); //ClickBuilder(summaryLinks[l], "LinkProxy('" + href + "');return false;"); - - if(feedID == bgPage.readLaterFeedID) - { - if(options.readlaterremovewhenviewed) - { - $(summaryLinks[l]).click({i:i},function(event){UnMarkItemReadLater(event.data.i);return false;}); + + if (feedID == bgPage.readLaterFeedID) { + if (options.readlaterremovewhenviewed) { + $(summaryLinks[l]).click({i: i}, function (event) { + UnMarkItemReadLater(event.data.i); + return false; + }); //ClickBuilder(summaryLinks[l], "UnMarkItemReadLater(" + i + ");"); } - } - else - { - $(summaryLinks[l]).click({itemID:itemID},function(event){MarkItemRead(event.data.itemID);return false;}); + } else { + $(summaryLinks[l]).click({itemID: itemID}, function (event) { + MarkItemRead(event.data.itemID); + return false; + }); //ClickBuilder(summaryLinks[l], "MarkItemRead(\"" + itemID + "\");"); } } - + // show snug images, or nuke them - summaryImages = feedSummary.getElementsByTagName("img"); - for(var q = summaryImages.length - 1; q >= 0; q--) - { - if(options.showfeedimages) - { + summaryImages = feedSummary.getElementsByTagName("img"); + for (var q = summaryImages.length - 1; q >= 0; q--) { + if (options.showfeedimages) { summaryImages[q].style.maxWidth = "95%"; summaryImages[q].style.width = ""; summaryImages[q].style.height = ""; summaryImages[q].removeAttribute("width"); - summaryImages[q].removeAttribute("height"); - } - else - { - summaryImages[q].parentNode.removeChild(summaryImages[q]); + summaryImages[q].removeAttribute("height"); + } else { + summaryImages[q].parentNode.removeChild(summaryImages[q]); } } - + // show snug objects, or nuke them - summaryObjects = feedSummary.getElementsByTagName("object"); - for(var o = summaryObjects.length - 1; o >= 0; o--) - { - if(!options.showfeedobjects) - { - summaryObjects[o].parentNode.removeChild(summaryObjects[o]); - } - else - { + summaryObjects = feedSummary.getElementsByTagName("object"); + for (var o = summaryObjects.length - 1; o >= 0; o--) { + if (!options.showfeedobjects) { + summaryObjects[o].parentNode.removeChild(summaryObjects[o]); + } else { summaryObjects[o].style.maxWidth = "95%"; summaryObjects[o].style.width = ""; summaryObjects[o].style.height = ""; summaryObjects[o].removeAttribute("width"); - summaryObjects[o].removeAttribute("height"); + summaryObjects[o].removeAttribute("height"); } } - + // show snug objects, or nuke them - summaryObjects = feedSummary.getElementsByTagName("embed"); - for(var o = summaryObjects.length - 1; o >= 0; o--) - { - if(!options.showfeedobjects) - { - summaryObjects[o].parentNode.removeChild(summaryObjects[o]); - } - else - { + summaryObjects = feedSummary.getElementsByTagName("embed"); + for (var o = summaryObjects.length - 1; o >= 0; o--) { + if (!options.showfeedobjects) { + summaryObjects[o].parentNode.removeChild(summaryObjects[o]); + } else { summaryObjects[o].style.maxWidth = "95%"; summaryObjects[o].style.width = ""; summaryObjects[o].style.height = ""; summaryObjects[o].removeAttribute("width"); - summaryObjects[o].removeAttribute("height"); + summaryObjects[o].removeAttribute("height"); } } - - + + // show snug iframes, or nuke them - summaryObjects = feedSummary.getElementsByTagName("iframe"); - for(var o = summaryObjects.length - 1; o >= 0; o--) - { - if(!options.showfeediframes) - { - summaryObjects[o].parentNode.removeChild(summaryObjects[o]); - } - else - { + summaryObjects = feedSummary.getElementsByTagName("iframe"); + for (var o = summaryObjects.length - 1; o >= 0; o--) { + if (!options.showfeediframes) { + summaryObjects[o].parentNode.removeChild(summaryObjects[o]); + } else { summaryObjects[o].style.maxWidth = "95%"; summaryObjects[o].style.width = ""; summaryObjects[o].style.height = ""; summaryObjects[o].removeAttribute("width"); - summaryObjects[o].removeAttribute("height"); + summaryObjects[o].removeAttribute("height"); } - } - - if(columnCount == options.columns) - { + } + + if (columnCount == options.columns) { columnCount = 0; } - - if(columnCount == 0) - { + + if (columnCount == 0) { currentTr = document.createElement("tr"); document.getElementById("feedPreview").appendChild(currentTr); } - - + + feedContainer.appendChild(feedTitle); feedContainer.appendChild(feedSummary); - feedContainer.appendChild(feedPublished); - feedContainer.appendChild(feedAuthor); - + feedContainer.appendChild(feedPublished); + feedContainer.appendChild(feedAuthor); + feedTd = document.createElement("td"); feedTd.style.width = colWidth; feedTd.appendChild(feedContainer); - + currentTr.appendChild(feedTd); - columnCount++; - } + columnCount++; + } } -function ShowFeedError(message) -{ +function ShowFeedError(message) { document.getElementById("feedError").style.display = ""; document.getElementById("feedErrorMessage").innerText = message; document.getElementById("headerMessage").innerText = "Feed Problems"; @@ -670,36 +634,34 @@ function ShowFeedError(message) // since we have multiple click events, this should allow us // to build them easily -function ClickBuilder(el, newFunction) -{ +function ClickBuilder(el, newFunction) { var obj = $(el); - var clickEvents = obj.data("clickEvents"); - - if(clickEvents == undefined) - { + var clickEvents = obj.data("clickEvents"); + + if (clickEvents == undefined) { clickEvents = ""; - } - - clickEvents = clickEvents + newFunction; - - if(/return false/i.test(clickEvents)) - { - clickEvents = clickEvents.replace(/return false;/i, "") + "return false;"; - } - + } + + clickEvents = clickEvents + newFunction; + + if (/return false/i.test(clickEvents)) { + clickEvents = clickEvents.replace(/return false;/i, "") + "return false;"; + } + // hack obj - .data('clickEvents', clickEvents) - .unbind('click') - .bind('click', function(){$.globalEval($(this).data('clickEvents'));}); - + .data('clickEvents', clickEvents) + .unbind('click') + .bind('click', function () { + $.globalEval($(this).data('clickEvents')); + }); + return; } // central function to control creation of tabs so we can put them in the background -function LinkProxy(uRL) -{ - chrome.tabs.create({url:uRL, selected: !bgPage.options.loadlinksinbackground}); +function LinkProxy(uRL) { + chrome.tabs.create({url: uRL, selected: !bgPage.options.loadlinksinbackground}); }