aboutsummaryrefslogtreecommitdiffstats
path: root/xpathBlink.js
blob: 1f950a9ad0632d48c701fb7f3aaa94371f92755c (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
let INFO =
<plugin name="xpathBlink" version="1.1.1"
        href="http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/xpathBlink.js"
        summary="blink elements by XPath"
        xmlns="http://vimperator.org/namespaces/liberator">
    <author email="teramako@gmail.com">teramako</author>
    <license href="http://www.mozilla.org/MPL/MPL-1.1.txt">MPL 1.1</license>
    <project name="Vimperator" minVersion="2.2"/>
    <p>
        For test XPath.
    </p>
    <p>CAUTION: This plugin needs "DOM Inspector" addon.</p>
    <item>
        <tags>:xpathb :xpathblink</tags>
        <spec>:xpathb<oa>link</oa> <a>expression</a></spec>
        <description>
            <p>
                blink specified elements with XPath <a>expression</a>
            </p>
        </description>
    </item>
</plugin>;

let PLUGIN_INFO =
<VimperatorPlugin>
<name>{NAME}</name>
<description>blink elements by XPath</description>
<author mail="teramako@gmail.com" homepage="http://vimperator.g.hatena.ne.jp/teramako/">teramako</author>
<require type="extension" id="inspector@mozilla.org">DOM Inspector</require>
<license>MPL 1.1</license>
<version>1.1.1</version>
<minVersion>2.2</minVersion>
<maxVersion>2.3</maxVersion>
<updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/xpathBlink.js</updateURL>
<detail><![CDATA[
for test xpath

== Usage==
:xpathb[link] {expression}:
:xb {expression}
    blink specified elements with XPath {expression} 

== Caution ==
It's need "DOM Inspector" addon
]]></detail>
</VimperatorPlugin>;

(function(){
let extid = "inspector@mozilla.org";
if (!Application.extensions.has(extid) || !Application.extensions.get(extid).enabled){
    liberator.echomsg("DOM Inspector is not installed or enabled", 2);
    return;
}
let flasher = null;
function getFlasher(){
	if (!flasher){
		flasher = Cc['@mozilla.org/inspector/flasher;1'].createInstance(Ci.inIFlasher);
		flasher.color = '#FF0000';
		flasher.thickness = 2;
	}
	return flasher;
}
/**
 * @param {Node} aNode
 */
function blink(aNode){
	if (aNode.nodeType == 3) aNode = aNode.parentNode;
	let toggle = true;
	let flasher = getFlasher();
	function setOutline(){
		if (toggle){
			flasher.drawElementOutline(aNode);
		} else {
			flasher.repaintElement(aNode);
		}
		toggle = !toggle;
	}
	for (let i=1; i<7; ++i){
		setTimeout(setOutline, i * 100);
	}
}
commands.addUserCommand(['xpathb[link]','xb'],'XPath blink nodes',
	function(expression){
		let result;
		try {
			result = util.evaluateXPath(expression.string);
		} catch(e) {
			liberator.echoerr('XPath blink: ' + e);
		}
		if (!result.snapshotLength){
			liberator.echo('XPath blink: none');
			return;
		}
		for (let i=0; i<result.snapshotLength; i++){
			blink(result.snapshotItem(i));
		}
	},{}
);
})();

// vim: set fdm=marker sw=4 ts=4 et:
s="o">%: 対象ページのURL %title%: 対象ページのタイトル %author%: 対象ページの著者 %content%: 対象ページの内容(一部) %rootURI%: 対象ページのトップページのURL %id%: 不明ドメイン日付パスが含まれる %published%: 投稿された日時(%Y-%m-%dT%H:%M:%SZ) %updated%: 更新された日時(%Y-%m-%dT%H:%M:%SZ) ]]></detail> </VimperatorPlugin>; liberator.plugins.relatedBlogSearch = (function(){ const LANG = window.navigator.language; const BLOGSEARCH_URL = 'http://blogsearch.google.com/blogsearch_feeds?output=atom&hl=' + LANG + '&q='; /** * Serach with Google blogsearch and get entries * @param {String} name query string */ function BlogSearch() { this._init.apply(this, arguments); } BlogSearch.prototype = { _init: function(name){ if (!name) throw Components.results.NS_ERROR_XPC_NOT_ENOUGH_ARGS; this.date = new Date(); this.name = name; this.query = BLOGSEARCH_URL + this.name; let self = this; this.items = Array.map( util.httpGet(this.query).responseXML.getElementsByTagName("entry"), function(entry) self._parse(entry) ); }, /** * @param {Element} entryElm Atom entry element * @return {Object} */ _parse: function(entryElm){ let entry = {}; Array.forEach(entryElm.childNodes, function(elm){ let tagName = elm.localName; switch(tagName){ case 'link': entry.link = elm.getAttribute('href'); break; case 'author': entry.author = elm.childNodes[0].textContent; entry.rootURI = elm.childNodes[1].textContent; break; default: entry[tagName] = elm.textContent; } }); return entry; }, /** * @param {RegExp} reg * @param {String[]} itemNames item's property names * @return {Object[]} item list */ search: function(reg, itemNames){ if (!itemNames) itemNames = [name for (name in this.items[0])]; return this.items.filter(function(item) itemNames.some(function(name) reg.test(item[name]))); }, /** * @param {String} template * @param {XMLList} xml header XML * @param {Object[]} items if omitted, used all items * template e.g.) * '<tr><td><a href="link">%title%</a></td><td>%author%</td><td>%content%</td></tr>' */ toXMLByTemplate: function(template, xml, items){ if (!items) items = this.items; function entryToXML(item){ function replacer(all, name) name in item ? item[name] : all; return new XMLList(template.replace(/%(\w+?)%/g, replacer).replace(/&/g,"&amp;")); } items.forEach(function(item){xml.* += entryToXML(item);}); return xml; }, }; /** * -query option completion list * e.g.) * return [ * ["link:https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects", "-"], * ["link:https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference", "-"], * ["link:https://developer.mozilla.org/en", "-"], * ["link:https://developer.mozilla.org", "-"], * ] * when current url is "https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects" * @return {String[][]} */ function getQueryList(){ return buffer.URL.split(/\/(?!\/)/).reduce(function(p,c){ p.length == 0 ? p.push(c) : p.push(p[p.length-1]+"/"+c); return p; },[]).splice(1).map(function(url) ["link:" + url, "-"]).reverse(); } // ---------------------------------------------- // command // ---------------------------------------------- commands.addUserCommand(["relatedblog"], "search linked blog from google blogsearch", function(args){ let query = args["-query"] ? args["-query"] : "link:" + buffer.URL; let entry = manager.getCache(query); let header = new XMLList(manager.headerTemplate); if (args.length == 0){ let xml = entry.toXMLByTemplate(manager.bodyTemplate, header); liberator.echo(xml, true); } else { let reg = new RegExp(args[0], "i"); let items = entry.search(reg); if (items.length > 1){ liberator.echo(entry.toXMLByTemplate(manager.bodyTemplate, header, items),true); } else if (items.length == 1){ let url = items[0].link; liberator.open(url); } else { liberator.echomsg("related blog is none",5); } } },{ options: [ [["-query", "-q"], commands.OPTION_STRING, null, getQueryList] ], argCount: "?", completer: function(context, args){ manager.completer(context, args); }, },true); // ---------------------------------------------- // public // ---------------------------------------------- var manager = { get bodyTemplate(){ return liberator.globalVariables.blogSearchBodyTemplate ? liberator.globalVariables.blogSearchBodyTemplate : '<tr><td><a highlight="URL" href="%link%">%title%</a></td><td>%author%</td><td>%content%</td></tr>'; }, get headerTemplate(){ return liberator.globalVariables.blogSearchHeaderTemplate ? liberator.globalVariables.blogSearchHeaderTemplate : '<table><tr><th>Title</th><th>Author</th><th>Content</th></tr></table>'; }, /** * @type {BlogSerach[]} */ cache: [], /** * キャッシュからエントリを取得 * キャッシュがないまたは期限切れの場合は新たに取得 * キャッシュのリストは10個まで XXX: 外だししたほうが良いかもしれない * XXX: 有効期限を変数に持たせた方が良いかもしれない * @param {String} name query string * @return {BlogSearch} */ getCache: function(name){ let cache = this.cache.filter(function(entry) entry.name == name); if (cache.length == 0){ let entry = new BlogSearch(name); if(this.cache.push(entry) > 10) this.cache.shift(); return entry; } else if (cache[0].date < Date.now() - 5*60*1000){ cache[0]._init(name); } return cache[0]; }, /** * relatedblog コマンド用の補完関数 * @param {CompletionContext} context * @param {String[]} args */ completer: function(context, args){ let query = args["-query"] ? args["-query"] : "link:" + buffer.URL; let entry = this.getCache(query) context.title = ["URL", "Title"]; if (args.length == 0){ context.completions = entry.items.map(function(item) [item.link, item.title]); } else { let reg = new RegExp(context.filter, "i"); context.completions = entry.search(reg).map(function(item) [item.link, item.title]); } }, }; return manager; })(); // vim: sw=2 ts=2 et: