152 lines
5.8 KiB
JavaScript
152 lines
5.8 KiB
JavaScript
![]() |
let INFO = //{{{
|
|||
|
<plugin name="statusbar panel" version="0.1"
|
|||
|
href="https://github.com/vimpr/vimperator-plugins/raw/master/statusbar_panel.js"
|
|||
|
summary="Click statusbar panel"
|
|||
|
lang="ja"
|
|||
|
xmlns="http://vimperator.org/namespaces/liberator">
|
|||
|
<author href="http://d.hatena.ne.jp/wlt/" email="wltlain@gmail.com">wlt</author>
|
|||
|
<license href="http://www.opensource.org/licenses/mit-license.php">MIT License</license>
|
|||
|
<project name="vimperator" minVersion="2.3.1"/>
|
|||
|
<p>
|
|||
|
ステータスバー(アドオンバー)にあるパネル(アイコン)をクリックするコマンドを提供します。
|
|||
|
</p>
|
|||
|
<item>
|
|||
|
<tags>:statusbarpanel</tags>
|
|||
|
<spec>:statusbarpanel <oa>-button=<a>l | m | r</a></oa> <oa>-double-click</oa> <a>panel-id</a></spec>
|
|||
|
<description>
|
|||
|
<p>
|
|||
|
<a>panel-id</a>で指定するID属性を持つステータスバーパネル(アイコン)をクリックします。
|
|||
|
クリックするボタンは<oa>-button=</oa>で指定できます:
|
|||
|
</p>
|
|||
|
<dl>
|
|||
|
<dt>l</dt>
|
|||
|
<dd>左ボタン(デフォルト)</dd>
|
|||
|
<dt>m</dt>
|
|||
|
<dd>中ボタン(スクロールボタン)</dd>
|
|||
|
<dt>r</dt>
|
|||
|
<dd>右ボタン</dd>
|
|||
|
</dl>
|
|||
|
<p><oa>-double-click</oa>を指定するとダブルクリックになります。</p>
|
|||
|
</description>
|
|||
|
</item>
|
|||
|
</plugin>;
|
|||
|
//}}}
|
|||
|
|
|||
|
let MOUSE_BUTTON_LEFT = 0;
|
|||
|
let MOUSE_BUTTON_MIDDLE = 1;
|
|||
|
let MOUSE_BUTTON_RIGHT = 2;
|
|||
|
|
|||
|
function getImages(panel) {
|
|||
|
var images = [];
|
|||
|
// 普通の子孫要素のimage要素探索
|
|||
|
for (let [k, node] in Iterator(panel.getElementsByTagName('image'))) images.push(node);
|
|||
|
// 匿名コンテントの子孫要素のimage要素探索
|
|||
|
var anonymousNodes = document.getAnonymousNodes(panel);
|
|||
|
for (let [k, anonymousNode] in Iterator(anonymousNodes)) {
|
|||
|
let node;
|
|||
|
let result = document.evaluate('descendant-or-self::xul:image', anonymousNode, function() XUL.uri, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
|
|||
|
while ((node = result.iterateNext())) images.push(node);
|
|||
|
}
|
|||
|
|
|||
|
return images;
|
|||
|
}
|
|||
|
|
|||
|
function makeIcon(panel) {
|
|||
|
var icon = <image xmlns={XUL.uri}/>;
|
|||
|
var image = getImages(panel)[0];
|
|||
|
|
|||
|
if (image) {
|
|||
|
let style = window.getComputedStyle(image, null);
|
|||
|
let src = image.src || style.listStyleImage.replace(/^url\("(.+)"\)$/, '$1');
|
|||
|
if (src != '') {
|
|||
|
icon.@style = 'list-style-image: url("' + src + '");' +
|
|||
|
'-moz-image-region: ' + style.MozImageRegion;
|
|||
|
}
|
|||
|
}
|
|||
|
return icon;
|
|||
|
}
|
|||
|
|
|||
|
function generateStatusbarpaneIDlList(filter) {
|
|||
|
var panels = document.getElementsByTagNameNS(XUL.uri, 'statusbarpanel');
|
|||
|
for ([k, p] in Iterator(panels)) {
|
|||
|
if (p.hidden != true) {
|
|||
|
yield {
|
|||
|
text: p.id,
|
|||
|
desc: 'statusbarpanel',
|
|||
|
icon: makeIcon(p)
|
|||
|
};
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function createAndDispatchEvent(target, type, detail, screenX, screenY, button) {
|
|||
|
var ev = document.createEvent('MouseEvents');
|
|||
|
ev.initMouseEvent(type, true, true, window, detail, screenX, screenY, 0, 0, false, false, false, false, button, null);
|
|||
|
target.dispatchEvent(ev);
|
|||
|
}
|
|||
|
|
|||
|
function clickStatusIcon(panel, button, doubleClick) {
|
|||
|
var target = getImages(panel)[0] || panel;
|
|||
|
if (!target) return;
|
|||
|
var x = target.boxObject.screenX;
|
|||
|
var y = target.boxObject.screenY;
|
|||
|
x += target.clientWidth / 2;
|
|||
|
y += target.clientHeight / 2;
|
|||
|
|
|||
|
// イベントの発生順序 http://www.quirksmode.org/dom/events/click.html
|
|||
|
createAndDispatchEvent(target, 'mousedown', 0, x, y, button);
|
|||
|
createAndDispatchEvent(target, 'mouseup', 0, x, y, button);
|
|||
|
createAndDispatchEvent(target, 'click', 1, x, y, button);
|
|||
|
|
|||
|
if (doubleClick) {
|
|||
|
createAndDispatchEvent(target, 'mousedown', 0, x, y, button);
|
|||
|
createAndDispatchEvent(target, 'mouseup', 0, x, y, button);
|
|||
|
createAndDispatchEvent(target, 'click', 1, x, y, button);
|
|||
|
createAndDispatchEvent(target, 'dblclick', 2, x, y, button);
|
|||
|
} else if (button == MOUSE_BUTTON_RIGHT) {
|
|||
|
createAndDispatchEvent(target, 'contextmenu', 1, x, y, button);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
commands.addUserCommand(['statusbarpanel'],'click statusbar panel',
|
|||
|
function(args) {
|
|||
|
var id = args[0];
|
|||
|
var panel = document.getElementById(id);
|
|||
|
if (!panel) {
|
|||
|
liberator.echoerr('No such statusbar panel: ' + id);
|
|||
|
return;
|
|||
|
}
|
|||
|
var button = MOUSE_BUTTON_LEFT;
|
|||
|
switch (args['-button']) {
|
|||
|
case 'm': button = MOUSE_BUTTON_MIDDLE; break;
|
|||
|
case 'r': button = MOUSE_BUTTON_RIGHT; break;
|
|||
|
case 'l': default: button = MOUSE_BUTTON_LEFT; break;
|
|||
|
}
|
|||
|
clickStatusIcon(panel, button, args['-double-click']);
|
|||
|
}, {
|
|||
|
argCount: '1',
|
|||
|
options: [
|
|||
|
[['-button', '-b'], commands.OPTION_STRING,
|
|||
|
function(arg) /^[lmr]$/.test(arg),
|
|||
|
[['l', 'Left click (default)'],
|
|||
|
['m', 'Middle click'],
|
|||
|
['r', 'Right click']]],
|
|||
|
[['-double-click', '-d'], commands.OPTION_NOARG]
|
|||
|
],
|
|||
|
completer: function(context, args) {
|
|||
|
var arg = args[0];
|
|||
|
context.anchored = false;
|
|||
|
context.title = ['Panel ID'];
|
|||
|
context.keys = { text: 'text', description: 'desc', icon: 'icon' };
|
|||
|
context.compare = CompletionContext.Sort.unsorted;
|
|||
|
context.process = [function (item, text) {
|
|||
|
return <><span highlight="CompIcon">{item.icon ? item.icon : <></>}</span><span class="td-strut"/>{text}</>
|
|||
|
}];
|
|||
|
|
|||
|
var list = generateStatusbarpaneIDlList(arg);
|
|||
|
context.completions = list;
|
|||
|
}
|
|||
|
}, true);
|
|||
|
|
|||
|
// vim: set sw=4 ts=4 et fdm=marker :
|