vimperator2.2のCSSに関するコマンド、JavaScript関数をまとめた。
参考情報
ヘルプ chrome://liberator/locale/styling.html
CSSに関する処理を記述したvimperator本体のソースファイル common/content/style.js
CSSに関して、colorscheme, highlight, styleという3つのコマンドがある。
vimperatorの内部においては、CSSに関して、StylesとHighlightsという2つのクラスが存在する。
このエントリでは、前者が受け持つ機能をスタイル、後者が受け持つ機能をハイライトと呼称する。
| colorscheme | 設定ファイルを読み込むコマンド | スタイルとハイライトを設定 |
| highlight | highlight属性のついた要素に対して、CSSで装飾するコマンド | ハイライトを設定 |
| style | URLごとのCSS設定、ブラウザのCSS設定を行うコマンド | スタイルを設定 |
ちなみに、sourceコマンドを用いてcssファイルを読み込むことも出来る。
source ~/vimperator/colors/xulstyle.css
ただし、一度設定したCSSをデフォルトに戻したり、異なるCSSファイルに差し替えたりするのには向かない。
sourceコマンドを使うよりも、colorscheme, highlight, styleコマンドを利用したほうが良いと思う。
では、その3つのコマンドを説明していく。
スタイル設定を記述したファイルを読み込む。
:colo hoge // 'runtimepath'(pluginディレクトリなどのあるディレクトリ)下のcolors/hoge.vimpが読み込まれる。
colorscheme設定ファイルの書式
/lang/javascript/vimperator-plugins/trunk/colors – CodeRepos::Share – Trac
http://coderepos.org/share/browser/lang/javascript/vimperator-plugins/trunk/colors?order=date&desc=1
vimperatorrcと同じ書式で書く。基本的に、hilightコマンド、styleコマンドを並べて書く。
オートコマンド
colorschemeが読み込み終わると、ColorSchemeオートコマンドが呼ばれる。
ハイライトの消去
:colo[rscheme] default
これでハイライトはデフォルトに戻る。このコマンドでは、スタイルのデフォルト化は出来ない。
highlight属性のついた要素に対して、CSSで装飾する。
:hi[ghlight][!] [-append] {group} [[{selector}] {css}]
{group}には、TabClose, CmdLine, StatusLine, Hint, Functionなどの決まった文字列を用いる。これはhighlight属性値にあたる。
グループの一覧→chrome://liberator/locale/styling.html#%3Ahi
本エントリ末尾のおまけも参照。
{selector}は省略できる。
appendオプション
-appendまたは-aをつけると、CSSを上書きせずに追加できる(-appendが無いと上書きする)。
:hi CmdLine -append font-size: 16px // コマンドラインの文字サイズを指定できる。
ハイライトの一覧表示
{selector}, {css}を略すと、その{group}にセットされているハイライトをリストアップできる。
この時、{group}は部分的に一致していてもマッチされる。
:hi Number // Number, TabNumber, TabIconNumberという3つのグループに割り当てられているハイライトが表示される。
ハイライトの除去
:hi[ghlight] clear {group} {selector} // ハイライトを消去しデフォルト値に戻す。
highlightコマンドではhereDoc(ヒアドキュメント)を利用できる。
:hi CmdLine<<E font-size: 18px; E
ブラウザやページにスタイルを追加する。
:sty[le][!] [-name={name}] [-append] {filter} [{css}]
{filter}について
コンマ区切りでURLを指定。cssはセレクタとCSS本体を合わせたもの。http://は書かない。
styleコマンドをファイルに書いて、colorschemeコマンドで読み込むことが出来る。ファイルの拡張子は.vimpにする。
ファイル内で複数行にわたって書きたい時は次のように記述する。
style mixi.jp <<EOM
.adBanner{ visibility: hidden !important }
#adBanner, #prContentsArea, #mixiRadioArea, #calendar, #prSepecial{ display: none !important }
EOM
ちなみに、vimperatorrcにもこのような記述が可能だが、vimperatorrcには出来れば記述せずに、
CSSのファイルはCSSのファイルだけでまとめたほうが良いと思う。
スタイルの命名
-nameまたは-nオプションにより、スタイルに名前をつけられる。
既存のスタイルの名前を指定すると、上書きされる。
上書きをせずに、既存のスタイルに追加するには、-appendオプションを使う。
スタイルの一覧
:sty[le] // 全てのスタイルの一覧
:sty[le] {filter} // {filter}に対するスタイルの一覧
この時に各スタイルに付いているindexを確認できる。
styleコマンドでも、hereDocを利用できる。
スタイルの消去
:dels[tyle] [-name={name}] [-index={index}] [{filter}] [{css}]
名前を指定する、またはスタイルのindexを指定する。
スタイルの無効、有効、トグル
:styled[isable] :styee[nable] :stylet[oggle]
引数はdels[tyle]と同じ。
グローバル変数highight, stylesが、ハイライトとスタイルに関するAPIである。
以下では、これらの持つメソッドその他を見ていく。
ハイライトを取得する。classはコマンドの項目で登場した{group}にあたる。
:hi CmdLine -a font-size: 18px
:ec highlight.get('CmdLine')
↓
class: "CmdLine" default: "font-family: monospace; padding: 1px;" filter: "chrome://liberator/content/buffer.xhtml,chrome://browser/content/browser.xul" selector: "[liberator|highlight~=CmdLine]>*" value: "font-family: monospace; padding: 1px; font-size: 18px;"
ハイライトをセットする。
指定したクラスのセレクタを得る。
:ec highlight.selector('CmdLine')
↓
[liberator|highlight~=CmdLine]
ハイライトをリセットする。
ハイライトのCSSを読み込む。highlightコマンドとは違って、上書きを阻止できないみたい。
highlight.loadCSS('CmdLine font-size: 30px') // コマンドラインの文字が大きくなる。
// highlight.loadCSS('-a CmdLine font-size: 30px') // これでは動かなかった。
このloadCSSは、上書きを阻止できないどころか、デフォルトのCSSまでも書き換えるらしい。
:ec highlight.get('CmdLine').default // font-size: 30pxと表示される。デフォルトで設定されていたfont-familyやpaddingは上書きされた。
ちなみに、vimperatorの起動時(style.js内でのhighlightオブジェクト作成時)に
this.loadCSS(this.CSS);
が実行される。このthis.CSSは次で説明する。
グループ名の一覧とそれらに割り当てられたデフォルトのCSSについて書かれた1つの長い文字列。
これをパースすれば、グループ名の一覧を簡単に取得できるはず。(もっと簡単な方法があるかも)
ユーザ定義のスタイル(sheetと呼ぶ)の配列をIterator()で包んだもの。
:ec var str = ''; for(let [, v] in styles.userSheets){ str += [v.id, v.name, v.sites, v.css].join(' | ') + '\n';} log(str);
デフォルトのsheetsをIterator()で包んだもの。
スタイル名をインデックスにしたオブジェクトをIterator()で包んだもの。
:ec var str = ''; for(let [k, ] in styles.userNames){ str += k + '\n';} al(str); // ユーザ定義で、名前のついたスタイルの名前を一覧表示。
sheet(スタイル)を追加する。
system引数は、デフォルトのスタイルかどうかを指定する論理値。
name引数は、スタイル名。
filter引数は、前述のstyleコマンドの{filter}引数と同じで、スタイルを適用するURLのフィルター(文字列)。
css引数は、セレクタとCSS本体からなる。複数のCSSを指定できる。
// vimperatorグループの文字サイズが大きくなり、ヘッダが見えなくなるスタイル。 styles.addSheet(0, 'test', 'vimperator\.g\.hatena\.ne\.jp', '*{ font-size: 20px } #simple-header{ display: none }')
:styletoggle -name test
とすれば、スタイルの有効/無効が切り替わる。
スタイル(sheet)を得るメソッド。identifierには、スタイルのindexまたはスタイル名を指定する。
sheetオブジェクトには、agent, css, id, name, sites, systemというプロパティがある。
styles.get(0, 'test'); // 先ほど作成したtestスタイルのオブジェクトを得る。
引数名は、これまでと同様の意味。getメソッドと違って、複数のスタイルを得る。
戻り値は、sheetオブジェクトの配列。
引数名は、これまでと同様。filterが指定された時はマッチする全てのスタイル(sheet)を削除する。
与えられたCSSのURIに対して、スタイルを登録する。reloadがtrueなら、既存のスタイルをリロードする。
sourceコマンドでCSSファイルをロードできるのも、このメソッドによる。
内部的にはnsIStyleSheetServiceが使われている。
const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
Using the Stylesheet Service - MDC
https://developer.mozilla.org/en/Using_the_Stylesheet_Service
登録していたCSSを解除する。
ハイライトがvimperator本体で使われている箇所(ソースファイルをhighlight=で検索)。
基本的に、echoする時や補完候補などを表示する時か、タブやページ要素にスタイルを与える時にハイライトが使われている。
以下のリストの大文字から始まる単語は、highlight属性値(CmdLineなど)にあたる。
:ec commandline.echo('<span highlight="Number">12345</span>', null, commandline.FORCE_MULTILINE) // デフォルトでは青だが:hi Number -a color: redとすると赤に。
追記 2010/03/07 12:19:52
vimperator2.2のdels[tyle]が動作していないかもしれない。
action: function (sheet) styles.removeSheet(sheet)
ではなく
action: function (sheet) styles.removeSheet(false, sheet.name)
が正しいのでは。
Re: vimperatorrcでキーコードを指定してmapする - hogelogの日記 - vimperatorグループ
http://vimperator.g.hatena.ne.jp/hogelog/20090510/1241970179
の方法がvimp2.2では使えなかったので、自分で書いた。既出かも。
ちなみにvimp2.2リリース以降のnightlyは未試用。
コード
// extraKeysForMapping.js { const extra_keys = [ [ 28, ["Henkan"]], [ 29, ["Muhenkan"]], [ 242, ["Katakana"]], [ 240, ["CapsLock", "Caps"]] ]; let [_code_key, _key_code] = liberator.eval('[code_key, key_code]', events.destroy); extra_keys.forEach(function([code, names]){ _code_key[code] = names[0]; for(let [, name] in Iterator(names)) _key_code[name.toLowerCase()] = code; }); let extra = uneval([_code_key, _key_code]); liberator.eval('[code_key, key_code] = ' + extra, events.destroy); }
動作
map <C-Caps> :js alert('ok')<CR> // Ctrl+CapsLockを入力した時に、'ok'というアラートが表示されるようになる unmap <C-CapsLock> map <C-Caps><C-Caps> :js alert('successful')<CR> // Ctrl+CapsLockを二回入力した時に、'successful'というアラートが表示されるようになる map <C-Caps>foo :js alert('foo')<CR> // 同様
firefox標準のpromptだと複数行入力できないので作った。
このメソッドを実行すると、テキストエリアが出現する。
テキストを入力してOKボタンを押すと、テキスト内容を引数にしてコールバックが実行される。
空のページで実行しないと表示がおかしくなる可能性がある。
ページ内にpromptを作ると、ページのCSSに左右されるデメリットがある。新しいミニウィンドウにpromptを作ると、読み込みに時間がかかるデメリットがある。
新しいタブにpromptを作るのは表示してたページが見えなくなってしまうデメリットがある。
サイドバーにpromptを作るのは横幅が通常は狭いデメリットがある。スマートな方法はないか?
// 複数行入力可能なプロンプトを出す。 util.openMultilinePrompt = function(callback, title, defaultVal, rows, cols, top, left){ var thisMethodName = 'util.openMultilinePrompt'; var rows = rows || 20; var cols = cols || 50; var _top = parseInt(top) || 50; var _left = parseInt(left) || 50; var defaultVal = defaultVal || ''; var html = '<div id="' + thisMethodName + '_div">' + '<h2>' + (title ? title + '<br/>': '') + '</h2>' + '<textarea id="' + thisMethodName + '_textarea" rows="' + rows + '" cols="' + cols + '"></textarea>' + '<br/>' + '<input id="' + thisMethodName + '_submit" type="button" value="ok"/>' +'</div>'; var div = content.document.createElement('div'); div.innerHTML = html; div.id = 'multilinePrompt'; div.style.opacity = '0.85'; div.style.position = 'fixed'; div.style.top = _top + 'px'; div.style.left = _left + 'px'; content.document.body.appendChild(div); var textarea = content.document.getElementById(thisMethodName + '_textarea'); textarea.focus(); textarea.value = defaultVal; var button = content.document.getElementById(thisMethodName + '_submit'); var submit = function(){ callback( textarea.value ); div.parentNode.removeChild(div); button.removeEventListener('click', submit, false); mappings.remove(modes.INSERT, '<Esc>'); }; button.addEventListener( 'click', submit, false ); mappings.addUserMap([modes.INSERT], ['<Esc>'], 'Esc for ' + thisMethodName, function(){ div.parentNode.removeChild(div); button.removeEventListener('click', submit, false); mappings.remove(modes.INSERT, '<Esc>'); modes.reset(); }); };
利用例
ブックマークを検索し、一覧され、選択し、編集して、確定すると、登録されるコマンド。
複数行の編集エリアなのでbookmarkletの編集がしやすくなった。
bookmarks.addByObj = function(o, starOnly){ var success = bookmarks.add(starOnly || false, o.title, o.url, o.keyword, o.tags); return success; }; String.prototype.fromUTF8Octets = function(){ return decodeURIComponent( this.replace(/[%\x80-\xFF]/g, function(c)'%' + c.charCodeAt(0).toString(16)) ); }; commands.addUserCommand( ['editBookmark'],'Edit Bookmark in Multi Line',function(args){ var bookmarkToText = function(bm){ var url = bm.url.replace(/;/g, ';\n'); return [bm.title, bm.keyword, bm.tags.join(','), url].join('\n'); } // edit and add bookmark var editBookmark = function(value, oldurl){ var addBookmark = function(str){ var obj = {}; var lines = str.split('\n'); var url = lines.splice(3).join(''); var [title, keyword, tags] = lines; tags = tags.split(/,\s*/g); obj.title = title; obj.keyword = keyword; obj.tags = tags; obj.url = url; var success = bookmarks.addByObj(obj); if(success) bookmarks.remove(oldurl); }; util.openMultilinePrompt( addBookmark, '1,2,3行目と4行目以降にそれぞれtitle, keyword, tags, urlを書く'.fromUTF8Octets(), value, 25, 90 ); }; // get bookmarks var filter = args[0] == '0' ? '': args[0]; var tags = []; if(args.length == 2) tags = args[1].split(','); else tags = args.splice(1); var bms = bookmarks.get(filter, tags); if(bms.length > 50){ liberator.echoerr('Too much tags to display'); return; } if(bms.length == 1){ editBookmark(bookmarkToText(bms[0]), bms[0].url); return; } // select bookmark var cursorPos = 0; var box = <div></div> // bmのキー: icon, id, keyword, title, url, tags bms.forEach(function(bm){ var iconURL = bm['icon'].match(/.*?(((http|https|chrome):\/\/|data:image\/).+)/)[1] || ''; var keyword = bm.keyword || ' - '; var tags = bm.tags.join(',') || ' - '; box.* += <><div class="matchedBookmark" style="padding:20px"> <p style="font-size:18px"><b>{bm['title']}</b></p> <p><img src={iconURL}/> {bm['url']}</p> <p>#keyword# {keyword}, #tags# {tags}</p> </div></>; }); box.@style = 'padding: 20px; height: 520; font-size:12px'; var wid = plugins.makeFloatWidget(box, 520, 800, 120, 30, 'white'); var div = wid.ref; var divs = div.getElementsByClassName('matchedBookmark'); divs[0].style.backgroundColor = '#cff'; div.style.overflow = 'scroll'; wid.selectThis(); wid.addKeyEvent(['j'], 'move next', function(){ var nextPos = cursorPos + 1; if(nextPos == divs.length) nextPos = 0; divs[cursorPos].style.backgroundColor = ''; divs[nextPos].style.backgroundColor = '#cff'; divs[nextPos].scrollIntoView(); cursorPos = nextPos; }); wid.addKeyEvent(['k'], 'move previous', function(){ let nextPos = cursorPos - 1; if(nextPos == -1) nextPos = divs.length - 1; divs[cursorPos].style.backgroundColor = ''; divs[nextPos].style.backgroundColor = '#cff'; divs[nextPos].scrollIntoView(); cursorPos = nextPos; }); wid.addKeyEvent(['D'], 'delete bookmark', function(){ bookmark.remove(bms[cursorPos].url); }); wid.addKeyEvent(['o'], 'edit this bookmark', function(){ wid.destroy(); var bm = bms[cursorPos]; editBookmark(bookmarkToText(bm), bm.url); }); },{},true );
ウィジェットを作るためのプラグインを改良した - vimpめも - vimperatorグループのプラグインを使用。
追記 2010/03/05 11:41:15
複数行入力可能にしたい時は、commandのextraInfo.hereDocがtrueなコマンドを定義すれば良いと気付いた。
commandline.inputMultiline(untilRegExp, callbackFunc)を使う手もある。
追記
外部エディタを使う方法もあった。
コマンドラインを外部エディタで編集 - Death to false Web browser! - vimperatorグループ
http://vimperator.g.hatena.ne.jp/nokturnalmortum/20100304/1267718311
デフォルトのFirefoxでは、タブ変更してもフォーカスの状態は保持される。
ところで、vimperatorのインサートモードにおいて、タブ変更を行うには、
<Esc><C-n>
といった操作を行う必要があり、少し面倒である。これを回避するには、
inoremap <C-n> <Esc><C-n>
とするのが一般的だと思う。
しかし、いずれにせよ、vimperatorでこうした設定を行えば、タブ変更時にテキスト入力エリアのフォーカス状態が保持されなくなる。
なぜなら、Escの実行によってインサートモードを脱出しているから。
これは、複数のタブを行き来しながら、テキストを入力していく時には、大きな問題となる。
例えば、あるタブで情報を見ながら、別のタブでそれに関するブログを書いている時に、ブログのタブに戻るたびに、入力エリアにフォーカスする必要が生じる。
そこで、
という2つの要求をかなえる設定を考えた。
_vimperatorrcの記述
" C-1, ..., C-9, C-n, C-p, C-t in the INSERT mode js <<EOM { for(let i = 0; i < 10; i++){ mappings.addUserMap([modes.INSERT], ['<C-' + i + '>'], 'tab operation - keep tabs INSERT', function(){ mappings.get(1, i + 'gt').execute(); }); } [ ['t', 'tabopen'], ['n', 'tabnext'], ['p', 'tabprevious'] ].forEach(function([c, cmd]){ mappings.addUserMap([modes.INSERT], ['<C-' + c + '>'], 'tab operation - keep tabs INSERT', function(){ liberator.execute(cmd); }); }); } EOM
ちなみに、インサートモードの時に他のタブをクリックした場合には、Escを実行しないので、
このような設定をせずとも、フォーカス状態を保持したままのタブ遷移が行える。
追記 2010/02/25 23:28:20
INSERT(menu) なモードでキーバインドが聞かない問題にたいする Hack - Death to false Web browser! - vimperatorグループ
の設定に伴って
inoremap <C-n> <Down> inoremap <C-p> <Up>
と設定している場合は、C-n, C-pがバッティングしてしまう。
そこで、次のように変更したところ、うまく共存できた。
window.addEventListener( 'keypress', function (event) { if (liberator.mode === modes.INSERT && modes.extended === modes.MENU) { let key = events.toString(event); if(key == '<C-n>' || key == '<C-p>'){ event.preventDefault(); event.stopPropagation(); } if(key == '<C-n>'){ events.feedkeys('<Down>'); return; }else if(key == '<C-p>'){ events.feedkeys('<Up>'); return; } let map = mappings.get(modes.INSERT, key); if (map) { event.preventDefault(); event.stopPropagation(); map.execute(); } } }, false );
以前から、プラグイン制作をしている時などに、開いているタブの情報を管理できたら便利だと思っていたので、作った。
機能
注意点
使い方
tabs.tabsinfo.length // 開いているタブの数 (tabs.countと等しい) // 左から2番目のタブにいるとする。 // 現在のタブのデータオブジェクトにキー:'hoge', 値:100を登録する。 tabs.setinfo(null, 'hoge', 100); // 5番目のタブに移動したとする。 // 2番目のタブのデータオブジェクトの'hoge'の値を得るには次のようにする。 tabs.getinfo(2)['hoge'] // 100 // 5番目のタブにいながら、3番目のタブに情報を追加する。 tabs.setinfo(3, 'fuga', 200); // 3番目のタブに移動したとする。 // 引数無しでgetinfoを呼び出しても、現在のタブの情報を取得できる。 tabs.getinfo()['fuga'] // 200 // ContentWindowオブジェクトも引数にとれる。 tabs.getinfo(content)['fuga'] // 200
おまけの使い方
// 新しいタブが開かれた時に、新しいタブのURLをアラートする。addEventはイベントハンドラを返す。イベント名は'TabOpen'でも'open'でも良い。 var handler=tabs.addEvent('open', function(event){ alert(event.target.linkedBrowser.contentWindow.location) }, false); // 従来なら、 // var handler = function(event){ alert(event.target.linkedBrowser.contentWindow.location) }; // gBrowser.tabContainer.addEventListener('TabOpen', handler, false); // と書くところ。 // イベントハンドラを除去する。従来の方法で登録したものも除去できる。 tabs.removeEvent('open', handler, false)
// tabsinfo.js { var contentwins = []; // [contentwin, infoObj]の配列。 tabs.__defineGetter__('tabsinfo', function(){ return contentwins; }); let getContentWindows = function(aTabBrowser) { let contentwins = []; let result = aTabBrowser.ownerDocument.evaluate( 'descendant::*[local-name()="tab"]', aTabBrowser.mTabContainer, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for(let i = 0, L = result.snapshotLength; i < L; i++) contentwins.push(gBrowser.getBrowserForTab(result.snapshotItem(i)).contentWindow); return contentwins; } // argは数字(tabindex)またはContentWindowオブジェクトまたはundefined let getinfo = function(arg){ function echoError(){ liberator.echoerr('illegal arg for tabs.getinfo'); } if(typeof arg == 'number'){ let tab; try{ tab = tabs.getTab(arg - 1); }catch(e){ echoError(); return null; } if(tab === undefined){ echoError(); return null; } arg = tab.linkedBrowser.contentWindow; } if( (arg instanceof Window && arg.document.body) || arg === undefined ){ arg = arg || content; for(let i = 0, L = contentwins.length; i < L; i++){ if(contentwins[i][0] == arg) return contentwins[i][1]; // 正しい引数の時の戻り値 } return null; }else{ echoError(); return null; } }; tabs.getinfo = getinfo; let setinfo = function(arg, key, value){ function echoError(){ liberator.echoerr('illegal arg for tabs.setinfo'); } if(typeof arg == 'number'){ let tab; try{ tab = tabs.getTab(arg - 1); }catch(e){ echoError(); return; } if(tab === undefined){ echoError(); return; } arg = tab.linkedBrowser.contentWindow; } if( (arg instanceof Window && arg.document.body) || arg == null ){ arg = arg || content; for(let i = 0, L = contentwins.length; i < L; i++){ if(contentwins[i][0] == arg){ contentwins[i][1][key] = value; // 正しい引数の時の動作 return; } } return; }else{ echoError(); return; } }; tabs.setinfo = setinfo; // 起動時に全てのタブをcontentwinsに格納する var startListener = function(){ contentwins = getContentWindows(gBrowser).map(function(cwin) [cwin, {}]); }; autocommands.add('VimperatorEnter', '.*', 'js liberator.plugins.tabsinfo.startListener()'); //let tabChangeListener = function(event){ // let newContentwin = event.target.contentWindow; // let oldContentwin = tabs.alternate.linkedBrowser.contentWindow; //}; //document.addEventListener('TabSelect', tabChangeListener, false); let tabOpenListener = function(event){ let contentwin = event.target.linkedBrowser.contentWindow; contentwins.push([contentwin, {}]); }; gBrowser.tabContainer.addEventListener('TabOpen', tabOpenListener, false); let tabCloseListener = function(event){ let lastContentWin = event.target.contentWindow; contentwins = contentwins.filter(function(cwin) cwin[0] != lastContentWin); }; document.addEventListener('TabClose', tabCloseListener, false); tabs.addEvent = function(type, listener, useCapture){ switch(type){ case 'TabSelect': case 'select': document.addEventListener('TabSelect', listener, useCapture); return listener; break; case 'TabOpenPre': case 'openpre': document.addEventListener('TabOpen', listener, useCapture); return listener; break; case 'TabOpen': case 'open': //event.target.linkedBrowser.contentWindow: 新しいタブのcontentwin gBrowser.tabContainer.addEventListener('TabOpen', listener, useCapture); return listener; break; case 'TabClose': case 'close': document.addEventListener('TabClose', listener, useCapture); return listener; break; } }; tabs.removeEvent = function(type, listener, useCapture){ switch(type){ case 'TabSelect': case 'select': document.removeEventListener('TabSelect', listener, useCapture); break; case 'TabClose': case 'close': document.removeEventListener('TabClose', listener, useCapture); break; case 'OpenPre': case 'openpre': document.removeEventListener('TabOpen', listener, useCapture); break; case 'TabOpen': case 'open': gBrowser.tabContainer.removeEventListener('TabOpen', listener, useCapture); break; } }; }
追記 2010/02/26 01:52:48
tabs.browserが各タブのbrowser要素を生成するジェネレータになっていることに気付いた。これを利用したほうが良かったかも。
js var br=tabs.browsers; var ar=[]; try{ while(1) ar.push(br.next()[1].contentWindow.location); }catch(e){} alert(ar.join('\n')); // 全てのタブのURLを表示
ジェネレータについて
New in JavaScript 1.7 - MDC
https://developer.mozilla.org/en/New_in_JavaScript_1.7#Generators_and_iterators
New in JavaScript 1.8 - MDC
https://developer.mozilla.org/en/New_in_JavaScript_1.8#Generator_expressions
追記 2010/03/04
tabs.getTab(index).linkedBrowser.contentWindowでi番目のタブのcontentWindowを取ってこれることに気付いた。
上のコードはかなり冗長で無駄骨だった。
tabs.getTab()で現在のタブが取れる。
最近vimperatorをいじっていなかったので、作法におかしな所があるかも。
commands.addUserCommand( ['insertDate'],'Insert Date String',function(args){ //一桁なら0をつける function convertTimeStringHelper(mo, d, h, m, s){ return [mo, d, h, m, s].map(function(t){ t = String(t); if(t.length == 1) t = '0' + t; return t; }); } //現在時刻を"yy/mm/dd hh:mm:ss"に加工する var now = new Date(); var [y, mo, d, h, m, s] = [now.getFullYear(), now.getMonth() + 1, now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds()]; [mo, d, h, m, s] = convertTimeStringHelper(mo, d, h, m, s); now = [y, mo, d].join('/') + ' ' + [h, m, s].join(':'); util.copyToClipboard(now, true); editor.pasteClipboard(); },{},true );
使い方
上のコマンドに適当なマッピングを割り当てる。例えば、次のようなものをvimperatorrcに記述。
" insert date string js <<EOM mappings.addUserMap([modes.INSERT], ['<C-d>d'], 'Insert Date String', function(){ liberator.execute('insertDate', null, true); }); EOM
インサートモードでは、通常のa-zA-Zなどのキーは文字入力に用いられるので、最初のキーは<C-d>のようなCtrl, Altのついたキーにする。
動作
インサートモードの時に、
<C-d>d
と入力すると、日付時刻が挿入される。
2009/12/30 02:39:28
ただし、OSの時計をjavascriptで取ってきているので、実際の時刻と比べて多少の誤差がある可能性がある。
追記
1/16
秒数が一桁の場合に十の位のゼロが表示されない問題を修正
inoremap <C-d>d :insertDate<CR>
で良いのではないでしょうか