aboutsummaryrefslogtreecommitdiffstats
path: root/ldrize_cooperation.js
blob: 35952e447ae4fb38975c622b2202c01065d2bb50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
 * ==VimperatorPlugin==
 * @name              Pukka
 * @description       Add bookmark to Delicious with Pukka
 * @description-ja    Pukkaを使用してDeliciousにブックマークする
 * @author            otsune info@otsune.com
 * @namespace         http://www.otsune.com/
 * @minVersion        2.0pre
 * @version           0.4
 * ==/VimperatorPlugin==
 *
 * see also http://codesorcery.net/pukka/
 *
 * Variables:
 *  g:pukka_normalizelink
 *      Specifies keys that use Pathtraq URL Normalizer
 *      usage: let g:pukka_normalizelink = true
 * Mappings:
 *  '[C-p]':
 * Commands:
 *  'pukka' or 'pu':
 *      Post bookmark to Delicious with Pukka
 *      usage: :pu[kka] [http://example.com/]
 * Options:
 *  not implemented
 */

(function() {
var useNormalizelink = liberator.globalVariables.pukka_normalizelink || true;
var buf = liberator.modules.buffer;

liberator.modules.commands
         .addUserCommand(['pukka', 'pu'], 'Post to Pukka bookmark', function(args) {
    if (!buf.title || !buf.URL || buf.URL == 'about:blank') {
        return false;
    }
    var scheme = 'pukka:';
    var title = encodeURIComponent(buf.title);
    var url = encodeURIComponent(buf.URL.toString());
    var extend = encodeURIComponent(window.content.getSelection().toString() || '');
    if (args.string) {
        url = encodeURIComponent(args.string);
    }
    liberator.open(scheme + 'url=' + url + '&title=' + title + '&extended=' + extend);
}, {
    bang: false,
    completer: function(filter) {
        var complist = [];

        complist.push([buf.URL, 'Raw URL: ' + buf.title]);

        if (useNormalizelink) {
            complist.push([getNormalizedPermalink(buf.URL), 'Normalized URL: ' + buf.title]);
        }

        // detect rel="bookmark"
        var elem;
        var relb = buf.evaluateXPath(
            '//*[contains(concat(" ", normalize-space(@rel), " "), " bookmark ")]',
            null, null, true);
        while ((elem = relb.iterateNext()) !== null) {
            complist.push([elem.toString(), '@rel="bookmark" URL: ' + elem]);
        }

        return [0, complist];
    }
});

liberator.modules.mappings
         .addUserMap([liberator.modules.modes.NORMAL], ['<C-p>'], 'Post to Pukka', function() {
    var urlarg = liberator.globalVariables.pukka_normalizelink ?
                 getNormalizedPermalink(buf.URL) :
                 buf.URL;
    liberator.modules.commandline
             .open(':', 'pukka ' + urlarg, modes.EX);
}, {});

// copied from Trapezoid's direct_hb.js
function getNormalizedPermalink(url) {
    var xhr = Components.classes[// Vimperator plugin: 'Cooperation LDRize Mappings'
// Version: 0.25
// Last Change: 07-Jan-2011. Jan 2008
// License: Creative Commons
// Maintainer: Trapezoid <trapezoid.g@gmail.com> - http://unsigned.g.hatena.ne.jp/Trapezoid
//
// Cooperation LDRize Mappings for Vimperator
//
// Variables:
//  g:ldrc_captureMapping
//      Specifies keys that capture by LDRize
//      usage: let g:ldrc_captureMappings = "['j','k','p','o','?']"
//  g:ldrc_enable
//      LDRize Cooperation be Enable by default or not
//      usage: let g:ldrc_enable = "false"
//      default: true
//  g:ldrc_hints
//      Narrows "hinttags" based on Siteinfo.
//      usage: let g:ldrc_hints = "true"
//      default: false
//  g:ldrc_intelligence_bind
//      More inteligence cooperation bind
//      usage: let g:ldrc_intelligence_bind = "true"
//      default: false
//  g:ldrc_skip
//      length in which paragraph is skipped (use by inteligence bind mode)
//      usage: let g:ldrc_hints = "true"
//      default: 0.5
// Mappings:
//      Mappings for LDRize
//      default: 'j','k','p','o'
// Commands:
//  'm' or 'mb' or 'minibuffer':
//      Execute args as Minibuffer Command
//      usage: :minibuffer pinned-link | open | clear-pin
//  'pin':
//      View pinned link list
//      usage: :pin
//  'pindownload':
//      Download View pinned link by handler function or outer promgram. please see 'handlerInfo' also
//      usage: :pindownload
//  'ldrc' or 'toggleldrizecooperation':
//      Toggle LDRize Cooperation
//      usage: :toggleldrizecooperation
// Hints:
//  ';l':
//      narrow down the candidates to LDRize paragraphes
//  ';L':
//      narrow down the candidates to LDRize paragraphes (in a new tab)
// Options:
//  'ldrc'
//      Enable LDRize Cooperation
//      usage: :set ldrc
//  'noldrc'
//      Disable LDRize Cooperation
//      usage: :set noldrc
//
//  'ldrchints'
//      Enable "Narrows Hinttags based on Siteinfo"
//      usage: :set ldrchints
//  'noldrchints'
//      Disable "Narrows Hinttags based on Siteinfo"
//      usage: :set noldrchints
if (liberator.plugins.LDRizeCooperation == undefined) (function(){
    //pattern: wildcard
    //include: [regexp,option] or regexp
    //handler: [programPath,[args]] or programPath or function(url,title)
    var handlerInfo = [
        //{
        //    pattern: "http://www.nicovideo.jp/*",
        //    handler: {
        //      download: ["c:\\usr\\SmileDownloader\\SmileDownloader.exe",["%URL%"]]
        //    },
        //    wait: 5000
        //},
        //{
        //    handler: ["C:\\usr\\irvine\\irvine.exe",["%URL%"]],
        //},
    ];
    const DISABLE_ICON = "data:image/png;base64,"
        +"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAA7E"
        +"AAAOxAGVKw4bAAACL0lEQVR4nF2Sy0tUYRjGf9+Z4/HMjJfjBUZEMM2MSDII"
        +"REjSVtVecBFZi6Bdi4RW/SFBq2oR0R8gSaUJhVJIBkEEMZOWl5kuM+fqnPN9"
        +"52sxQ4kPv837Pu+zel4xMjkz/3h5p87pbhyDw4o1mzUOkubYbvLo2kVx+4Pe"
        +"rAKMdTGQ5YgiWK/8z+QT3yyVUTFAzaBXHQ0IONPKOxepAH65dUOGSB/pM9LC"
        +"whjyy/sg4DB3TjGZbjVuVIihQhKfxGdzmzhhNBvGXhr7NDiRY+fr573ibmtC"
        +"4pN4GNJDukiXusvbIuMnh9K9YujSYKKPl6vrZu+EI5EuyheG9JEe0qPusfSR"
        +"4cGBbPA98og8LMlAPlor2ZEvVIT0kD6G9EhcEpfY58c+xbKYHBaRl4Ye432s"
        +"rqyo7pnQo/qTxEW62gy2CKoAbheu4mGGm5eHgsViOTh+5Sp37+2X4gJQC0gU"
        +"Otb0j2hhaCG06NfC0K22/radzs6uTM3ojY1SobDcdHNaCC2Mimn2YZmQggEd"
        +"kPJ0UczfyOzVWHr1xnVmrS5I0R6pgTC1mXdoUwB2Jj5QFvDsBc8fTCkpL82l"
        +"uW6rWWEPQBoL07JwCgAaywbgd8ynIrultTB3wWk73LtWdS3OXtd/fBwH2+Yg"
        +"xM4R14kqrzMZzM5pO9dcNlQrl832wTSoGiEok84eOrK0ZGB0+shTJYpyFUv7"
        +"In/s/LlbTyq+/ufZFlkTK4MhAJKUMCGs6x473rg/9xe9wS0xVA1n/AAAAABJ"
        +"RU5ErkJggg==";
    const ENABLE_ICON = "data:image/png;base64,"
        +"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsT"
        +"AAALEwEAmpwYAAACI0lEQVR4nGWSzU7yQBSGp84UKalDY0MkLsSdYWtCIok3"
        +"4YKV7tx7MWy9A6/ABZDgHbhghdFqU9M0FpH57cyUcdFA8Pue3fl5T07Oe5zz"
        +"8/PhcEgpbbfbtVoN7LBer9M01VpX4f7+/t3dnfP4+JimKQDg6OgIYwz+UpZl"
        +"HMdbjbUWZVkmpQQAEEJc1wX/EYZhHMdlWQIAKKV7cgPG+PLy8uPjg/+l3+/7"
        +"vl/1KKVQURRCCABAFEVa6yAIOOeO41Tjj4+PoyiK49h1XSkl53xPbOCcz+fz"
        +"bre7WCzYhpOTk+l0GoYhhFAIIaXck1JuNc/Pz51OpyiKahkAAMb49fVVCKGU"
        +"qgTw4uKCUqq1RggZY05PT8uyTJJEa312dvby8rJcLq21y+WSUiqlhN1uN89z"
        +"xpgxJs9zQkiv1xuNRlmWXV9f39/ff39/53meZRmllBCCZrNZkiTWWowxIWQ6"
        +"nV5dXRFCGGOfn59PT0+MMWut67pa6/V6jZrNpjHGWus4TqPRsNaORqPBYCCE"
        +"GI/Hvu/7vm+trc4KAEC+71dGQggrdyaTyXA4NMbc3NxsvW82mwCAoihQrVY7"
        +"PDzctVYIEUXR29tbo9GAEO6WpJTO7e0tIQRjXK/XhRCe5ymlsiyDEAZB4Hle"
        +"lawEX19fqNVqVS/kOE6r1fI8DyHU6XT++ShjzM/Pz8HBAXx/f+/3+9X2WmvO"
        +"uVKq3GCMUUoxxlarVb1ef3h4+AWNW50eXTIBjgAAAABJRU5ErkJggg==";

    var Class = function() function(){this.initialize.apply(this,arguments)};

    var _isEnable;

    function replaceMap (mode,key,desc,aroundFunc,extra){
      var old = liberator.modules.mappings.getDefault(mode,key);
      var oldAction = old.action;
      old.description = desc;
      old.action = function()
                      let (self = this,args = arguments)
                        aroundFunc(function() oldAction.apply(self,args));
    }

    var LDRizeCooperation = new Class();
    LDRizeCooperation.prototype = {
        initialize: function(){
            var self = this;
            this.LDRize = {getSiteinfo: function() undefined};
            this.Minibuffer = null;
            this.handlerInfo = handlerInfo;

            this.LDRizeCooperationPanel = this.setupStatusbarPanel();

            this.isEnable = liberator.globalVariables.ldrc_enable != undefined ?
                window.eval(liberator.globalVariables.ldrc_enable) : true ;
            this.isIntelligenceBind = liberator.globalVariables.ldrc_intelligence_bind != undefined ?
                window.eval(liberator.globalVariables.ldrc_intelligence_bind) : false ;
            this.isModHints = liberator.globalVariables.ldrc_hints != undefined ?
                window.eval(liberator.globalVariables.ldrc_hints) : false ;
            this.captureMappings = window.eval(liberator.globalVariables.ldrc_captureMappings) || ["j","k","p","o"];
            this.skipHeight = liberator.globalVariables.ldrc_skip != undefined ?
                window.eval(liberator.globalVariables.ldrc_skip) : 0.5 ;

            this.convertHandlerInfo(this.handlerInfo);
            this.hookGreasemonkey();
            this.initLDRizeCaptureKeys(this.captureMappings);
            this.initLDRizeCooperationFuture();


            if(liberator.plugins.LDRizeCooperationPlugins != undefined){
                liberator.plugins.LDRizeCooperationPlugins.forEach(function(func){
                    func.apply(self,arguments);
                });
                delete liberator.plugins.LDRizeCooperationPlugins;
            }
        },
        setupStatusbarPanel: function(){
            var self = this;
            var LDRizeCooperationPanel = document.createElement("statusbarpanel");
            LDRizeCooperationPanel.setAttribute("id","ldrizecopperation-status");
            LDRizeCooperationPanel.setAttribute("class","statusbarpanel-iconic");
            LDRizeCooperationPanel.setAttribute("src",this.isEnable ? ENABLE_ICON : DISABLE_ICON);
            LDRizeCooperationPanel.addEventListener("click",function(e){
                    self.isEnable = !self.isEnable;
            },false);
            var ref = document.getElementById("security-button") ? document.getElementById("security-button").nextSibling
                                                                 : document.getElementById("status-bar").firstChild;
            document.getElementById("status-bar").insertBefore(LDRizeCooperationPanel,ref);

            return LDRizeCooperationPanel;
        },
        hookGreasemonkey: function(){
            var self = this;
            var GreasemonkeyService;
            try{
                GreasemonkeyService = Cc["@greasemonkey.mozdev.org/greasemonkey-service;1"].getService().wrappedJSObject;
                this.addAfter(GreasemonkeyService,"evalInSandbox",function(){
                    var gmVersion = liberator.extensions.filter(function(e)e.name=='Greasemonkey')[0].version;
                    var versionChecker = Cc["@mozilla.org/xpcom/version-comparator;1"]
                        .getService(Ci.nsIVersionComparator);
                    if (versionChecker.compare(gmVersion, "0.8.*") > 0) {
                        var [code,sandbox] = arguments;
                    } else {
                        var [code,codebase,sandbox] = arguments;
                    }
                    if(sandbox.window.LDRize != undefined && sandbox.window.Minibuffer != undefined){
                        sandbox.window.addEventListener("focus",function(){
                            self.LDRize = liberator.eval("self",sandbox.window.LDRize.getSiteinfo);
                            self.Minibuffer = liberator.eval("command",sandbox.window.Minibuffer.addCommand);
                            if (typeof self.LDRize.getSiteinfo != 'function') self.LDRize = sandbox.window.LDRize;
                            if (typeof self.Minibuffer.addCommand != 'function') self.Minibuffer = sandbox.window.Minibuffer.command;
                        },false);
                        if(window.content.wrappedJSObject == sandbox.unsafeWindow){
                            self.LDRize = liberator.eval("self",sandbox.window.LDRize.getSiteinfo);
                            self.Minibuffer = liberator.eval("command",sandbox.window.Minibuffer.addCommand);
                            if (typeof self.LDRize.getSiteinfo != 'function') self.LDRize = sandbox.window.LDRize;
                            if (typeof self.Minibuffer.addCommand != 'function') self.Minibuffer = sandbox.window.Minibuffer.command;
                        }
                    }
                });
            }catch(e){
                liberator.log(e);
            }
        },
        initLDRizeCaptureKeys: function(keys){
            var self = this;
            keys.forEach(function(x){
                    var map = liberator.modules.mappings.get(null,x) || liberator.modules.mappings.getDefault(null,x);
                    var oldAction = map.action;
                    var getter = "getPrev";
                    switch(x){
                        case "j":   getter = "getNext";
                        case "k":   map.action = function(){
                                        self.isEnableLDRizeCooperation() ?
                                            self.isIntelligenceBind && self.isScrollOrBind(getter) ?
                                                oldAction.apply(this,arguments)           // scroll
                                                : self.sendRawKeyEvent(0,x.charCodeAt(0)) // bind
                                            : oldAction.apply(this,arguments);
                                    };
                                    break;
                        case "J":
                        case "K":   map.action = function(){
                                        self.isEnableLDRizeCooperation()
                                            ? self.sendRawKeyEvent(0,x.charCodeAt(0) + 32)
                                            : oldAction.apply(this,arguments);
                                    };
                                    break;
                        default:    map.action = function(){
                                        self.isEnableLDRizeCooperation()
                                            ? self.sendRawKeyEvent(0,x.charCodeAt(0))
                                            : oldAction.apply(this,arguments);
                                    };
                                    break;
                    }
            });
        },
        initLDRizeCooperationFuture: function(){
            var self = this;

            //Hints
            [
                ["l","LDRize paragraphes",liberator.CURRENT_TAB],
                ["L","LDRize paragraphes (in a new tab",liberator.NEW_TAB]
            ].forEach(function([mode,prompt,target]){
                liberator.modules.hints.addMode(mode,prompt,
                        function(elem) liberator.modules.buffer.followLink(elem,target),
                        function(){
                            var siteinfo = self.LDRize.getSiteinfo();
                            return siteinfo.paragraph + "/" + siteinfo.link;
                        });

            });

            //Commands
            liberator.modules.commands.addUserCommand(["pin"],"LDRize Pinned Links",
                function(){
                    var links = self.getPinnedItems();
                    var showString = links.length + " Items<br/>";
                    links.forEach(function(link){
                        showString += link + "<br/>";
                    });
                    liberator.modules.commandline.echo(showString,liberator.modules.commandline.HL_NORMAL,liberator.modules.commandline.FORCE_MULTILINE);
                },{});
            liberator.modules.commands.addUserCommand(["mb","m","minibuffer"],"Execute Minibuffer",
                function(arg){ self.Minibuffer.execute(arg.string.replace(/\\+/g,"")) },
                {
                    completer: function(context,arg){
                        var filter = context.filter;
                        var completionList = [];
                        var command = self.Minibuffer.command;
                        var alias = self.Minibuffer.alias_getter();
                        var tokens = filter.split("|").map(function(str) str.replace(/\s+/g,""));
                        var exp = new RegExp("^" + tokens.pop());
                        for(let i in command) if(exp.test(i))completionList.push([tokens.concat(i).join(" | "),"MinibufferCommand"]);
                        for(let i in alias) if(exp.test(i))completionList.push([i,"MinibufferAlias"]);
                        context.title = ["Minibuffer Command","Description"];
                        context.completions = completionList;
                    }
                });
            liberator.modules.commands.addUserCommand(["pindownload"],"Download pinned links by any software",
                function(arg){ self.downloadLinksByProgram("download",self.getPinnedItems());},{});
            liberator.modules.commands.addUserCommand(["pindo"],"Do external command, with pinned links",
                function(arg){ self.downloadLinksByProgram(arg.string, self.getPinnedItems());},{});
            liberator.modules.commands.addUserCommand(["toggleldrizecooperation","toggleldrc"],"Toggle LDRize Cooperation",
            function(arg){ self.isEnable = !self.isEnable},{});
            //Options
            liberator.modules.options.add(["ldrc","ldrizecooperation"],"LDRize cooperation","boolean",this.isEnable,
                {
                    setter: function(value){ return self.isEnable = value; },
                    getter: function() self.isEnable
                }
            );
            liberator.modules.options.add(["ldrchints"],"mod hinttags for LDRize","boolean",this.isModHints,
                {
                    setter: function(value){ return self.isModHints = value; },
                    getter: function() self.isModHints
                }
            );
        },
        convertHandlerInfo: function(handlerInfoArray){
            handlerInfoArray.forEach(function(x){
                x.include = typeof x.include != "undefined"
                    ? typeof x.include == "string" ? new RegExp(x.include) : new RegExp(x.include[0],x.include[1])
                    : typeof x.pattern != "undefined"
                        ? new RegExp("^"+String(x.pattern).replace(/\s+/g,"").replace(/[\\^$.+?|(){}\[\]]/g,"\\$&")
                            .replace(/(?=\*)/g,".")+"$","i")
                        : /(?:)/;
                delete x.pattern;
            });
        },

        get isEnable() _isEnable,
        set isEnable(value){
            this.LDRizeCooperationPanel.setAttribute("src",value ? DISABLE_ICON : ENABLE_ICON);
            _isEnable = value;
        },
        isEnableLDRize: function() this.LDRize.getSiteinfo() != undefined,
        isEnableLDRizeCooperation: function() /^https?:$/.test(content.location.protocol) && this.isEnable && this.isEnableLDRize(),

        //Pin
        getPinnedItems: function(){
            var linkXpath = this.LDRize.getSiteinfo()["link"];
            var viewXpath = this.LDRize.getSiteinfo()["view"] || linkXpath + "/text()";
            return this.LDRize.getPinnedItems().map(function(i){
                var linkResult = i.XPath(linkXpath),viewResult = i.XPath(viewXpath);
                return [linkResult,viewResult ? viewResult.textContent : null];
            });
        },
        downloadLinksByProgram: function(command, links){
            var self = this;
            var count = 0;
            links.forEach(function([url,title]){
                for each(let x in self.handlerInfo){
                    if(x.include.test(url)){
                        setTimeout(function(){
                            if(typeof x.handler[command] == "object"){
                                let args = x.handler[command][1].map(function(s) s.replace(/%URL%/g,url).replace(/%TITLE%/g,title));
                                liberator.modules.io.run(x.handler[command][0],args,false);
                            }else if(typeof x.handler[command] == "string"){
                                liberator.modules.io.run(x.handler[command],[url],false);
                            }else if(typeof x.handler[command] == "function"){
                                x.handler[command](url.toString(),title);
                            }
                        },x.wait != undefined ? x.wait * count++ : 0);
                        return;
                    }
                }
                liberator.echoerr("LDRize Cooperation: download pattern not found!!");
            });
        },
        isScrollOrBind: function(getter){
            var self = this;
            var paragraphes,paragraph,current,next,innerHeight,scrollY,limit,p,np,cp;
            try{
                paragraphes = this.LDRize.getParagraphes();
                paragraph = paragraphes[getter]();
                current = paragraphes.current;
                next = paragraphes.getNext();

                innerHeight = window.content.innerHeight;
                scrollY = window.content.scrollY;

                limit = window.content.innerHeight * (self.skipHeight + 0.5);

                if(paragraph.paragraph == undefined) return true;                                 // scroll
                if(current.paragraph == undefined) return false;                                  // bind
                if(current.paragraph.y - window.content.scrollY == this.LDRize.getScrollHeight()
                        && getter == "getPrev") return false;                                     // bind

                p = this.getClientPosition(paragraph.paragraph.node);
                np = next && next.paragraph.node != undefined ?
                    this.getClientPosition(next.paragraph.node) :
                    {top: window.content.scrollMaxY + window.content.innerHeight,left: 0};
                cp = this.getClientPosition(current.paragraph.node);

                /*
                 *log(p);
                 *log(np);
                 *log(cp);
                 */

                //check current paragraph
                if(!(scrollY < np.top && cp.top < scrollY + innerHeight)) return false;           // bind
                //check next/prev paragraph
                if(Math.abs(p.top - (scrollY + innerHeight/2)) < innerHeight * 0.5) return false; // bind
                if(Math.abs(p.top - (scrollY + innerHeight/2)) > limit) return true;              // scroll
                return false;                                                                     // bind
            }catch(e){
                liberator.log(e);
            }
        },

        //Utils
        addAfter: function(target,name,after){
            var original = target[name];
            target[name] = function(){
                var tmp = original.apply(target,arguments);
                after.apply(target,arguments);
                return tmp;
            };
        },
        getClientPosition: function(elem){
            var position;
            try{
                position = elem.getBoundingClientRect();
            }catch(e){
                position = elem.parentNode.getBoundingClientRect();
            }
            return {
                left: Math.round(window.content.scrollX+position.left),
                top:  Math.round(window.content.scrollY+position.top)
            };
        },
        sendRawKeyEvent: function(keyCode,charCode){
            modes.passAllKeys = true;
            var evt = window.content.wrappedJSObject.document.createEvent("KeyEvents");
            evt.initKeyEvent("keypress",false,false,window.content.wrappedJSObject,false,false,false,false,keyCode,charCode);
            window.content.wrappedJSObject.document.dispatchEvent(evt);
            modes.passAllKeys = false;
        },
    };

    liberator.plugins.LDRizeCooperation = new LDRizeCooperation();
})();