aboutsummaryrefslogtreecommitdiffstats
path: root/copy.js
blob: 4bcd3e33b1a81d7976b68354e82996210af587f5 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/**
 * ==VimperatorPlugin==
 * @name           copy.js
 * @description    enable to copy strings from a template (like CopyURL+)
 * @description-ja テンプレートから文字列のコピーを可能にします(CopyURL+みたなもの)
 * @minVersion     1.1
 * @author         teramako teramako@gmail.com
 * @version        0.5a
 * ==/VimperatorPlugin==
 *
 * Usage:
 * :copy {copyString}         -> copy the argument replaced some certain string
 * :copy! {expr}              -> evaluate the argument and copy the result
 *
 * e.g.)
 * :copy %TITLE%              -> copied the title of the current page
 * :copy title                -> same as `:copy %TITLE%' by default
 * :copy! liberator.version   -> copy the value of liberator.version
 *
 * If non-argument, used `default'
 *
 * label: template name which is command argument
 * value:  copy string
 *    the certian string is replace to ...
 *        %TITTLE%  -> to the title of the current page
 *        %URL%     -> to the URL of the current page
 *        %SEL%     -> to the string of selection
 *        %HTMLSEL% -> to the html string of selection
 *
 * map: key map (optional)
 *
 * custom: {function} or {Array} (optional)
 *   {function}:
 *    execute the function and copy return value, if specified.
 *
 *   {Array}:
 *    replaced to the {value} by normal way at first.
 *    and replace words matched {Array}[0] in the replaced string to {Array}[1].
 *    {Array}[0] is string or regexp
 *    {Array}[1] is string or function
 *    see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:String:replace
 *
 * The copy_templates is a string variable which can set on
 * vimperatorrc as following.
 *
 * let copy_templates = "[{ label: 'titleAndURL', value: '%TITLE%\n%URL%' }, { label: 'title', value: '%TITLE%' }]"
 *
 * or your can set it using inline JavaScript.
 *
 * javascript <<EOM
 * liberator.globalVariables.copy_templates = [
 *   { label: 'titleAndURL',    value: '%TITLE%\n%URL%' },
 *   { label: 'title',          value: '%TITLE%', map: ',y' },
 *   { label: 'anchor',         value: '<a href="%URL%">%TITLE%</a>' },
 *   { label: 'selanchor',      value: '<a href="%URL%" title="%TITLE%">%SEL%</a>' },
 *   { label: 'htmlblockquote', value: '<blockquote cite="%URL%" title="%TITLE%">%HTMLSEL%</blockquote>' }
 *   { label: 'ASIN',   value: 'copy ASIN code from Amazon', custom: function(){return content.document.getElementById('ASIN').value;} },
 * ];
 * EOM
 */
liberator.plugins.exCopy = (function(){
if (!liberator.globalVariables.copy_templates){
    liberator.globalVariables.copy_templates = [
        { label: 'titleAndURL',    value: '%TITLE%\n%URL%' },
        { label: 'title',          value: '%TITLE%' },
        { label: 'anchor',         value: '<a href="%URL%">%TITLE%</a>' },
        { label: 'selanchor',      value: '<a href="%URL%" title="%TITLE%">%SEL%</a>' },
        { label: 'htmlblockquote', value: '<blockquote cite="%URL%" title="%TITLE%">%HTMLSEL%</blockquote>' }
    ];
}

liberator.globalVariables.copy_templates.forEach(function(template){
    if (typeof template.map == 'string')
        addUserMap(template.label, [template.map]);
    else if (template.map instanceof Array)
        addUserMap(template.label, template.map);
});

// used when argument is none
//const defaultValue = templates[0].label;
commands.addUserCommand(['copy'],'Copy to clipboard',
    function(arg, special){
        liberator.plugins.exCopy.copy(arg, special);
    },{
        completer: function(filter, special){
            if (special){
                return completion.javascript(filter);
            }
            var templates = liberator.globalVariables.copy_templates.map(function(template)
                [template.label, template.value]
            );
            if (!filter){ return [0,templates]; }
            var candidates = [];
            templates.forEach(function(template){
                if (template[0].toLowerCase().indexOf(filter.toLowerCase()) == 0){
                    candidates.push(template);
                }
            });
            return [0, candidates];
        },
        bang: true
    }
);

function addUserMap(label, map){
    mappings.addUserMap([modes.NORMAL,modes.VISUAL], map,
        label,
        function(){ liberator.plugins.exCopy.copy(label); },
        { rhs: label }
    );
}
function getCopyTemplate(label){
    var ret = null;
    liberator.globalVariables.copy_templates.some(function(template)
        template.label == label ? (ret = template) && true : false);
    return ret;
}
function replaceVariable(str){
    if (!str) return '';
    var win = new XPCNativeWrapper(window.content.window);
    var sel = '',htmlsel = '';
    if (str.indexOf('%SEL%') >= 0 || str.indexOf('%HTMLSEL%') >= 0){
        sel = win.getSelection().getRangeAt(0);
    }
    if (str.indexOf('%HTMLSEL%') >= 0){
        var serializer = new XMLSerializer();
        htmlsel = serializer.serializeToString(sel.cloneContents());
    }
    return str.replace(/%TITLE%/g,buffer.title)
              .replace(/%URL%/g,buffer.URL)
              .replace(/%SEL%/g,sel.toString())
              .replace(/%HTMLSEL%/g,htmlsel);
}

var exCopyManager = {
    add: function(label, value, custom, map){
        var template = {label: label, value: value, custom: custom, map: map};
        liberator.globalVariables.copy_templates.unshift(template);
        if (map) addUserMap(label, map);

        return template;
    },
    get: function(label){
        return getCopyTemplate(label);
    },
    copy: function(arg, special){
        var copyString = '';
        var isError = false;
        if (special && arg){
            try {
                copyString = window.eval('with(liberator){' + arg + '}');
                switch (typeof copyString){
                    case 'object':
                        copyString = copyString === null ? 'null' : copyString.toSource();
                        break;
                    case 'function':
                        copyString = copyString.toString();
                        break;
                    case 'number':
                    case 'boolean':
                        copyString = '' + copyString;
                        break;
                    case 'undefined':
                        copyString = 'undefined';
                        break;
                }
            } catch (e){
                isError = true;
                copyString = e.toString();
            }
        } else {
            if (!arg) arg = liberator.globalVariables.copy_templates[0];
            var template = getCopyTemplate(arg) || arg;
            if (typeof template.custom == 'function'){
                copyString = template.custom.call(this, template.value);
            } else if (template.custom instanceof Array){
                copyString = replaceVariable(template.value).replace(tempalte.custom[0], template.custom[1]);
            } else {
                copyString = replaceVariable(template.value);
            }
        }
        util.copyToClipboard(copyString);
        if (isError){
            liberator.echoerr('CopiedErrorString: `' + copyString + "'");
        } else {
            liberator.echo('CopiedString: `' + util.escapeHTML(copyString) + "'");
        }
    }
};
return exCopyManager;
})();

// vim: set fdm=marker sw=4 ts=4 et:
) { this.uri = uri; this.uriObject = this.ioService.newURI(uri, null, null); this.cookie = this._deserializeCookie(this._getCookieString()); } }, _getCookieString: function () { return this.uriObject ? this.cookieService.getCookieString(this.uriObject, null) : null; }, _setCookieString: function (cookieString) { if (this.uriObject && cookieString) { this.cookieService.setCookieString(this.uriObject, null, cookieString, null); } }, _deserializeCookie: function (cookieString) { var cookies = cookieString.split('; '); var cookie = {}; var key, val; for (var i=0, max=cookies.length ; i<max ; ++i) { [key, val] = cookies[i].split('='); cookie[key] = val; } return cookie; }, getCookie: function (key) { return this.cookie[key] ? this.cookie[key] : null; }, setCookie: function (obj) { this.cookie[obj.key] = obj.value; var string = [ obj.key + '=' + obj.value, 'domain=' + obj.domain, 'expires=' + new Date(new Date().getTime() + obj.expires), ].join(';'); this._setCookieString(string); }, }; // NicoPlayerController Class function NicoPlayerController() { this.initialize.apply(this, arguments); } NicoPlayerController.prototype = { initialize: function () { this.cookieManager = new CookieManager(); }, constants: { VERSION: '0.53', CARDINAL_NUMBER: 10, NICO_DOMAIN: '.nicovideo.jp', NICO_URL: 'http://www.nicovideo.jp/', WATCH_URL: 'http://www.nicovideo.jp/watch/', WATCH_PAGE: 1, FLVPLAYER_NODE_ID: 'flvplayer', STATE_PLAYING: 'playing', PLAY: true, PAUSE: false, STATE_SIZE_NORMAL: 'normal', STATE_SIZE_FIT: 'fit', NAME_PREMIUM_NO: 'premiumNo', NAME_PLAYER_VERSION: 'PLAYER_VERSION', SEEKTO_DEFAULT: 0, SEEKBY_DEFAULT: 0, VOLUMETO_DEFAULT: 100, VOLUMEBY_DEFAULT: 0, DESCRIPTION_HIDDEN_NODE_ID: 'des_1', DESCRIPTION_DISPLAYED_NODE_ID: 'des_2', DESCRIPTION_HIDDEN_STATE: 0, DESCRIPTION_DISPLAYED_STATE: 1, COOKIE_DESCRIPTION_NAME: 'desopen', COOKIE_EXPIRES: 60 * 60 * 24 * 365 * 1000, COMMAND_NORMAL: [ ['naka', 'normal comment (flow right to left)'], ['ue', 'fix comment to vertical top and horizonal center of the screen'], ['shita', 'fix comment to vertical bottom and horizonal center of the screen'], ['medium', 'normal size comment'], ['big', 'big size comment'], ['small', 'small size comment'], ['white', 'white color comment'], ['red', 'red color comment'], ['pink', 'pink color comment'], ['orange', 'orange color comment'], ['yellow', 'yellow color comment'], ['green', 'green color comment'], ['cyan', 'cyan color comment'], ['blue', 'bule color comment'], ['purple', 'purple color comment'], ['184', 'anonymouse comment'], ['sage', 'post comment on "sage" mode'], ['invisible', 'invisible comment'], ], COMMAND_PREMIUM: [ ['niconicowhite', 'nicinicowhite color comment'], ['truered', 'truered color comment'], ['passionorange', 'passionorange comment'], ['madyellow', 'madyellow comment'], ['elementalgreen', 'elementalgreen comment'], ['marineblue', 'marineblue'], ['nobleviolet', 'nobleviolet'], ['black', 'black'], ], }, getControllerVersion: function () { return this.constants.VERSION; }, getPlayerVersion: function () { return this.getValue(this.constants.NAME_PLAYER_VERSION); }, pagecheck: function() { if(this.getURL().match(this.constants.WATCH_URL)) return this.constants.WATCH_PAGE; throw new Error('current tab is not watch page on nicovideo.jp'); }, getURL: function() { return liberator.modules.buffer.URL; }, _flvplayer: function() { if(this.pagecheck() === this.constants.WATCH_PAGE) { var flvplayer = window.content.document.getElementById(this.constants.FLVPLAYER_NODE_ID); if(! flvplayer) throw new Error('flvplayer is not found'); return flvplayer.wrappedJSObject ? flvplayer.wrappedJSObject : flvplayer ? flvplayer : null; } return null; }, togglePlay: function() { var p = this._flvplayer(); (p.ext_getStatus() !== this.constants.STATE_PLAYING) ? p.ext_play(this.constants.PLAY) : p.ext_play(this.constants.PAUSE); }, toggleMute: function() { var p = this._flvplayer(); p.ext_setMute(! p.ext_isMute()); }, toggleCommentVisible: function() { var p = this._flvplayer(); p.ext_setCommentVisible(! p.ext_isCommentVisible()); }, toggleRepeat: function() { var p = this._flvplayer(); p.ext_setRepeat(! p.ext_isRepeat()); }, toggleSize: function() { var p = this._flvplayer(); (p.ext_getVideoSize() === this.constants.STATE_SIZE_NORMAL) ? p.ext_setVideoSize(this.constants.STATE_SIZE_FIT) : p.ext_setVideoSize(this.constants.STATE_SIZE_NORMAL); }, toggleDescription: function () { if (!(this.pagecheck() === this.constants.WATCH_PAGE)) { return; } // get nodes var hidden = window.content.document.getElementById(this.constants.DESCRIPTION_HIDDEN_NODE_ID); var displayed = window.content.document.getElementById(this.constants.DESCRIPTION_DISPLAYED_NODE_ID); // get cookie this.cookieManager.readCookie(this.constants.NICO_URL); var val = this.cookieManager.getCookie(this.constants.COOKIE_DESCRIPTION_NAME); if (!(hidden && displayed && val !== undefined && val !== null)) { return; } // change 'display' property of description nodes var escape = hidden.style.display; hidden.style.display = displayed.style.display; displayed.style.display = escape; // change cookie var change = (val == this.constants.DESCRIPTION_HIDDEN_STATE) ? this.constants.DESCRIPTION_DISPLAYED_STATE : this.constants.DESCRIPTION_HIDDEN_STATE; this.cookieManager.setCookie({ key: this.constants.COOKIE_DESCRIPTION_NAME, value: change, domain: this.constants.NICO_DOMAIN, expires: this.constants.COOKIE_EXPIRES, }); }, seekTo: function(position) { if(position) { if(position.match(/^(\d+):(\d+)$/)) { position = parseInt(RegExp.$1, this.constants.CARDINAL_NUMBER) * 60 + parseInt(RegExp.$2, this.constants.CARDINAL_NUMBER); } if(isNaN(position)) throw new Error('assign unsigned number : seekTo()'); } else position = this.constants.SEEKTO_DEFAULT; var p = this._flvplayer(); p.ext_setPlayheadTime(position); }, seekBy: function(delta) { if(delta) { if(isNaN(delta)) throw new Error('assign signed number : seekBy()'); } else delta = this.constants.SEEKBY_DEFAULT; var p = this._flvplayer(); var position = p.ext_getPlayheadTime(); position += parseInt(delta, this.constants.CARDINAL_NUMBER); p.ext_setPlayheadTime(position); }, volumeTo: function(volume) { if(volume) { if(isNaN(volume)) throw new Error('assign unsigned number : volumeTo()'); } else volume = this.constants.VOLUMETO_DEFAULT; var p = this._flvplayer(); p.ext_setVolume(volume); }, volumeBy: function(delta) { if(delta) { if(isNaN(delta)) throw new Error('assign signed number : volumeBy()'); } else delta = this.constants.VOLUMEBY_DEFAULT; var p = this._flvplayer(); var volume = p.ext_getVolume(); volume += parseInt(delta, this.constants.CARDINAL_NUMBER); p.ext_setVolume(volume); }, getValue: function(name) { return this._flvplayer().GetVariable(name); }, setValue: function(name, value) { return this._flvplayer().SetVariable(name, value); }, // return the clone not to damage // Array.apply() is cloning Array // (adding method to Array has a lot of troubles) // refer: http://la.ma.la/blog/diary_200510062243.htm getAvailableCommands: function() { return this.getValue(this.constants.NAME_PREMIUM_NO) ? this.constants.COMMAND_NORMAL.concat(this.constants.COMMAND_PREMIUM) : Array.apply(null, this.constants.COMMAND_NORMAL) } }; // global object var controller = new NicoPlayerController(); // command register liberator.modules.commands.addUserCommand( ['nicoinfo'], 'display player information', function() { try { var info = [ 'player version : ' + controller.getPlayerVersion(), 'controller version : ' + controller.getControllerVersion(), ].join("\n"); liberator.echo(info, liberator.modules.commandline.FORCE_MULTILINE); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicopause'], 'toggle play / pause', function() { try { controller.togglePlay(); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicomute'], 'toggle mute', function() { try { controller.toggleMute(); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicommentvisible'], 'toggle comment visible', function() { try { controller.toggleCommentVisible(); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicorepeat'], 'toggle repeat', function() { try { controller.toggleRepeat(); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicoseek'], 'controll seek bar', function(args, special) { try { var arg = (args.arguments.length > 1) ? args.arguments[0].toString() : args.string; special ? controller.seekBy(arg) : controller.seekTo(arg); } catch(e) { liberator.echoerr(e); } }, { bang: true, } ); liberator.modules.commands.addUserCommand( ['nicovolume'], 'controll volume', function(args, special) { try { var arg = (args.arguments.length > 1) ? args.arguments[0].toString() : args.string; special ? controller.volumeBy(arg) : controller.volumeTo(arg); } catch(e) { liberator.echoerr(e); } }, { bang: true, } ); liberator.modules.commands.addUserCommand( ['nicosize'], 'toggle video size', function() { try { controller.toggleSize(); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicodescription'], 'toggle display or not the description for video', function() { try { controller.toggleDescription(); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicomment'], 'fill comment box', function(args) { try { var arg = args.string; var command, comment; [command, comment] = expandExCommand(arg); comment = comment.replace(/&emsp;/g, EMSP) .replace(/&nbsp;/g, NBSP) .replace(/<LF>/g, LF); if(command) { controller.setValue('inputArea.MailInput.text', command); } controller.setValue('ChatInput.text', comment); } catch(e) { liberator.echoerr(e); } }, {} ); liberator.modules.commands.addUserCommand( ['nicommand'], 'fill command box', function(arg) { try { controller.setValue('inputArea.MailInput.text', arg.string); } catch(e) { liberator.echoerr(e); } }, { completer: function(args){ var arg = args.string; // get available commands by roll var availableCommands = controller.getAvailableCommands(); // for no argument if(!arg) { return [0, availableCommands]; } // make array of inputted words // and current input word shoud be last (dayone ?) var inputted = arg.toLowerCase().split(/\s+/); var current = inputted[inputted.length - 1]; // complete position is the top of last word var completePosition = arg.lastIndexOf(' ') + 1; // exclude inputted word from candidates var candidates = availableCommands.filter( function(commandSet) { for(var i=0, numofInputted=inputted.length ; i<numofInputted ; ++i) { if(commandSet[0] === inputted[i]){ inputted.splice(i, 1); return false; } } return true; }); // display all candidates in after space ' ' if(inputted[inputted.length - 1] !== current) { // complete position is the next of last space completePosition = arg.length + 1; return [completePosition, candidates]; } // return the set that start with current word var commands = candidates.filter( function(commandSet) { return (commandSet[0].indexOf(current) === 0); }); return [completePosition, commands]; }, } ); // for ex-command ------------------------------------------------------- // constants const MAX_LINE = { big: 16, medium: 25, small: 38, }; const EMSP = '\u3000'; const NBSP = '\u00a0'; const LF = '\u000a'; const PROPATIES_DEFAULT = { fixFlag: false, max : MAX_LINE['medium'], line : 1, size : '', }; const COMMAND_SEPARATOR = '|'; // functions function expandExCommand(arg) { var command, comment; // command and comment is separated by COMMAND_SEPARATOR var temp = arg.split(COMMAND_SEPARATOR); if(temp.length > 1) { command = temp.shift(); comment = temp.join(COMMAND_SEPARATOR); } else { comment = arg; } // ex_command is putted in braces if(comment.match(/^\{([^{}]+)\}(.+)/)) { var exCommand = RegExp.$1; var text = RegExp.$2; var properties = analysisExCommand(exCommand); // fine tune command about comment size if(properties.size) { if(command) { command = command.replace(/\s*big\s*/g, ' ') .replace(/\s*medium\s*/g, ' ') .replace(/\s*small\s*/g, ' '); } command += ' ' + properties.size; } // expand!! comment = buildLineBreakString(properties.line) + text; if(properties.fixFlag) { var post = buildLineBreakString(properties.max - properties.line + 1); comment += post + NBSP; } } return [command, comment]; } // "&nbsp;" and <LF> on each line function buildLineBreakString(numof) { // faster than string concatenate (+, +=) var string = Array(numof * 2); for(var i=1 ; i<numof ; ++i) { string.push(NBSP); string.push(LF); } return string.join(''); } // RegExp hell function analysisExCommand(exCommand) { // default set var properties = PROPATIES_DEFAULT; // fix or not if(exCommand.match(/\bfix\b/)) { properties.fixFlag = true; } // comment size and max line if(exCommand.match(/\b(big|medium|small)\b/)) { properties.size = RegExp.$1; properties.max = MAX_LINE[properties.size]; } else if(exCommand.match(/\bmax(\d+)\b/)) { properties.max = RegExp.$1; } // line if(exCommand.match(/\bline(-?\d+)\b/)) { var line = parseInt(RegExp.$1, 10); if(line < 0) line = properties.max + line + 1; if(line > properties.max) line = properties.max; properties.line = line; } return properties; } })(); // vim: set sw=4 ts=4 et;