aboutsummaryrefslogtreecommitdiffstats
path: root/blinkelement.js
blob: af9ca75e4ba86a9ef6d8744a5494d528b69504a0 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
 * ==VimperatorPlugin==
 * @name            blinkelement.js
 * @description     blink specified elements.
 * @description-ja  指定した要素を点滅させる。
 * @author          janus_wel <janus_wel@fb3.so-net.ne.jp>
 * @version         0.32
 * @minversion      2.3pre 2009/11/02
 * ==/VimperatorPlugin==
 *
 * LICENSE
 *  New BSD License
 *
 * CONSTRAINT
 *  need highlight.js
 *
 * USAGE
 *  :blink {element[s] object}
 *  :bl
 *      -> blink specified element[s].
 *
 *  :noblink
 *  :nobl
 *      -> clear blink all elements.
 *
 * SETTING
 *  blink_element_interval: interval time. default is 800 msec.
 *  blink_element_color:    color for blink. default is red.
 *  blink_element_opacity:  opacity value. defualt is 0.5 .
 *
 * EXAMPLE
 *  let blink_element_interval='500'
 *  let blink_element_color='green'
 *  let blink_element_opacity='0.7'
 *
 *  :bl content.document.getElementsByTagName('A');
 *  :bl util.evaluateXPath('//a');
 *  :nobl
 * */

// use setTimeout to synchronize ( wait to process highlight.js )
// "liberator.modules.plugins.highlighterFactory" is build by highlight.js .
// it is the factory that build highlight object.
setTimeout( function () {

if (!plugins.highlighterFactory) {
    liberator.log('blinkelement.js needs highlight.js', 0);
    return;
}

// default settings
const defaultColor    = 'red';
const defaultOpacity  = 0.5;
const defaultInterval = 800;

let highlighter = liberator.modules.plugins.highlighterFactory({
    color:    liberator.globalVariables.blink_element_color    || defaultColor,
    opacity:  liberator.globalVariables.blink_element_opacity  || defaultOpacity,
    interval: liberator.globalVariables.blink_element_interval || defaultInterval,
});

// register commands
commands.addUserCommand(
    ['blink', 'bl'],
    'blink',
    function (args) {
        let arg = args.string;
        let element = liberator.eval(arg);

        if (!element) {
            liberator.echoerr('specify element[s]');
            return;
        }

        liberator.log(highlighter, 0);

        // reflect settings ( follow dynamic change of settings )
        highlighter.set({
            color:    liberator.globalVariables.blink_element_color    || defaultColor,
            opacity:  liberator.globalVariables.blink_element_opacity  || defaultOpacity,
            interval: liberator.globalVariables.blink_element_interval || defaultInterval,
        });

        // for getElement[s]By...
        if (element instanceof HTMLCollection) {
            for (let [, e] in Iterator(element)) highlighter.highlight(e);
        }
        // for evaluate
        else if (element instanceof XPathResult) {
            for (let e in element) highlighter.highlight(e);
        }
        // single element
        else if (element) {
            highlighter.highlight(element);
        }
        else {
            liberator.echoerr('specify element[s]');
        }
    },
    {
        literal: 0,
        completer: function (filter) completion.javascript(filter),
    },
    true
);

commands.addUserCommand(
    ['noblink', 'nobl'],
    'no blink',
    function () highlighter.unhighlightAll(),
    {}
);

}, 0); // setTimeout

// vim: set sw=4 ts=4 et;
lt;/name> <description>Make notify hatebu-count when specified site's hatebu-count changed.</description> <description lang="ja">指定されたサイトのはてブ数を監視、変動があったらお知らせします。</description> <minVersion>2.0pre</minVersion> <maxVersion>2.2pre</maxVersion> <updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/hatebuWatchDog.js</updateURL> <author mail="snaka.gml@gmail.com" homepage="http://vimperator.g.hatena.ne.jp/snaka72/">snaka</author> <license>MIT style license</license> <version>1.3.0</version> <detail><![CDATA[ == Subject == Make notify hatebu-count when specified site's hatebu-count changed. Usage is just put this script into vimperator's plugin directory. == Global variables == g:hatebuWatchDogInterval: Number. Watching interval. Default:600 Min:60 g:hatebuWtachDogTargets: String. Sites where it wants you to watch. If you want watch only one site, you should specify like following. >|| :let g:hatebuWatchDogTargets = "http://d.hatena.ne.jp/snaka72/" ||< If you want watch more than one site, you should specify like following. >|| :let g:hatebuWatchDogTargets = "['http://d.hatena.ne.jp/snaka72/', 'http://vimperator.g.hatena.ne.jp/snaka72/']" ||< g:hatebuWatchDogAlways: Boole. Make notify every time. (for debug) Default:false ]]></detail> <detail lang="ja"><![CDATA[ == 概要 == 指定されたサイトの被はてブ数を監視してその数値に変動があったらお知らせします 使い方はこのスクリプトをVimperatorのpluginディレクトリに格納するだけです == グローバル変数 == g:hatebuWatchDogInterval: Number. 監視の間隔(). デフォルト600 設定可能な最小値:60 g:hatebuWtachDogTargets: String. Sites where it wants you to watch 監視対象のサイトが一つだけの場合は以下のように設定します >|| :let g:hatebuWatchDogTargets = "http://d.hatena.ne.jp/snaka72/" ||< 監視対象のサイトがが複数の場合は以下のように設定します >|| :let g:hatebuWatchDogTargets = "['http://d.hatena.ne.jp/snaka72/', 'http://vimperator.g.hatena.ne.jp/snaka72/']" ||< g:hatebuWatchDogAlways: Boole. 毎回報告を挙げるかどうかデフォルト:false 主にでバッグ用 == ToDo == - 新着ブックマークのユーザidとコメントの表示 - 監視フレームワークにのっける ]]></detail> </VimperatorPlugin>; // }}} // Clear all watchers if started watcher exists. if (plugins.hatebuWatchDog && plugins.hatebuWatchDog.stopWatching) plugins.hatebuWatchDog.stopWatching(); let publics = plugins.hatebuWatchDog = (function() { // PRIVATE //////////////////////////////////////////////////////////////{{{ const libly = plugins.libly; let previousValue = 0; let tasks = []; function getCurrentValue(target, onSuccess, onFailure) { // build hatebu xml-rpc request let req = new libly.Request( 'http://b.hatena.ne.jp/xmlrpc', { 'Content-Type' : 'text/xml' },{ postBody : <methodCall> <methodName>bookmark.getTotalCount</methodName> <params> <param><value><string>{target}</string></value></param> </params> </methodCall>.toXMLString() } ); let currentValue; req.addEventListener("onSuccess", function(data) { liberator.log("XML-RPC request was succeeded."); let resXml = new XML(data.responseText.replace(/^<\?xml version[^>]+?>/, '')); currentValue = window.eval(resXml..int.toString()); onSuccess(currentValue); }); req.addEventListener("onFailure", function(data) { onFailure(); }); liberator.log("reauest..."); req.post(); liberator.log("done..."); } function notifyAlways() window.eval(liberator.globalVariables.hatebuWatchDogAlways) || false; function showHatebuNotification(targetSite, currentValue, delta) { let title = delta >= 0 ? "hatebuWatchDog\u304B\u3089\u306E\u304A\u77E5\u3089\u305B" // ordinary notification : "\u6B8B\u5FF5\u306A\u304A\u77E5\u3089\u305B" // bad notification let suffix = delta != 0 ? "\u306B\u306A\u308A\u307E\u3057\u305F\u3002" : "\u3067\u3059\u3002"; let message = "'" + targetSite + "' \u306E\u88AB\u306F\u3066\u30D6\u6570\u306F '" + currentValue + "' " + suffix + " (" + getSignedNum(delta) + ")"; (getNotifier())(title, message, growlIcon); } function getSignedNum(num) { if (num > 0) return "+" + num; if (num < 0) return "-" + Math.abs(num); return "0"; } let _notifier = null; const GROWL_EXTENSION_ID = "growlgntp@brian.dunnington"; function getNotifier() { if (_notifier) return _notifier; if (Application.extensions.has(GROWL_EXTENSION_ID) && Application.extensions.get(GROWL_EXTENSION_ID).enabled) { _notifier = publics.notify; } else { _notifier = showAlertNotification; } return _notifier; } function showAlertNotification(title, message, icon) { liberator.dump("icon:" + icon); Cc['@mozilla.org/alerts-service;1'] .getService(Ci.nsIAlertsService) .showAlertNotification( null, //'chrome://mozapps/skin/downloads/downloadIcon.png', title, message ); } function growl() Components.classes['@growlforwindows.com/growlgntp;1'] .getService().wrappedJSObject; const growlIcon = "http://img.f.hatena.ne.jp/images/fotolife/s/snaka72/20090608/20090608045633.gif"; // temporary function growlRegister() { growl().register( PLUGIN_INFO.name, growlIcon, [ {name: 'announce', displayName: 'Announce from hatebuWatchDog'}, {name: 'sadlynews',displayName: 'Sadly announce from hatebuWatchdog'}, {name: 'failed', displayName: 'Erroer report from hatebuWatchdog'} ] ); } function getInterval() window.eval(liberator.globalVariables.hatebuWatchDogInterval) || 600; // default : 10 min. // for debug let log = liberator.log; let dump = liberator.dump; // }}} // PUBLIC ///////////////////////////////////////////////////////////////{{{ let self = { startWatching: function() { let targets; try { targets = window.eval(liberator.globalVariables.hatebuWatchDogTargets); } catch(e) { targets = liberator.globalVariables.hatebuWatchDogTargets; } if (targets) { if (!(targets instanceof Array)) targets = [targets]; let i = 1, delay = 5000; log("before setTimeout()"); targets.forEach(function(targetSite) { setTimeout(function() { publics.addTask({site : targetSite}); }, delay * i++); }); log("after setTimeout()"); } else { liberator.echoerr("Please set g:hatebeWatchDogTargets before watching()."); } }, addTask: function(target) { dump(target.site); const MINUTE = 60; // sec. interval = getInterval() || (10 * MINUTE); // default 10 min. interval = Math.max(interval, MINUTE); // lower limt is 1 min. // initialize previous value target.previousValue = 0; target.initialize = true; publics.watching(target); // set watching interval tasks.push(setInterval(publics.watching, 1000 * interval, target)); dump({target: target, interval: interval}); }, clearAllTasks: function() { tasks.forEach(function(task) { clearInterval(task); }); tasks = []; dump("watch dog is sleeping..."); }, watching: function(target) { dump("watching..."); dump(target); getCurrentValue( target.site, function(currentValue) { if (target.initialize) { target.initialize = false; target.previousValue = currentValue; return; } let delta = currentValue - target.previousValue; if (delta || notifyAlways()) { showHatebuNotification(target.site, currentValue, delta); } target.previousValue = currentValue; if (delta > 0) { liberator.dump("***hoge"); self.getBookmarklistByURL(target.site) .slice(0, delta) .forEach(function(item) self.reportBookmarkedItem(self.parseBookmarkItem(item))); } }, function() { liberator.echoerr("Cannot get current value."); } ); }, notify: function(title, message) { growlRegister(); growl().notify( PLUGIN_INFO.name, 'announce', title, message ); }, getBookmarkListRss: function(url) { return util.httpGet("http://b.hatena.ne.jp/bookmarklist.rss?url=" + encodeURIComponent(url)); }, getBookmarklistByURL: function(url) { liberator.dump("********** getBookmarklistByURL"); let res = util.httpGet('http://b.hatena.ne.jp/bookmarklist.rss?url=' + encodeURIComponent(url)); liberator.dump(res); return self.evaluateXPath("//rss:item", res.responseXML, self.nsResolver); }, nsResolver: { lookupNamespaceURI: function(pfx) (({ 'rdf' : "http://www.w3.org/1999/02/22-rdf-syntax-ns#", 'content' : "http://purl.org/rss/1.0/modules/content/", 'taxo' : "http://purl.org/rss/1.0/modules/taxonomy/", 'opensearch' : "http://a9.com/-/spec/opensearchrss/1.0/", 'dc' : "http://purl.org/dc/elements/1.1/", 'hatena' : "http://www.hatena.ne.jp/info/xmlns#", 'media' : "http://search.yahoo.com/mrss" })[pfx] || 'http://purl.org/rss/1.0/') }, // reffered _libly.js evaluateXPath: function(xpath, context, nsresolver) { if (!xpath) return []; var ret = []; context = context || window.content.document; var nodesSnapshot = ( context.ownerDocument || context ).evaluate( xpath, context, nsresolver || self.nsResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (let i = 0, l = nodesSnapshot.snapshotLength; i < l; i++) { ret.push(nodesSnapshot.snapshotItem(i)); } return ret; }, parseBookmarkItem: function(item) { let parsed = { title: self.evaluateXPath("./rss:title", item)[0].textContent, creator: self.evaluateXPath("./dc:creator", item)[0].textContent, date: self.evaluateXPath("./dc:date", item)[0].textContent, comment: self.evaluateXPath("./rss:description", item)[0].textContent, tags: self.evaluateXPath("./dc:subject", item).map(function(i) i.textContent).join(",") }; return parsed; }, reportBookmarkedItem: function(item) { liberator.dump(item); (getNotifier())( item.title, item.creator + " bookmarked at " + item.date + "\n" + item.tags + ":" + item.comment, 'http://www.hatena.ne.jp/users/' + item.creator.substr(0, 2) + '/' + item.creator + '/profile.gif' ); } }; // }}} return self; })(); // Awaking the watch dog. publics.startWatching(); liberator.dump("Watch dog is awaking ..."); // vim: sw=2 ts=2 et fdm=marker