阅读:2594回复:1
有无firefox和google reader整合的扩展~类似google bookmark
官方扩展中搜索了一下没有
|
|
1楼#
发布于:2006-11-18 23:00
我是用gm的userjs
那个js是google reader和gmail整合在一起 ////////////////////////////////////////////////// // Gmail and Google Reader Integrator v2.0 ////////////////////////////////////////////////// //Author: // Winston Teo, inspired by Mihai@http://persistent.info/archives/2006/10/13/google-reader-redux //Description: // This script integrates Google Reader into Gmail, built for Greasemonkey. //Requirements: // Firefox Browser // Greasmonkey Extension //Features: // 1. Spilt-window view of Gmail and Reader on a single page // 2. Links to collapse|expand either Gmail or Reader // 3. Integrated Reader uses start-page as specified in Reader's "Settings" // 4. Labels selector // 5. Key 'v' to open Reader links in a new Window // 6. Automatic resize of Gmail and Reader views //Credits: // Mihai @ http://persistent.info/ for having such a good code basis for me to learn and start with. // I used some of his functions as listed: // function newNode, getNode, hasClass, addClass, removeClass, getClassMap, updateFeedsCount //Changelog: // 1. 06-11-2006: Removed Reader on clicking "Contacts" link // 2. 09-11-2006: Resolved variable naming bug; from READER_SHARED_URL to READER_BROADCAST_URL // 3. 10-11-2006: Resolved default start-page issue; able to display "Home" as default start-page ////////////////////////////////////////////////// // ==UserScript== // @name Gmail + Reader Integrator // @namespace http://www.winstonyw.com // @description Integrates Google Reader into Gmail, built for Greasemonkey. // @include http://mail.google.com/* // @include https://mail.google.com/* // @include http://www.google.com/reader/* // ==/UserScript== ////////////////////////////////////////////////// //Setting of DEFAULTS ////////////////////////////////////////////////// //Note: All Links have to end with ?embed // In this way, only the Reader view embedded in Gmail would be affected by the style changes, // and not the Reader view even at its own URL: www.google.com/reader/view const READER_HOME_URL = 'http://www.google.com/reader/view?embed'; const READER_LIST_URL = 'http://www.google.com/reader/view/user/-/state/com.google/reading-list?embed'; const READER_STARRED_URL = 'http://www.google.com/reader/view/user/-/state/com.google/starred?embed'; const READER_BROADCAST_URL = 'http://www.google.com/reader/view/user/-/state/com.google/broadcast?embed'; const READER_LABEL_URL = 'http://www.google.com/reader/view/user/-/label/' ; const UNREAD_COUNT_API = 'http://www.google.com/reader/api/0/unread-count?all=true&output=json&client=gm'; const PREFERENCES_API = 'http://www.google.com/reader/api/0/preference/list?output=json&client=gm'; const LABELS_LIST_API = 'http://www.google.com/reader/api/0/tag/list?output=json&client=gm' //Local Storage for ALL Labels as retrieved from Reader //Note: GM_setValue only allows for integers, strings and booleans var LABELS = []; //Default Heights in Split-Window mode //Change these according to your preference const READER_EMBED_HEIGHT = 400; const GMAIL_SPLIT_HEIGHT = 220; ////////////////////////////////////////////////// //CSS Styles ////////////////////////////////////////////////// //Styles for: // Frame wrapping an iFrame (with Reader in iFrame) // Reader Links on LHS Navigation // Labels Selector const READER_FRAME_STYLES = "#readerFrame {" + " width: 100%;" + " border: 0px;" + " padding: 0px;" + "}" + "#readerEmbed {" + " width: 100%;" + " height: " + READER_EMBED_HEIGHT + "px;" + " border: 0px;" + " padding: 0px;" + "}" + "#readerLabelsSelection {" + " width: 80%;" + " font-family: arial,sans-serif;" + " font-size: 100%;" + "}" + //Selected Link appears UNSELECTED //Usage: hideGmail ".readerEmbed table.cv * {"+ " background: #FFFFFF;" + " font-weight: normal;" + "}"; //Styles for Website (www.google.com/reader...?embed) contained in iFrame //Removes Logo, Navigation, Menu + Displays Main Window const FORMAT_READER_STYLES = "body {" + " background: #FFFFFF;" + "}" + "#nav," + "#logo-container," + "#global-info," + "#viewer-header," + "#home-header," + ".home-header-box," + "#recent-activity," + "#footer {" + " display: none !important;" + "}" + "#main {" + " margin-top: 0;" + "}" + "#chrome {" + " margin-left: 0;" + "}"; //////////////////////////////////////////////////////////////////////////////////////////////////// //Start Execution of Script //////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////// //Detects Google Reader (in iFrame) and updates CSS in Google Reader to hide specific elements ////////////////////////////////////////////////// //Note: Header MUST contain: @include http://www.google.com/reader/* // Then, http://www.google.com/reader/* will include a copy of JS, and only execute this conditional clause. //Note: document.location.search returns ONLY QUERY STRING.. ?embed if (document.location.hostname == 'www.google.com' && document.location.search.indexOf('embed') != -1) { GM_addStyle(FORMAT_READER_STYLES); addKeypressEvents(); } //Method Name: addKeypressEvents() //Description: Adds keypress events to current window. // Currently events include: // 1. Key 'v' opens Reader links in new Window/Tab function addKeypressEvents() { document.addEventListener('keypress', openInNewWindow, false); } //Method Name: openInNewWindow() //Description: Key 'v' opens Reader links in new Window/Tab function openInNewWindow (event) { var code = event.keyCode ? event.keyCode : event.which; var char = String.fromCharCode(code); if (char == 'v') { var currEntry = getNode('current-entry'); if (!currEntry) return; currEntryHREF = document.evaluate( "//div[@id='current-entry']//a[@href]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); window.open (currEntryHREF.snapshotItem(0).href, 'target=newWin'); } } ////////////////////////////////////////////////// //Detects Gmail + Displays Google Reader ////////////////////////////////////////////////// if (document.location.hostname == 'mail.google.com') { GM_addStyle(READER_FRAME_STYLES); addReader(); } //Method Name: addReader() //Description: Adds Reader in iFrame below Inbox // Displays Reader Links (and Feed Counts) in #nav, with Links to specific Labels // Stores Global Variables: Gmail Frame Height + Default Reader start-page in Reader's settings function addReader() { //Only Display in Messages view (Inbox, Starred, Sent etc); //No Display in misc iFrames, or "Compose Mail" view, or "Contacts" view if (!getNode('co') || getNode('msgs') || getNode('cm_compose') || getNode('ctm') || getNode('cnt')) return; //Stores Global Variable setHeight(); setReaderSourceURL(); //Create Links, Feed Counts setNavLink(); updateFeedsCount(); //Create Label Selector setReaderLabelsSelection(); //Create iFrame setReaderFrame(); window.setInterval (updateFeedsCount, 5 * 60 * 1000); } //Method Name: setNavLink() //Description: Displays Reader Links (and Feed Counts), and Show|Hide Gmail Link in #nav. function setNavLink() { var separator = newNode('div'); separator.innerHTML = '<br>'; //Reader Link in #nav var navReaderLink = newNode('div'); navReaderLink.className = 'nl'; navReaderLink.innerHTML = '<span id="navReaderLink" class="lk"><b>Reader <span id="unreadCount"></span></b></span>'; //Insert BEFORE Contacts Link var contNode = getNode('cont'); contNode.parentNode.parentNode.insertBefore(separator, contNode.parentNode); contNode.parentNode.parentNode.insertBefore(navReaderLink, contNode.parentNode); //Event to Show|Hide Reader navReaderLink.addEventListener('click', setReaderVisibility, false); //Gmail Show|Hide Link var GmailToggle = newNode ('div'); GmailToggle.className = 'nl'; GmailToggle.innerHTML = '<span id="GmailToggle" class="lk">Collapse Gmail</span>'; //Insert AFTER Trash Link var navNode = getNode('nds'); navNode.parentNode.insertBefore(GmailToggle, navNode.nextSibling); //Event to Show|Hide Gmail GmailToggle.addEventListener('click', setGmailVisibility, false); //Event to Show Gmail on clicking any link in #nds getNode('nds').addEventListener('click', showGmail, false); } //Method Name: setReaderFrame() //Description: Creates a Frame that contains an iFrame (embedded with Reader) and appends below #co (Inbox, Starred etc) function setReaderFrame() { var readerFrame = newNode('div'); readerFrame.id = 'readerFrame'; readerFrame.className = 'thc'; var readerFrameTop = newNode('div'); readerFrameTop.className = 'tbc'; var readerFrameLinks = newNode('div'); readerFrameLinks.id = 'readerFrameLinks'; readerFrameLinks.className = 'tbcs'; var readerLink = newNode ('div'); readerLink.id = 'readerLink'; readerLink.className = 'l'; readerLink.innerHTML = '<img id="readerLinkImg" src="images/triangle.gif"></img> Google Reader'; readerLink.addEventListener ('click', setReaderVisibility, false); readerFrame.appendChild (readerFrameTop); readerFrameTop.appendChild (readerFrameLinks); readerFrameLinks.appendChild(readerLink); var mailFrame = getNode('co'); var separator = newNode('div'); separator.innerHTML = '<br>'; mailFrame.appendChild(separator); mailFrame.appendChild(readerFrame); } //Method Name: setReaderSourceURL() //Description: Retrieves Reader's settings page through API @ PREFERENCES_API, // and uses value for start-page, as set by User in Google Reader, as start-page for viewReader() method call function setReaderSourceURL() { GM_xmlhttpRequest({ method: 'GET', url: PREFERENCES_API, onload: function(responseDetails) { var data = eval ("(" + responseDetails.responseText + ")"); for (var i = 0 ; i<data.prefs.length ; i++) { var prefsPair = data.prefs[i] if (prefsPair.id.indexOf("start-page") != -1){ //alert(array[i]); if (prefsPair.value.indexOf('home') != -1) { GM_setValue('READER_SOURCE_URL', READER_HOME_URL); } else if (prefsPair.value.indexOf('reading-list') != -1) { GM_setValue('READER_SOURCE_URL', READER_LIST_URL); } else if (prefsPair.value.indexOf('starred') != -1) { GM_setValue('READER_SOURCE_URL', READER_STARRED_URL); } else if (prefsPair.value.indexOf('broadcast') != -1) { GM_setValue('READER_SOURCE_URL', READER_BROADCAST_URL); } else if (prefsPair.value.indexOf('label') != -1) { var LABEL = prefsPair.value.substring(prefsPair.value.lastIndexOf('/')+1, prefsPair.value.length); //alert (LABEL); GM_setValue('READER_SOURCE_URL', READER_LABEL_URL + LABEL + '?embed'); GM_setValue('LABEL', LABEL); } } } } }); } /*********************************** //Obsolete: This method reads the HTML of Reader setting's and is easily breakable. //Refer instead to the same method name which uses API and JSON. function setReaderSourceURL() { GM_xmlhttpRequest({ method: 'GET', url: 'http://www.google.com/reader/settings?nochrome', onload: function(responseDetails) { var data = responseDetails.responseText; var array = data.split('\n'); for (var i=0; i<array.length; i++) { if (array[i].indexOf('selected="selected"') != -1 ) { //alert(array[i]); if (array[i].indexOf('reading-list') != -1 || array[i].indexOf('home') != -1) { GM_setValue('READER_SOURCE_URL', READER_LIST_URL); } else if (array[i].indexOf('starred') != -1) { GM_setValue('READER_SOURCE_URL', READER_STARRED_URL); } else if (array[i].indexOf('broadcast') != -1) { GM_setValue('READER_SOURCE_URL', READER_BROADCAST_URL); } else if (array[i].indexOf('label') != -1) { var LABEL = array[i].substring(array[i].lastIndexOf('/')+1, array[i].lastIndexOf('\"')); //alert (LABEL); GM_setValue('READER_SOURCE_URL', READER_LABEL_URL + LABEL + '?embed'); GM_setValue('LABEL', LABEL); } } } } }); } ***********************************/ ////////////////////////////////////////////////// //Reader Labels Selector ////////////////////////////////////////////////// //Method Name: setReaderLabelsSelection() //Description: Creates Reader Labels Selection from Global Variable LABELS[] in LHS Navigation when Reader is visible function setReaderLabelsSelection() { var selectionNode = newNode('div'); selectionNode.className = 'nl'; var readerLabelsSelection = newNode('select'); readerLabelsSelection.id = "readerLabelsSelection"; //Default: Hidden; Display only when Reader Frame is visible readerLabelsSelection.style.visibility = 'hidden'; selectionNode.appendChild(readerLabelsSelection); var separator = newNode('div'); separator.innerHTML = '<br>'; var navReaderLink = getNode('navReaderLink'); navReaderLink.parentNode.parentNode.insertBefore(separator, navReaderLink.parentNode.nextSibling); navReaderLink.parentNode.parentNode.insertBefore(selectionNode, navReaderLink.parentNode.nextSibling); var opList = newNode('option'); opList.value = READER_LIST_URL; opList.innerHTML = 'All'; if (GM_getValue('READER_SOURCE_URL') == READER_LIST_URL) opList.selected = true; var opStarred = newNode('option'); opStarred.value = READER_STARRED_URL; opStarred.innerHTML = 'Starred'; if (GM_getValue('READER_SOURCE_URL') == READER_STARRED_URL) opStarred.selected = true; var opBroadcast = newNode('option'); opBroadcast.value = READER_BROADCAST_URL; opBroadcast.innerHTML = 'Shared'; if (GM_getValue('READER_SOURCE_URL') == READER_BROADCAST_URL) opBroadcast.selected = true; readerLabelsSelection.appendChild(opList); readerLabelsSelection.appendChild(opStarred); readerLabelsSelection.appendChild(opBroadcast); //Initializes Global Variable, and appends to Selection Node setReaderLabels(); readerLabelsSelection.addEventListener('change', switchView, false); } //Method Name: setReaderLabels() //Description: Retrieves Labels from JSON API and stores as Global Variables function setReaderLabels() { var readerLabelsSelection = getNode("readerLabelsSelection"); if (!readerLabelsSelection) return; GM_xmlhttpRequest({ method: "GET", url: LABELS_LIST_API, onload: function(responseDetails) { var data = eval("(" + responseDetails.responseText + ")"); for (var i = 0 ; i<data.tags.length ; i++) { var tagsPair = data.tags[i] if (tagsPair.id.indexOf("label") != -1){ var LABEL = tagsPair.id.substring(tagsPair.id.lastIndexOf('/')+1, tagsPair.id.length); LABELS.push(LABEL); var opLabel = newNode('option'); opLabel.value = READER_LABEL_URL + LABEL + '?embed'; opLabel.innerHTML = LABEL; if (GM_getValue('READER_SOURCE_URL') == opLabel.value) opLabel.selected = true; readerLabelsSelection.appendChild(opLabel); } } } }); } //Method Name: switchView(event) //Description: Switches Reader view in iFrame according to selection in Reader Labels Selection function switchView(event) { var readerLabelsSelection = getNode('readerLabelsSelection'); for (var i=0; childNode = readerLabelsSelection.childNodes[i]; i++) { if (childNode.selected) { //alert('URL:' childNode.value); GM_setValue('READER_SOURCE_URL', childNode.value); break; } } hideReader(); viewReader(); resizeReaderFrame(); } ////////////////////////////////////////////////// //Gmail Visibility ////////////////////////////////////////////////// //Method Name: setGmailVisibility (event) //Description: Toggles Gmail Frame visibility by calling showGmail() or hideGmail() function setGmailVisibility (event) { var GmailToggle = getNode('GmailToggle'); if (GmailToggle.innerHTML.indexOf('Collapse') != -1) { hideGmail(); } else { showGmail(); } resizeMailFrame(); resizeReaderFrame(); event.stopPropagation(); } //Method Name: showGmail (event) //Description: Shows Gmail Frame function showGmail() { var GmailToggle = getNode('GmailToggle'); //Shows Gmail var mailFrame = getNode('co'); for (var i = mailFrame.firstChild; i.id != 'readerFrame'; i = i.nextSibling) { i.style.display=''; } //Adds "highlight" to Link in #nav removeClass(document.body, 'readerEmbed'); //Change Link in #nav, from "Show" to "Hide" GmailToggle.innerHTML = 'Collapse Gmail'; } //Method Name: hideGmail (event) //Description: Hides Gmail Frame function hideGmail() { var GmailToggle = getNode('GmailToggle'); //Hides Gmail var mailFrame = getNode('co'); for (var i = mailFrame.firstChild; i.id != 'readerFrame'; i = i.nextSibling) { i.style.display='none'; } //Removes "highlight" from Link in #nav addClass(document.body, 'readerEmbed'); //Change Link in #nav, from "Hide" to "Show" GmailToggle.innerHTML = 'Expand Gmail'; } ////////////////////////////////////////////////// //Reader Visibility ////////////////////////////////////////////////// //Method Name: setReaderVisibility(event) //Description: Toggles Reader Frame visibility by calling viewReader() or hideReader() // In addition, visibility of Label links at #nav is dependent on viewReader() or hideReader() method call // Event can be activated by 2 Links, Navigation Link and Reader Frame Link function setReaderVisibility(event) { var readerEmbed = getNode('readerEmbed'); if (readerEmbed == null || (readerEmbed != null && readerEmbed.style.display == 'none')) { swapImg('show' , 'readerLinkImg'); viewReaderLabelsSelection(); viewReader(); } else { swapImg('hide', 'readerLinkImg'); hideReaderLabelsSelection(); hideReader(); } resizeMailFrame(); resizeReaderFrame(); event.stopPropagation(); } //Method Name: viewReader() //Description: Displays Reader Frame, and embeds READER_SOURCE_URL into iFrame function viewReader() { var readerEmbed = getNode('readerEmbed'); if (readerEmbed == null) { readerEmbed = newNode('iframe'); readerEmbed.id = 'readerEmbed'; readerEmbed.name = 'readerEmbed'; readerEmbed.src = GM_getValue('READER_SOURCE_URL'); getNode('readerFrame').appendChild(readerEmbed); } //Not Applicable - Reader is ALWAYS REMOVED in hideReader(), and not hidden through style properties //Reason: Saves on resources + Updated Reader iFrame on every viewReader() method call else { readerEmbed.style.display = ''; } } //Method Name: hideReader() //Description: Hides (Removes) Reader Frame function hideReader() { var readerEmbed = getNode('readerEmbed'); getNode('readerFrame').removeChild(readerEmbed); readerEmbed = null; //Problem with Memory Management? //readerEmbed.style.display="none"; } //Method Name: viewReaderLabelsSelection() //Description: Displays Reader Labels Selection in LHS Navigation when Reader is visible function viewReaderLabelsSelection() { getNode('readerLabelsSelection').style.visibility = 'visible'; } //Method Name: hideReaderLabelsSelection() //Description: Hidess Reader Labels Selection in LHS Navigation when Reader is invisible (removed) function hideReaderLabelsSelection() { getNode('readerLabelsSelection').style.visibility = 'hidden'; } ////////////////////////////////////////////////// //Aesthetic Functions ////////////////////////////////////////////////// //Method Name: minHeight() //Description: Determines Height for Gmail Frame function setHeight() { //Original GM_setValue('mailHeightOriginal', getNode('co').childNodes[1].clientHeight); //Split if (GM_getValue('mailHeightOriginal') < GMAIL_SPLIT_HEIGHT) { GM_setValue('mailHeightSplit', getNode('co').childNodes[1].clientHeight); } else { GM_setValue('mailHeightSplit', GMAIL_SPLIT_HEIGHT); } } //Method Name: swapImg(key, id) //Description: Imitates Contacts, Labels Box with Triangle GIF function swapImg(key, id) { var elem = getNode(id); if (key == 'show') elem.src = 'images/opentriangle.gif'; else elem.src = 'images/triangle.gif'; } //Method Name: resizeMailFrame() //Description: Resizes Gmail Frame based on presence of Reader Frame, or based on Click Events function resizeMailFrame() { //Shrinks Gmail Frame in Split-Window mode var GMAIL_FRAME_SMALL = ".fs {" + " height: " + GM_getValue('mailHeightSplit') + "px !important;" + " overflow: auto;" + "}"; //Expands Gmail Frame in Single-Window mode var GMAIL_FRAME_LARGE = ".fs {" + " height: " + GM_getValue('mailHeightOriginal') + "px !important;" + " overflow: auto;" + "}"; if (!getNode('readerEmbed')) { GM_addStyle (GMAIL_FRAME_LARGE); } else { GM_addStyle (GMAIL_FRAME_SMALL); } } //Method Name: resizeReaderFrame() //Description: Resizes Reader Frame based on Click Events function resizeReaderFrame() { var readerEmbed = getNode('readerEmbed'); if (!readerEmbed) return; if (getNode('co').firstChild.style.display == 'none') { readerEmbed.style.height = (window.innerHeight - readerEmbed.offsetTop) + "px"; } else { readerEmbed.style.height = READER_EMBED_HEIGHT + "px"; } } ////////////////////////////////////////////////// //Functions credited to Mihai @ http://persistent.info/ ////////////////////////////////////////////////// function updateFeedsCount() { var unreadCountNode = getNode("unreadCount"); if (!unreadCountNode) return; GM_xmlhttpRequest({ method: "GET", url: UNREAD_COUNT_API, onload: function(responseDetails) { var data = eval("(" + responseDetails.responseText + ")"); for (var i = 0, unreadCountPair ; unreadCountPair = data.unreadcounts[i] ; i++) { if (unreadCountPair.id.indexOf("reading-list") != -1) { var count = unreadCountPair.count; unreadCountNode.innerHTML = count == 0 ? '' : ' (' + count + (count == data.max ? '+' : '') + ') '; break; } } } }); } function newNode(type) { return unsafeWindow.document.createElement(type); } function getNode(id) { return unsafeWindow.document.getElementById(id); } function hasClass(node, className) { return className in getClassMap(node); } function addClass(node, className) { if (hasClass(node, className)) return; node.className += " " + className; } function removeClass(node, className) { var classMap = getClassMap(node); if (!(className in classMap)) return; delete classMap[className]; var newClassList = []; for (var className in classMap) { newClassList.push(className); } node.className = newClassList.join(" "); } function getClassMap(node) { var classMap = {}; var classNames = node.className.split(/\s+/); for (var i = 0; i < classNames.length; i++) { classMap[classNames[i]] = true; } return classMap; } |
|
|