vimperatorプラグイン書いた

すんません、前のブログに書いてた記事の転載です。
仕切り直しで投稿しますた。
※9/10 ちょいと描き直し
 はてな記法(?)のせいで一部のコードがでてなかったので修正。

※9/16
更新しました。 http://d.hatena.ne.jp/pekepekesamurai/20080916/1221581901

vimperator のプラグインをかいてみました。
http://anond.hatelabo.jp/20080826124641で、ローカルキーを使用可能にするプラグインがあったので、それの自分用改造版です。
(改造というより、ほぼ書き換えに近いですけど・・・笑)

※古いファイルをアップしていたので、アップし直し。
追加していた機能について記述を追記しました。
キー送信に関しては、実験的につけただけなので、あんまり動作しないかもです…

●追加するコマンド

togglelocalkeymode
ローカルキーの有効無効切り替え

●ローカルキーの設定方法。
.vimperatorrc に js で liberator.globalVariables.localKeyMappings に [ [url_regexp, [ [key, command/function],...], ...] の形式で指定する。

●設定例


" 起動時に LocalKeyMode を有効化
" (デフォルトは "false")
let g:localkeymode_enable = "true"

" ローカルキーの割り当て
javascript <<EOM
liberator.globalVariables.localKeyMappings=[
// ニコニコ動画用の例
['^http://www\.nicovideo\.jp/watch/', [
['p', ':nicopause'],
['m', ':nicomute'],
['v', ':nicommentvisible'],
['s', ':nicoseek! +10'],
['S', ':nicoseek! -10'],
['z', ':nicosize ', true],
['c', ':nicomment ', true], // true指定でコマンド入力欄を確定させない
['C', ':nicommand ', true],
] ],
// www.hoge.com の例
['^http://www\.hoge\.com/',[
['e', 'J'] // : をつけないと指定したキー(J)をウィンドウに送信します。
['q', 'd', true] // noremap ON で指定したキーを送信
] ],
];
EOM

●localkeymode.js


/**
* ==VimperatorPlugin==
* @name local key mode
* @description assign temporary usermodemap
* @description-ja 一時的なキーマップの割り当てを行います。
* @version 0.1b
* ==/VimperatorPlugin==
*
* Usage:
*
* :togglelocalkeymode
*
* 有効/無効のトグルです。(ステータスバーのアイコンクリックでも切り替え可能)
*
* .vimperatorrc
* g:localkeymode_enable : [true=有効/false=無効(デフォルト)]
*
* .vimperatorrrc 設定例:
* let g:localkeymode_enable = "true"
* javascript <<EOM
*
* liberator.globalVariables.localKeyMappings= //[ [url regexp, [ [key, command/function ] ,... ] ] , ... ]
* [
* ['^http://www\.nicovideo\.jp/watch/', [
* ['p', ':nicopause'],
* ['m', ':nicomute'],
* ['v', ':nicommentvisible'],
* ['s', ':nicoseek! +10'],
* ['S', ':nicoseek! -10'],
* ['z', ':nicosize ', true],
* ['c', ':nicomment ', true],
* ['C', ':nicommand ', true],
* ['t', function(){alert('test');}],
* ] ],
* ['^http://www\.hoge\.com/', [
* ['e', '<C-v> ?', true],
* ['q', 'd', true],
* ],
* // ['', [
* // ['', ],
* // ],
* ];
* EOM
*
* 備考:
* *
*/
(function(){

const DISABLE_ICON = 'data:image/png;base64,'
+'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEUAAAABAQECAgIDAwMEBAQF'
+'BQUGBgYHBwcICAgJCQkKCgoLCwsMDAwNDQ0ODg4PDw8QEBARERESEhITExMUFBQVFRUWFhYXFxcY'
+'GBgZGRkaGhobGxscHBwdHR0eHh4fHx8gICAhISEiIiIjIyMkJCQlJSUmJiYnJycoKCgpKSkqKior'
+'KyssLCwtLS0uLi4vLy8wMDAxMTEyMjIzMzM0NDQ1NTU2NjY3Nzc4ODg5OTk6Ojo7Ozs8PDw9PT0+'
+'Pj4/Pz9AQEBBQUFCQkJDQ0NERERFRUVGRkZHR0dISEhJSUlKSkpLS0tMTExNTU1OTk5PT09QUFBR'
+'UVFSUlJTU1NUVFRVVVVWVlZXV1dYWFhZWVlaWlpbW1tcXFxdXV1eXl5fX19gYGBhYWFiYmJjY2Nk'
+'ZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5vb29wcHBxcXFycnJzc3N0dHR1dXV2dnZ3'
+'d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+AgICBgYGCgoKDg4OEhISFhYWGhoaHh4eIiIiJiYmK'
+'ioqLi4uMjIyNjY2Ojo6Pj4+QkJCRkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZmampqbm5ucnJyd'
+'nZ2enp6fn5+goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6+w'
+'sLCxsbGysrKzs7O0tLS1tbW2tra3t7e4uLi5ubm6urq7u7u8vLy9vb2+vr6/v7/AwMDBwcHCwsLD'
+'w8PExMTFxcXGxsbHx8fIyMjJycnKysrLy8vMzMzNzc3Ozs7Pz8/Q0NDR0dHS0tLT09PU1NTV1dXW'
+'1tbX19fY2NjZ2dna2trb29vc3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp'
+'6enq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8'
+'/Pz9/f3+/v7////isF19AAAAPElEQVR4nGNYgwYYsAv8/48Q6AeB///7YQBToAkE/v9vggFMgRIQ'
+'+P+/BAYwBQibgcsdEAASmIsGCAsAAE8ZnUuRMbA8AAAAAElFTkSuQmCC';

const ENABLE_ICON = 'data:image/png;base64,'
+'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAa0lEQVR4nGP0+OzAQApgIkk1Fg3b'
+'efZv59mPRwMjwycU/n/e/wwMDIyfGanmJBaG16gCvAwMDAzogpTZ8AJVQImBgYEBXZAyGySwCWMV'
+'JNcGUWzCWAWhGrABSPQhA3hUMvo9Js1JFCc+ggAAYtsQ+fmaz5UAAAAASUVORK5CYII=';

const isCmdRegExp = /^:/;

var _isEnable;
var _isLocalKeyBinding = false;

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

var LocalKeyMode = new Class();
LocalKeyMode.prototype = {
initialize: function() {
this.storekeymaps = [];
this.delkeychars = [];
this.localkeymaps = [];

var global = liberator.globalVariables;
this.panel = this.setupStatusBar();
this.isEnable = global.localkeymode_enable != undefined ? window.eval(global.localkeymode_enable) : false;
this.setupEnvironment();
this.initLocalKeyMap();
},
setupStatusBar: function() {
var self = this;
var panel = document.createElement('statusbarpanel');
panel.setAttribute('id','localkeymode-status');
panel.setAttribute('class','statusbarpanel-iconic');
panel.setAttribute('src', self.isEnable ? ENABLE_ICON : DISABLE_ICON);
panel.addEventListener('click', function(e){ self.isEnable = !self.isEnable; },false);
document.getElementById('status-bar').insertBefore(panel, document.getElementById('security-button').nextSibling);
return panel;
},
get isEnable(){
return _isEnable;
},
set isEnable(value){
this.panel.setAttribute('src', value ? ENABLE_ICON : DISABLE_ICON);
_isEnable = value;
},
initLocalKeyMap: function(){
if (liberator.globalVariables.localKeyMappings == undefined ) return;
var list = liberator.globalVariables.localKeyMappings;
if (!list) return;
for (var i=0; i<list.length; i++){
let item=list[i];
if (!item[0] || !item[1]) continue;
this.addLocalKeyMap(item[0], item[1]);
}
},
addLocalKeyMap: function( uri, items ) {
if (!uri) return;
var keymaps = [];
for ( var i=0; i<items.length ;i++){
if (items[i].length < 1 || !items[i][0] || !items[i][1]) continue;
var command = items[i][1];
var extend = items[i].length>=3 && items[i][2] ? true : false;
if (typeof command != 'function') {
if (isCmdRegExp.test(command)){
if (extend) command = new Function( 'liberator.commandline.open("","'+command+'",liberator.modes.EX);');
else command = new Function( 'liberator.execute("'+command+'");' );
} else {
command = new Function('liberator.events.feedkeys("'+command+'" ,'+extend+');');
//command = new Function('"'+command+'".split(" ").forEach(function(keys){liberator.events.feedkeys( keys,'+extend+');});');
}
}

keymaps.push( new Array( items[i][0], command ) );
}
this.localkeymaps.push( { uri:new RegExp(uri,'i'), key:keymaps } );
},
loadKeyMap: function() {
if (_isLocalKeyBinding) this.restoreKeyMap();
if (!this.isEnable) return;
for (var i=0; i<this.localkeymaps.length; i++) {
var keymap = this.localkeymaps[i];
if (content.location.href.match(keymap.uri)) {
for (var j=0; j<keymap.key.length ;j++){
let key = keymap.key[j][0];
let action = keymap.key[j][1];
let org = liberator.mappings.get( liberator.modes.NORMAL, key);
if (org) this.storekeymaps.push( new Map(org.modes, org.names, org.description, org.action,{flags:org.flags, rhs: org.rhs, noremap:org.noremap}) );
else this.delkeychars.push( key );

liberator.mappings.addUserMap([liberator.modes.NORMAL], [key], 'localkeymap', action ,{rhs: key, noremap:true});
}
_isLocalKeyBinding = true;
break;
}
}
},
restoreKeyMap: function() {
if (_isLocalKeyBinding){
for (; 0 < this.storekeymaps.length; ) {
var m = this.storekeymaps[0];
liberator.mappings.addUserMap([liberator.modes.NORMAL], m.names, m.description, m.action, {flags:m.flags, rhs: m.rhs, noremap: m.noremap});
this.storekeymaps.shift();
}
for (; 0 < this.delkeychars.length; ) {
liberator.mappings.remove( liberator.modes.NORMAL, this.delkeychars[0] );
this.delkeychars.shift();
}
_isLocalKeyBinding = false;
}
},
setupEnvironment: function() {
var self = this;
liberator.commands.addUserCommand(["togglelocalkeymode"], "Toggle Local/Global Key Mapping",
function() {
self.isEnable = !self.isEnable;
self.loadKeyMap();
}, {} );
},
};

liberator.plugins.LocalKeyMode = new LocalKeyMode();
autocommands.add('LocationChange', '.*', 'js liberator.plugins.LocalKeyMode.loadKeyMap();');
})();