// ==UserScript== // @author DemianGod - demiangod@gmail.com // @name Google Reader New Style Minimalistic by DemianGod v4.3 // @namespace http://userscripts.org/scripts/show/30242 // @description Removes all the junk from New Google+ Reader and just gives you the search and collapsable subscriptions + favicons. // @include http*://*.google.com*/reader/* // ==/UserScript== // Google Reader New Style Minimalistic By DemianGod v4.3 // DemianGod http://userscripts.org/scripts/show/30242 const EXPORT_URL = '/reader/subscriptions/export'; const ICON_XPATH = "/html/body/div[6]/div/div[2]/div/div[5]/div[4]//div[starts-with(@class,'icon sub-icon')]"; const ICON_XPATH_PREFIX = '/opml/body//outline[@text="'; const ICON_OPML_XPATH_PREFIX = '/opml/body//outline'; const YQL_BASE_URL = 'http://query.yahooapis.com/v1/public/yql?q='; const YQL_GET_HTML = 'select%20*%20from%20html%20where'; // URI-encoded const YQL_HTML_QUERY = YQL_BASE_URL+YQL_GET_HTML; const FAVICON_XPATH = "/html/head/link[@rel='icon'] | /html/head/link[@rel='ICON'] | /html/head/link[@rel='shortcut icon'] | /html/head/link[@rel='SHORTCUT ICON']"; const URL_PATTERN = "^http://"; // "http://" at the start of the string const CHANGE_MSG_XPATH = "/html/body/div[2]/div/div[@id='message-area']"; const NAV_BAR_XPATH = "/html/body/div[6]/div"; const FEED_ADD_MSG_XPATH = "//div[@id='quick-add-success']"; // The OPML file is the file you get when you try to export your Google Reader subscriptions. // It contains (amongst other things) the mapping between each site's URL and feed URL. function fetchOPML(url, callback) { var xhr = new XMLHttpRequest(); xhr.open('get', url); xhr.onload = function(){callback(xhr.responseXML)}; xhr.send(null); } function drawFavicon(iconNode, imgNode) { var parent = iconNode.parentNode; parent.replaceChild(imgNode, iconNode); } function replaceAllFeedIcons(opml) { function replaceIcons(iconNodes) { for (var i=0; i<iconNodes.snapshotLength; i++) { /* I need to match the icon node with its XML element in the OPML file. * I'm going to match based on the title. */ var currIcon = iconNodes.snapshotItem(i); var feedTitle = currIcon.nextSibling.firstChild.textContent; var srcURLNode, srcURL; if (feedTitle.indexOf("\"") == -1) // common case - title doesn't contain double quotes { srcURLNode = opml.evaluate(ICON_XPATH_PREFIX+feedTitle+'"]/@htmlUrl', opml, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (srcURLNode == null) // shouldn't ever (or at least rarely) happen { GM_log("Unable to get the srcURLNode for feed "+feedTitle); continue; } srcURL = srcURLNode.textContent; } else // going to be expensive { var iconOPMLNodes = opml.evaluate(ICON_OPML_XPATH_PREFIX, opml, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); /* Unfortunately, XPath 1.0 doesn't allow for escaping single quotes (') and double quotes ("). * Therefore, I'm treating the "text" attribute as a string, and doing the comparison this way. * XPath 2.0, whenever that gets widely supported, should render this method obsolete. */ for (var j=0; j<iconOPMLNodes.snapshotLength; j++) { currNode = iconOPMLNodes.snapshotItem(j); if (currNode.getAttribute("text") == feedTitle) { srcURL = currNode.getAttribute("htmlUrl"); break; } } if (j == iconOPMLNodes.snapshotLength) { GM_log("Unable to get the srcURLNode for feed "+feedTitle); continue; } } srcURL = "http://"+srcURL.split("/", 3)[2]; // get the root URL /* create the img node used to display our icon */ var imgNode = document.createElement("img"); imgNode.style.borderWidth = "0px"; imgNode.style.height = "16px"; imgNode.style.width = "16px"; imgNode.style.opacity = "1.0"; imgNode.style.marginTop = "2px"; /* By setting the class attribute to be the same, we can ensure that the same CSS styles get applied. * You can remove the line to see what it looks like without those styles */ imgNode.className = currIcon.className; // remove the default feed icon imgNode.style.backgroundImage = "none"; imgNode.style.visibility = "hidden"; imgNode.setAttribute("alreadysearchedpage", "false"); var defaultFaviconURL; // contains our first guess at the correct URL var faviconURL = GM_getValue(srcURL); if (faviconURL == undefined || faviconURL == "") // no user-specified value defaultFaviconURL = srcURL + "/favicon.ico"; else defaultFaviconURL = faviconURL; imgNode.src = defaultFaviconURL; // if the image loads correctly, then the favicon is in the default location imgNode.addEventListener("load", (function(srcURL, defaultFaviconURL) { return function() { this.style.visibility = "visible"; GM_setValue(srcURL, defaultFaviconURL); }; })(srcURL, defaultFaviconURL), true); // otherwise, its in a non-default location and we have to hunt for it imgNode.addEventListener("error", (function(imgNode, srcURL, currIcon) { return function() { if (this.getAttribute("alreadysearchedpage") == "true") return; /* make use of the YQL service from Yahoo! which will: * 1) convert HTML into well-formed XML * 2) lets us retrieve selective parts of a webpage, based on an XPath query - * the benefit is that we have to do less client-side processing * * Here we are only requesting the part of the webpage which specifies the favicon location */ var queryURL = YQL_HTML_QUERY+encodeURIComponent(' url="'+srcURL+'"'+' and xpath="'+FAVICON_XPATH+'"'); GM_xmlhttpRequest({ method: "GET", url: queryURL, onload: function(response) { if (response.status == '200') // response is OK { // remove XML opening declaration before passing to constructor (apparently required) var urlResultDoc = new XML(response.responseText.replace(/^<\?xml [^>]*>\s*/,'')); var urlResult = urlResultDoc.results; var url, faviconURL; if (urlResult.link.length() == 0) // no favicons :( { /* therefore, go back to using the generic icon provided by Google Reader, * so that the icon isn't just blank/broken */ drawFavicon(imgNode, currIcon); /* create the entry, so the user can manually fill it in (if desired) via about:config * (e.g., with the URL of some other site's favicon) */ GM_setValue(srcURL, ""); return; } else if (urlResult.link.length() == 1) url = urlResult.link.@href; else if (urlResult.link.length() == 2) /* this should rarely happen, but some websites will specify 2 link tags: * one with rel="shortcut icon" and one with rel="icon". I've arbitrarily * chosen to select the former. */ url = urlResult.link.(@rel.toLowerCase() == "shortcut icon").@href; if (url.search(new RegExp(URL_PATTERN)) != -1) // absolute path faviconURL = url; else // relative path { /* originally I thought the following was sufficient to distinguish between relative and * absolute, but then at sites like www.hdnumerique.com, I saw they specified their * favicon url as "imgs/favicon.ico" :) */ if (url.charAt(0) == '/') faviconURL = srcURL+url; else faviconURL = srcURL+'/'+url; } imgNode.setAttribute("alreadysearchedpage", "true"); imgNode.src = faviconURL; drawFavicon(currIcon, imgNode); imgNode.style.visibility = "visible"; GM_setValue(srcURL, faviconURL.toString()); } else GM_log("YQL query for "+srcURL+" returned with error " + response.status); } }); } })(imgNode, srcURL, currIcon), true); drawFavicon(currIcon, imgNode); } } var regIconNodes = document.evaluate(ICON_XPATH, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); replaceIcons(regIconNodes); } // here we draw the favicons when our script first loads fetchOPML(EXPORT_URL, replaceAllFeedIcons); /* But there are 3 times when we will have to redraw the favicons: * * 1) When the user edits feeds (e.g., re-order, rename) * 2) When the user navigates to the Settings and back * 3) When the user adds a feed using the "Add a subscription" button * * This is because these operations don't reload the page (I think Google is using AJAX for them). * Detection of these events is fairly crude, but Google doesn't provide notifications for them. */ // Editing ends when the "Saved changes to [feed-name]" message appears var changeMsg = document.evaluate(CHANGE_MSG_XPATH, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; changeMsg.addEventListener("DOMNodeInserted", function (event) { if (this.textContent.search("Saved changes") == 0 || this.textContent.search("You have") == 0) /* * I don't actually need to fetch the opml file here, but the replaceAllFeedIcons() function * makes calls to GM_getValue()/GM_setValue(), which cannot be made in the context of the * webpage (a security error occurs when this happens). Thus, I have to call the function * in the context of a GreaseMonkey XmlHttpRequest. */ fetchOPML(EXPORT_URL, replaceAllFeedIcons); }, true); // The user navigated back from the Settings page when the class attribute of the // left-hand side navigation bar is modified in a certain way var navBar = document.evaluate(NAV_BAR_XPATH, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; var unhide = false; navBar.addEventListener("DOMAttrModified", function(event) { // if (event.attrName == "class") // console.log("attrName = "+event.attrName+"\nprevValue = "+event.prevValue+"\nnewValue = "+event.newValue); // we're coming back from the Settings page if (event.attrName == "class" && event.prevValue == "hidden" && event.newValue == "") unhide = true; // console.log("unhide = "+unhide+" attrName = "+event.attrName + " newValue = "+event.newValue); /* I only re-draw the first time the class attribute is changed after coming back from the * Settings page. I used the flag because this type of change to the class * attribute occurs often. For example, it occurs every time you click on a feed/subscription * in the left panel. */ if (unhide && event.attrName == "class" && event.newValue == "link tree-link-selected") { fetchOPML(EXPORT_URL, replaceAllFeedIcons); unhide = false; } }, true); // A new feed is added using the "Add a subscription" button when the class attribute // of the "success" message becomes visible var feedAddMsg = document.evaluate(FEED_ADD_MSG_XPATH, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; feedAddMsg.addEventListener("DOMAttrModified", function(event) { if (event.attrName == "class" && event.prevValue == "hidden" && event.newValue == "") { /* * I don't actually need to fetch the opml file here, but the replaceAllFeedIcons() function * makes calls to GM_getValue()/GM_setValue(), which cannot be made in the context of the * webpage (a security error occurs when this happens). Thus, I have to call the function * in the context of a GreaseMonkey XmlHttpRequest. */ fetchOPML(EXPORT_URL, replaceAllFeedIcons); } }, true); //--------------------------------------------------------------- (function() { var ids = ["logo-container","gbg","gbx3","gbx4","gbzc","gbz","gbu","gbq1","gbzw","gbbw","logo-section","sections-header","reading-list-selector","lhn-recommendations","sub-tree-header","lhn-add-subscription-section","lhn-selectors","home-section","viewer-refresh","viewer-view-options","mark-all-as-read-split-button","stream-prefs-menu","chrome-view-links","settings-button-container"]; function toggle_gr () { var length = ids.length; var is_visible = document.getElementById(ids[0]).style.display != "none"; for (var i=0; i<length; i++){ if(document.getElementById(ids[i]) != null) document.getElementById(ids[i]).style.display = is_visible?"none":"block"; } GM_addStyle(".gbh { display:none !important; }"); //Hide dividing line if(is_visible){ document.getElementById('main').style.fontSize = '8pt'; document.getElementById('sub-tree').style.fontSize = '8pt'; var overrideCSS = " \ #search { padding:2px !important ; position:fixed; z-index:2 !important; } \ #gbq2 { left:-50px !important; top:11px !important; width:0px !important; position:fixed; z-index:3 !important; } \ #gbqfbw { left:500px !important; display:block !important; } \ #gbqff { width:500px !important; } \ #settings-button { top:-3px !important; } \ #viewer-header-container { height:35px !important; } \ #viewer-top-controls-container { top:15px !important; } \ #sections-header { height:35px !important; } \ #overview-section-header { width:0px !important; height:0px !important; position:fixed; } \ #gb { height:0px !important; } \ #gbx1 { display:none !important; } \ #gbq { height:0px !important; } \ #gbqf { left:100px !important; top:-30px !important; } \ #lhn-subscriptions-minimize { left:0px !important; top:0px !important; } \ #sub-tree-container { top:10px !important; } \ #entries { padding:0ex !important; } \ #entries.list .collapsed { height: 4.0ex !important; } \ #entries.list .collapsed .entry-source-title, #entries.list .collapsed .entry-title, #entries.list .collapsed .entry-date { line-height: 4.0ex !important;} \ #entries.list .entry .entry-secondary .snippet { color: #333 } \ #entries.list .entry.read .entry-secondary .snippet { color: inherit } \ #entries.list .entry .entry-main .entry-source-title \ {color:#333 !important} \ #entries.list .entry.read .entry-main .entry-source-title \ {color: #666 !important} \ #title-and-status-holder { padding:0 0 0 0.5em !important; } \ #sub-tree-header \ { padding-left: 15px !important; } \ .folder .folder .folder-toggle { margin-left:13px !important } \ .folder .sub-icon, .folder .folder>a>.icon { margin-left:27px !important } \ .folder .folder>ul .icon { margin-left:34px !important } \ .folder .folder .name-text { max-width:160px; !important } \ #recommendations-tree .sub-icon {background-position: -65px 0 !important;} \ .scroll-tree .icon, .scroll-tree .favicon {height: 15px !important; width: 15px !important;} \ .scroll-tree .folder-icon {background-position: -48px 0 !important;} \ .scroll-tree li a .name {color: #000000 !important;} \ .scroll-tree .tag-icon {background-position: -33px -32px !important;} \ "; GM_addStyle(overrideCSS); } else { //--- } } function GRT_key(event) { element = event.target; elementName = element.nodeName.toLowerCase(); if (elementName == "input") { typing = (element.type == "text" || element.type == "password"); } else { typing = (elementName == "textarea"); } if (typing) return true; if (String.fromCharCode(event.which)=="W" && !event.ctrlKey && !event.metaKey) { toggle_gr(); try { event.preventDefault(); } catch (e) { } return false; } return true; } document.addEventListener("keydown", GRT_key, false); toggle_gr(); try { var accountname = document.getElementById('gbmpn'); document.title = document.title + " | " + accountname.innerHTML + " |"; } catch(err) { } })();
Mozilla add on,User script,Grease Monkey Script, greasemonkey userscripts, updater userscripts mafia wars userscripts mafia wars autoplayer userscripts mafia wars wall userscripts scripts userscripts travian greasemonkey greasemonkey download greasemonkey facebook greasemonkey tutorial greasemonkey youtube greasemonkey travian greasemonkey chrome greasemonkey mafia wars greasemonkey mafia wars autoplayer
Friday, March 2, 2012
Google Reader New Style Minimalistic by DemianGod v4.3
Subscribe to:
Post Comments (Atom)
0 comments:
Post a Comment