var PLUGIN_INFO = {NAME} Access to Hatena Sevices quickly. はてなのサーヴィスに簡単にアクセス出来ます. 2.1a1pre 2.1a1pre https://github.com/vimpr/vimperator-plugins/raw/master/access_hatena.js Masayuki KIMURA and id:hitode909 0.63 || map ; :accesshatena ||< # 最後にスペースを入れておくと直ぐにホストの入力から始められます. ]]> ; (function(){ var useWedata; var ignoreIds; var ids; var recentHosts; var maxRecentHostsSize; var historyCompletions; var collectLogSpan; var pageFor; var title; var isFirst; var isIncreased; var isUpdated; var lastLocation; function Title() { this.initialize.apply(this, arguments); } Title.prototype = { initialize: function() { this.title = []; this.n = 0; }, key: function(host, id) { return [host, id.replace('/', '')].join(':'); }, set: function(host, id, title) { var key = this.key(host, id); if (this.title[key] == null) { this.title[key] = title; this.n++; } }, get: function(host, id, title) { if (!this.title[this.key(host, id)]) return host + '.hatena.ne.jp/' + id; return this.title[this.key(host, id)]; } }; function init() { ids = []; recentHosts = []; historyCompletions = []; pageFor = []; title = new Title(); isFirst = true; isIncreased = false; isUpdated = false; lastLocation = window.content.location.href.replace(/^https?:\/\//, ''); maxRecentHostsSize = liberator.globalVariables.maxRecentHostsSize || 10; collectLogSpan = liberator.globalVariables.collectLogSpan || 24 * 7 * 4 * 60 * 60 * 1000000; // 4 weeks useWedata = liberator.globalVariables.accessHatenaUseWedata; ignoreIds = liberator.globalVariables.accessHatenaIgnoreIds; useWedata = (useWedata != null) ? useWedata : true; ignoreIds = (ignoreIds != null) ? ignoreIds : ['login']; if (useWedata) { loadWedata(); } } init(); function prepareSearch() { var historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"].getService(Components.interfaces.nsINavHistoryService); var options = historyService.getNewQueryOptions(); var query = historyService.getNewQuery(); query.beginTimeReference = query.TIME_RELATIVE_NOW; query.beginTime = -1 * collectLogSpan; query.endTimeReference = query.TIME_RELATIVE_NOW; query.endTime = 0; query.domain = "hatena.ne.jp"; return historyService.executeQuery(query, options).root; } function collectLog() { var root = prepareSearch(); ids = []; recentHosts = []; historyCompletions = []; historyCompletions.h = []; root.containerOpen = true; for (var i = 0, length = root.childCount; i < length; i++) { var page = root.getChild(i); page.uri.match('^https?://([a-zA-Z0-9.]+)\\.hatena\\.ne\\.jp/([a-zA-Z][a-zA-Z0-9_-]{1,30}[a-zA-Z0-9](?:\\+[a-zA-Z0-9_-]{1,30})?/?)?'); var host = RegExp.$1; var id = RegExp.$2; var _recent_hosts_length = recentHosts.length; if (host != '') { if (!page.uri) continue; if (!pageFor[host]) { pageFor[host] = page; isIncreased = true; } else if (pageFor[host].uri.length > page.uri.length) { // より短いアドレスのタイトルが妥当 pageFor[host] = page; isUpdated = true; } if (_recent_hosts_length < maxRecentHostsSize && recentHosts.indexOf(host) == -1) { recentHosts.push(host); } else if (recentHosts.indexOf(host) == -1 && historyCompletions.h.indexOf(host) == -1) { historyCompletions.push([host, pageFor[host].title]); historyCompletions.h.push(host); } } if (id != '' && !id.replace('/', '').match(new RegExp('^(?:' + ignoreIds.join('|') + ')$'))) { // Wedata の拒否リストに入っていなかったら var index = ids.indexOf(id); if (index == -1) { ids.unshift(id); } else { ids.splice(index, 1); ids.unshift(id); } if (isFirst || isIncreased || isUpdated) { // 初回か,pageFor に何か追加されたか,pageFor が更新されたら isIncreased = false; isUpdated = false; if (page.title != '' && title.get(host, id) != page.title) { title.set(host, id, page.title); } } } } root.containerOpen = false; isFirst = false; } collectLog(); function loadWedata() { var url = 'http://wedata.net/databases/access_hatena_ignore_id/items.json'; var req = XMLHttpRequest(); req.open('GET', url, true); req.onload = registerIgnoreIds; req.onerror = function(e) { liberator.echoerr('Error in access_hatena.js: loadWedata'); }; req.send(null); } function registerIgnoreIds(e) { var req = this; var json = eval(req.responseText); for (var i in json) if (json.hasOwnProperty(i)) { var id = json[i].data.id; if (ignoreIds.indexOf(id) == -1 && id != '') { ignoreIds.push(id) } } } commands.addUserCommand(["accesshatena"], "Access to Hatene Service Quickly", function(args) { var host = args[0] ? encodeURIComponent(args[0].toString()) : 'www'; var id = args[1] ? encodeURIComponent(args[1].toString()).replace('%2F', '/') : ''; var uri = 'http://' + host + '.hatena.ne.jp/' + id; var targetTab = args.bang ? liberator.CURRENT_TAB : liberator.NEW_TAB; liberator.open(uri, targetTab); lastLocation = ''; }, { completer: function (context, args) { if (args.length == 1) { context.title = ["Host", "Service"]; if (window.content.location.href.replace(/^https?:\/\//, '') != lastLocation) { // ページ遷移がない場合に何度も collectLog() しないように collectLog(); lastLocation = window.content.location.href.replace(/https?:\/\//, ''); } context.completions = [[recentHosts[i], pageFor[recentHosts[i]].title] for (i in recentHosts) if (recentHosts.hasOwnProperty(i))].concat(historyCompletions); } else if (args.length == 2) { var host = args[0].toString(); context.title = ["ID", "Page"]; var _completions = [[ids[i], title.get(host, ids[i])] for (i in ids) if (ids.hasOwnProperty(i))]; context.completions = host != 'd' ? _completions.filter(function(i){ return !/\+/.test(i[0]) }) : _completions; } } } ); commands.addUserCommand(["accesshatenainit"], "Initialize Access Hatena", function() { init(); liberator.echo('Finish initializing.'); } ); })(); // vim:sw=4 ts=4 et: