Extentsion開発日誌:XBLに手を出す
めずらしく長続きしてモチベーションが衰えることなく開発中。経緯とか何を作っているかはhogehoge - Extension開発中を見てちょ。
UI向上のためにtextboxがフォーカスされている時にCtrl + SPACEでメニューを出したくなっただが、onkeypress
でイベントを取ってキーコードがどうたらとかが面倒だったのでXBLに手を出してみた。
XBL
あたりを参考にした。
<?xml version="1.0" encoding="utf-8"?> <bindings xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <binding id="editorbox" extends="chrome://global/content/bindings/textbox.xml#textarea"> <handlers> <handler event="keypress" modifiers="control" key=" "><![CDATA[ var menu = document.getElementById('editToolsPopup'); menu.showPopup(this,this.boxObject.screenX,this.boxObject.screenY,"popup",null,null); ]]></handler> </handlers> </binding> </bindings>
Ctrl + SPACEのkeypress
イベントが発生すると後述のXULのpopup要素がポップアップされる。既存のXBLも継承するためにDOM Inspectorで調べてextends属性も追加しておく。
最初、keycode="VK_SPACE"
で取ろうとしていたが何度やってもイベントを取れないので闇雲にkey=" "
でやってみたら何故か取れた。SPACEは特殊キーだと思ってわざわざVK_SPACE
でやっていたオイラは一体....。
本当はポップアップメニューの位置をマウス位置にしたかったけど、keypress
のイベントではどうも位置を取れないようで諦めた。
XULの一部
<popup id="editToolsPopup"> <menuitem label="Order List" class="heAddOL" accesskey="o" oncommand="editSelection('+');"/> <menuitem label="Unorder List" class="heAddUL" accesskey="u" oncommand="editSelection('-');"/> <menuitem label="Add Date" class="heAddDate" accesskey="d" oncommand="editSelection('date');"/> <menuitem label="Add Time" class="heAddTime" accesskey="t" oncommand="editSelection('time');"/> </popup> ... <textbox id="hatena-edit" multiline="true" flex="1"/>
editSelection(hoge);
はフォーム中のカーソル位置を取得し、行頭に+やら-を追加するJavaScript関数。
それぞれにaccesskey
を割り当てる。これでCtrl + SPACE,oで行頭に+
が追加されると言う具合。
CSSの一部
あとはCSSでバインドしておけばOK。
#hatena-edit { -moz-binding: url(chrome://hatenaeditor/content/textbox.xml#editorbox); }
JavaScriptの一部
editSelection(hoge);
の中身。Firefoxのみを考えれば良いからテキストボックス中のカーソル位置とかの取得が楽チンだね。
var edit = document.getElementById('hatena-edit'); ...(省略)... function editSelection( str ) { var text = edit.value; var start = edit.selectionStart; var end = edit.selectionEnd; var startText = text.substring(0, start); var endText = text.substring(end, text.length ); var sel = text.substring( start, end); switch ( str ) { case '-': case '+': if ( start == end ) { var startLine = startText.split('\n'); var endLine = endText.split('\n'); var currentLine = str + startLine.pop() + endLine.shift(); edit.value = startLine.concat( currentLine, endLine).join('\n'); } else { edit.value = [ startText, '\n'+str+sel+'\n', endText ].join(''); } break; case 'date': // yyyy-mm-dd を挿入 ...(省略)... break; case 'time': // HH:MM:SS を挿入 ...(省略)... break; } }