root/lang/javascript/vimperator-plugins/branches/2.2/access_hatena.js

Revision 35568, 8.6 kB (checked in by masa138, 11 months ago)

Small fix

Line 
1var PLUGIN_INFO =
2<VimperatorPlugin>
3<name>{NAME}</name>
4<description>Access to Hatena Sevices quickly.</description>
5<description lang="ja">はてなのサーヴィスに簡単にアクセス出来ます.</description>
6<minVersion>2.1a1pre</minVersion>
7<maxVersion>2.1a1pre</maxVersion>
8<updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/access_hatena.js</updateURL>
9<author mail="masa138@gmail.com" homepage="http://www.hatena.ne.jp/masa138/">Masayuki KIMURA and id:hitode909</author>
10<version>0.62</version>
11<detail><![CDATA[
12
13== Commands ==
14:accesshatena
15    Access to http://www.hatena.ne.jp/
16
17:accesshatena {host}
18    Access to http://{host}.hatena.ne.jp/
19
20:accesshatena {host} {user_id}
21    Access to http://{host}.hatena.ne.jp/{user_id}/
22
23:accesshatena {group_name}.g {user_id}
24    Access to http://{group_name}.g.hatena.ne.jp/{user_id}/
25
26
27== Global variables ==
28maxRecentHostsSize
29    直近何件の履歴を検索してホスト補完をするか
30
31collectLogSpan
32    どのくらいの期間の履歴を検索するか
33
34accessHatenaUseWedata
35    Wedata から拒否 ID リストを取ってくるか
36
37accessHatenaIgnoreIds
38    Wedata の拒否リストに含まれないけれど拒否したい ID の記入用
39
40
41== .vimperatorrc ==
42コマンドが長いので,以下の様に短い物にマッピングすると便利です.
43>||
44map ; :accesshatena
45||<
46# 最後にスペースを入れておくと直ぐにホストの入力から始められます.
47
48]]></detail>
49</VimperatorPlugin>;
50(function(){
51    var useWedata;
52    var ignoreIds;
53    var ids;
54    var recentHosts;
55    var maxRecentHostsSize;
56    var historyCompletions;
57    var collectLogSpan;
58    var pageFor;
59    var title;
60    var isFirst;
61    var isIncreased;
62    var isUpdated;
63    var lastLocation;
64
65    function Title() {
66        this.initialize.apply(this, arguments);
67    }
68    Title.prototype = {
69        initialize: function() {
70            this.title = [];
71            this.n     = 0;
72        },
73        key: function(host, id) {
74            return [host, id.replace('/', '')].join(':');
75        },
76        set: function(host, id, title) {
77            var key = this.key(host, id);
78            if (this.title[key] == null) {
79                this.title[key] = title;
80                this.n++;
81            }
82        },
83        get: function(host, id, title) {
84            if (!this.title[this.key(host, id)]) return host + '.hatena.ne.jp/' + id;
85            return this.title[this.key(host, id)];
86        }
87    };
88
89    function init() {
90        ids                = [];
91        recentHosts        = [];
92        historyCompletions = [];
93        pageFor            = [];
94        title              = new Title();
95        isFirst            = true;
96        isIncreased        = false;
97        isUpdated          = false;
98        lastLocation       = window.content.location.href.replace(/^https?:\/\//, '');
99
100        maxRecentHostsSize = liberator.globalVariables.maxRecentHostsSize || 10;
101        collectLogSpan     = liberator.globalVariables.collectLogSpan     || 24 * 7 * 4 * 60 * 60 * 1000000; // 4 weeks
102        useWedata          = liberator.globalVariables.accessHatenaUseWedata;
103        ignoreIds          = liberator.globalVariables.accessHatenaIgnoreIds;
104        useWedata          = (useWedata != null) ? useWedata : true;
105        ignoreIds          = (ignoreIds != null) ? ignoreIds : ['login'];
106
107        if (useWedata) {
108            loadWedata();
109        }
110    }
111    init();
112
113    function prepareSearch() {
114        var historyService       = Components.classes["@mozilla.org/browser/nav-history-service;1"].getService(Components.interfaces.nsINavHistoryService);
115        var options              = historyService.getNewQueryOptions();
116        var query                = historyService.getNewQuery();
117        query.beginTimeReference = query.TIME_RELATIVE_NOW;
118        query.beginTime          = -1 * collectLogSpan;
119        query.endTimeReference   = query.TIME_RELATIVE_NOW;
120        query.endTime            = 0;
121        query.domain             = "hatena.ne.jp";
122
123        return historyService.executeQuery(query, options).root;
124    }
125
126    function collectLog() {
127        var root             = prepareSearch();
128        ids                  = [];
129        recentHosts          = [];
130        historyCompletions   = [];
131        historyCompletions.h = [];
132
133        root.containerOpen = true;
134        for (var i = 0, length = root.childCount; i < length; i++) {
135            var page = root.getChild(i);
136            page.uri.match('^https?://([a-zA-Z0-9.]+)\\.hatena\\.ne\\.jp/([a-zA-Z][a-zA-Z0-9_-]{1,30}[a-zA-Z0-9]/?)?');
137            var host = RegExp.$1;
138            var id   = RegExp.$2;
139            var _recent_hosts_length = recentHosts.length;
140            if (host != '') {
141                if (!pageFor[host]) {
142                    pageFor[host] = page;
143                    isIncreased = true;
144                } else if (pageFor[host].uri.length > page.uri.length) { // より短いアドレスのタイトルが妥当
145                    pageFor[host] = page;
146                    isUpdated = true;
147                }
148
149                if (_recent_hosts_length < maxRecentHostsSize && recentHosts.indexOf(host) == -1) {
150                    recentHosts.push(host);
151                } else if (recentHosts.indexOf(host) == -1 && historyCompletions.h.indexOf(host) == -1) {
152                    historyCompletions.push([host, pageFor[host].title]);
153                    historyCompletions.h.push(host);
154                }
155            }
156            if (id != '' && !id.replace('/', '').match(new RegExp('^(?:' + ignoreIds.join('|') + ')$'))) { // Wedata の拒否リストに入っていなかったら
157                var index = ids.indexOf(id);
158                if (index == -1) {
159                    ids.unshift(id);
160                } else {
161                    ids.splice(index, 1);
162                    ids.unshift(id);
163                }
164                if (isFirst || isIncreased || isUpdated) { // 初回か,pageFor に何か追加されたか,pageFor が更新されたら
165                    isIncreased = false;
166                    isUpdated   = false;
167                    if (page.title != '' && title.get(host, id) != page.title) {
168                        title.set(host, id, page.title);
169                    }
170                }
171            }
172        }
173        root.containerOpen = false;
174        isFirst = false;
175    }
176    collectLog();
177
178    function loadWedata() {
179        var url = 'http://wedata.net/databases/access_hatena_ignore_id/items.json';
180        var req = XMLHttpRequest();
181
182        req.open('GET', url, true);
183        req.onload = registerIgnoreIds;
184        req.onerror = function(e) { liberator.echoerr('Error in access_hatena.js: loadWedata'); };
185        req.send(null);
186    }
187
188    function registerIgnoreIds(e) {
189        var req = this;
190        var json = eval(req.responseText);
191        for (var i in json) if (json.hasOwnProperty(i)) {
192            var id = json[i].data.id;
193            if (ignoreIds.indexOf(id) == -1 && id != '') {
194                ignoreIds.push(id)
195            }
196        }
197    }
198
199    commands.addUserCommand(["accesshatena"], "Access to Hatene Service Quickly",
200        function(args) {
201            var host = args[0] ? encodeURIComponent(args[0].toString()) : 'www';
202            var id   = args[1] ? encodeURIComponent(args[1].toString()).replace('%2F', '/') : '';
203            var uri  = 'http://' + host + '.hatena.ne.jp/' + id;
204            liberator.open(uri, liberator.CURRENT_TAB);
205            lastLocation = '';
206        }, {
207            completer: function (context, args) {
208                if (args.length == 1) {
209                    context.title = ["Host", "Service"];
210                    if (window.content.location.href.replace(/^https?:\/\//, '') != lastLocation) { // ページ遷移がない場合に何度も collectLog() しないように
211                        collectLog();
212                        lastLocation = window.content.location.href.replace(/https?:\/\//, '');
213                    }
214                    context.completions = [[recentHosts[i], pageFor[recentHosts[i]].title] for (i in recentHosts) if (recentHosts.hasOwnProperty(i))].concat(historyCompletions);
215                } else if (args.length == 2) {
216                    var host = args[0].toString();
217                    context.title = ["ID", "Page"];
218                    context.completions = [[ids[i], title.get(host, ids[i])] for (i in ids) if (ids.hasOwnProperty(i))];
219                }
220            }
221        }
222    );
223
224    commands.addUserCommand(["accesshatenainit"], "Initialize Access Hatena",
225        function() {
226            init();
227            liberator.echo('Finish initializing.');
228        }
229    );
230})();
231// vim:sw=4 ts=4 et:
Note: See TracBrowser for help on using the browser.