Pin Extension for GReader

By janus_wel Last update Oct 16, 2008 — Installed 136 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
// ==UserScript==
// @name           Pin Extension for GReader
// @namespace      http://d.hatena.ne.jp/janus_wel
// @description    open current or pinned for Google Reader
// @include        http://www.google.com/reader/view/*
// @include        https://www.google.com/reader/view/*
// @include        http://www.google.co.jp/reader/view/*
// ==/UserScript==
/*
 * VERSION
 *  0.50
 *
 * LICENSE
 *  New BSD License
 *
 * HISTORY
 *  2008/04/20  ver. 0.10   initial written.
 *  2008/05/09  ver. 0.20   make blue pin icon.
 *  2008/05/10  ver. 0.30   use XPath expression.
 *  2008/06/20  ver. 0.40   display number of pinned items.
 *                          refactoring.
 *                          bugfix - can't open multiple feed.
 *                          other fine bugfix.
 *                          use 'const' for constant data.
 *  2008/06/28  ver. 0.50   change style data.
 *                          add license description.
 */

(function() {
    // const variables
    // icon data
    const icon = 'data:image/png;base64,'+
    'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAB'+
    'P0lEQVR4nIWSv0sCYRzGn/uJERK4KOamSA6hQ0p/QePNTeISXNzQ7CQ0OvYXOLhIkuFk+Sc0HLgI'+
    '3RZ2xFUgvIeaV++3wZDruLe+4+fL8z7P876vREQQz3S6mM2UUknL5eQfROKpVm+BZ4AAMs2vDRQK'+
    'Go0r4K5YpGaTWi0CaDD4JCJZFKbTuc5mNU3j6zUyGeTzaLc/AAgFwKuqPi0Wj+Mxul14HlarFwDq'+
    'dm/btud5ACQJhcJ+pXLoOPfptO77/ny+x9hbvb7zq/RoNIrU0PVjSTqR5XPgoly+3EBVkGdT4yyV'+
    'Ouj1bkzztFY7il5rxKHf7y+XPhFNJg9hLiztum4isQvAdd/DPF4wHA4ty4pdxXcwDEPk/Mc7/CdQ'+
    '1Xg3RVHiIzHGHMcJgiC85pxHDpK235tzzhiLBpDlZDIZJt8M+uyw7h+2YAAAAABJRU5ErkJggg==';

    // css settings
    const outlineStyles = [
        'position:           absolute',
        'bottom:             64px',
        'right:              64px',
        'z-index:            100',
        'width:              140px',
        'padding:            8px',
        'background-color:   gray',
        'text-align:         center',
        'display:            none',
        '-moz-border-radius: 10px',
        '-moz-opacity:       0.7',
    ].join(';');

    const numberStyles = [
        'margin-right: 3px',
        'text-align:   center',
        'color:        yellow',
        'font-size:    48px',
        'font-weight:  bold',
    ].join(';');

    const textStyles = [
        'text-align:  center',
        'color:       white',
        'font-size:   24px',
        'font-weight: bold',
    ].join(';');

    const displayTemplate = [
        '<span style="$NUMBER_STYLES">$NUMBER</span>',
        '<span style="$TEXT_STYLES">$TEXT</span>'
    ].join('');

    // scraping function
    function getCurrentEntry() {
        return xpath('//div[@id="current-entry"]');
    }

    function getCurrentEntryURL() {
        var currentEntry = xpath('//div[@id="current-entry"]//a[@class="entry-title-link"][@href]');
        return currentEntry ? currentEntry.href : null;
    }


    // main
    // script global variables
    var pinned = new Array();
    var numofPinned = 0;
    var dispDiv = initialDispDivElement();
    var innerTemplate = initialTemplate();

    document.addEventListener('keydown', pinEntry, false);



    // define functions
    // process icon
    function insertPinIcon(currentURL) {
        pinned[currentURL] = currentURL;

        // insert pin icon
        var pinimg = document.createElement('img');
        pinimg.setAttribute('src', icon);
        pinimg.setAttribute('width', '16');
        pinimg.setAttribute('height', '16');
        pinimg.setAttribute('id', currentURL);
        xpath("//div[@id='current-entry']//div[@class='entry-icons']").appendChild(pinimg);
    }

    function deletePinIcon(currentURL) {
        delete pinned[currentURL];

        // remove pin icon
        var pin = xpath('//img[@id="' + currentURL + '"]');
        if (pin) pin.parentNode.removeChild(pin);
    }

    function pinEntry(event) {
        var currentURL = getCurrentEntryURL();
        // when entry is selected in GReader interface by user
        if (currentURL) {
            // when 'i' key down
            if (event.keyCode == 73) {
                if (pinned[currentURL] == undefined) {
                    insertPinIcon(currentURL);
                    ++numofPinned;
                }
                else {
                    deletePinIcon(currentURL);
                    --numofPinned;
                }
            }
        }

        // 'o' key down and pinned exist
        if (event.keyCode == 79 && !event.shiftKey) {
            var flag = 0;
            for (var url in pinned) {
                flag = 1;
                if (url == 'peek') {
                    break; // for Opera's Array
                }
                window.open(url);
                deletePinIcon(url);
                --numofPinned;
            }

            if (!flag)
            {
                var url = getCurrentEntryURL();
                window.open(url);
                return;
            }
        }

        // display number of pinned item.
        if (numofPinned) {
            var inner = innerTemplate;
            dispDiv.innerHTML = inner.replace(/\$NUMBER/g, numofPinned)
                                     .replace(/\$TEXT/g, 'item' + ((numofPinned > 1) ? 's' : ''));
            dispDiv.style.display = 'block';
        }
        else {
            dispDiv.innerHTML = '';
            dispDiv.style.display = 'none';
        }
    }

    // initial functions
    function initialDispDivElement() {
        var dispDiv = xpath('//div[@id="pefg_display"]');
        // if not exist, insert div element to display number of pinned items.
        if (!dispDiv) {
            var elementDiv = document.createElement('div');
            elementDiv.id = 'pefg_display';
            elementDiv.setAttribute('style', outlineStyles);
            xpath('html').appendChild(elementDiv);
            var dispDiv = xpath('//div[@id="pefg_display"]');
        }
        return dispDiv;
    }

    function initialTemplate() {
         var template = displayTemplate;
         return displayTemplate.replace(/\$NUMBER_STYLES/g, numberStyles)
                               .replace(/\$TEXT_STYLES/g, textStyles);
    }

    // helper function
    function xpath(query) {
        return document.evaluate(
            query,
            document,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        ).singleNodeValue;
    }

})();

// vim:sw=4 ts=4 et: