1 /*** BEGIN LICENSE BLOCK {{{
2 Copyright (c) 2008 suVene<suvene@zeromemory.info>
4 distributable under the terms of an MIT-style license.
5 http://www.opensource.jp/licenses/mit-license.html
6 }}} END LICENSE BLOCK ***/
9 <plugin name="multi_requester" version="0.4.16"
10 href="https://github.com/vimpr/vimperator-plugins/raw/master/multi_requester.js"
11 summary="request, and the result is displayed to the buffer."
12 xmlns="http://vimperator.org/namespaces/liberator">
13 <author href="http://zeromemory.sblo.jp/">suVene</author>
14 <license>MIT</license>
15 <project name="Vimperator" minVersion="3.6"/>
19 - _libly.js(ver.0.1.19)
20 @see http://coderepos.org/share/browser/lang/javascript/vimperator-plugins/trunk/_libly.js
24 command[!] subcommand [ANY_TEXT]
27 - ANY_TEXT your input text
31 :mr alc[,goo,any1,any2…] ANY_TEXT -> request by the input text, and display to the buffer.
32 :mr! goo[,any1,any2,…] {window.selection} -> request by the selected text, and display to the new tab.
35 == Custumize .vimperatorrc ==
36 === Command(default [ mr ]) ===
38 let g:multi_requester_command = "ANY1, ANY2, ……"
40 liberator.globalVariables.multi_requester_command = [ ANY1, ANY2, …… ];
43 === Default Sites (default undefined) ===
45 liberator.globalVariables.multi_requester_default_sites = "alc,goo"
47 These sites(subcommands) will be used, if this variable has been defined and you do not specify subcommands.
53 liberator.globalVariables.multi_requester_siteinfo = [
55 map: ",me", // optional: keymap for this siteinfo call
56 bang: true, // optional:
57 args: "any" // optional:
58 name: "ex", // required: subcommand name
59 description: "example", // required: commandline short help
60 url: "http://example.com/?%s", // required: %s <-- replace string
61 xpath: "//*", // optional: default all
62 srcEncode: "SHIFT_JIS", // optional: default UTF-8
63 urlEncode: "SHIFT_JIS", // optional: default srcEncode
64 ignoreTags: "img", // optional: default script, syntax "tag1,tag2,……"
65 extractLink: "//xpath" // optional: extract permalink
71 === other siteinfo by wedata. ===
72 @see http://wedata.net/databases/Multi%20Requester/items
78 liberator.globalVariables.multi_requester_mappings = [
79 [ ",ml", "ex" ], // == :mr ex
80 [ ",mg", "goo", "!" ], // == :mr! goo
81 [ ",ma", "alc", , "args" ], // == :mr alc args
88 let g:multi_requester_use_wedata = "false" // true by default
90 wedata を利用しない場合は false を設定してください。
92 let g:multi_requester_default_sites = 'alc';
94 subcommand を省略した場合に利用されるサイトを設定します。
96 let g:multi_requester_order = 'count'; // date by default
98 補完の順番を設定します。(大きい順に並びます)
99 "count" または "date" を設定してください。
105 if (!liberator.plugins.libly) {
106 liberator.log("multi_requester: needs _libly.js");
110 // global variables {{{
111 var DEFAULT_COMMAND = [ "mr" ];
115 description: "SPACE ALC (\u82F1\u8F9E\u6717 on the Web)",
116 url: "http://eow.alc.co.jp/%s/UTF-8/",
117 xpath: 'id("resultsList")'
120 var libly = liberator.plugins.libly;
122 var logger = $U.getLogger("multi_requester");
123 var mergedSiteinfo = {};
124 var store = storage.newMap('plugins-multi_requester', {store: true});
127 // Vimperator plugin command register {{{
128 var CommandRegister = {
129 register: function(cmdClass, siteinfo) {
130 cmdClass.siteinfo = siteinfo;
132 commands.addUserCommand(
134 cmdClass.description,
135 $U.bind(cmdClass, cmdClass.cmdAction),
137 completer: cmdClass.cmdCompleter || function(context, arg) {
140 context.title = [ "Name", "Descprition" ];
141 var sorted = siteinfo.sort(function(a, b)
142 typeof liberator.globalVariables.multi_requester_order == "undefined" ||
143 liberator.globalVariables.multi_requester_order == "date" ? store.get(b.name).lastPostTime - store.get(a.name).lastPostTime :
144 liberator.globalVariables.multi_requester_order == "count" ? store.get(b.name).count - store.get(a.name).count :
145 store.get(b.name).lastPostTime - store.get(a.name).lastPostTime);
146 var filters = context.filter.split(",");
147 var prefilters = filters.slice(0, filters.length - 1);
148 var prefilter = !prefilters.length ? "" : prefilters.join(",") + ",";
149 var subfilters = sorted.filter(function(s) prefilters.every(function(p) s.name != p));
150 var allSuggestions = subfilters.map(function(s) [prefilter + s.name, s.description]);
151 context.completions = context.filter
152 ? allSuggestions.filter(function(s) s[0].indexOf(context.filter) == 0)
155 options: cmdClass.cmdOptions,
156 argCount: cmdClass.argCount || undefined,
157 bang: cmdClass.bang || true,
158 count: cmdClass.count || false
164 addUserMaps: function(prefix, mapdef) {
165 mapdef.forEach(function([ key, command, bang, args ]) {
166 var cmd = prefix + (bang ? "! " : " ") + command + " ";
168 [ modes.NORMAL, modes.VISUAL ],
170 "user defined mapping",
173 liberator.execute(cmd + args);
175 let sel = $U.getSelectedString();
177 liberator.execute(cmd + sel);
179 commandline.open(":", cmd, modes.EX);
193 // initial data access class {{{
195 getCommand: function() {
196 var c = liberator.globalVariables.multi_requester_command;
198 if (typeof c == "string") {
200 } else if (typeof c == "Array") {
203 ret = DEFAULT_COMMAND;
207 getSiteInfo: function() {
210 var useWedata = typeof liberator.globalVariables.multi_requester_use_wedata == "undefined" ?
211 true : $U.eval(liberator.globalVariables.multi_requester_use_wedata);
213 if (liberator.globalVariables.multi_requester_siteinfo) {
214 liberator.globalVariables.multi_requester_siteinfo.forEach(function(site) {
215 if (!mergedSiteinfo[site.name]) mergedSiteinfo[site.name] = {};
216 $U.extend(mergedSiteinfo[site.name], site);
217 if (!store.get(site.name)) {
218 store.set(site.name, { count: 0, lastPostTime: (new Date()).getTime() });
222 CommandRegister.addUserMaps(MultiRequester.name[0],
223 [[ site.map, site.name, site.bang, site.args ]]);
228 SITEINFO.forEach(function(site) {
229 if (!mergedSiteinfo[site.name]) mergedSiteinfo[site.name] = {};
230 $U.extend(mergedSiteinfo[site.name], site);
231 if (!store.get(site.name)) {
232 store.set(site.name, { count: 0, lastPostTime: (new Date()).getTime() });
236 CommandRegister.addUserMaps(MultiRequester.name[0],
237 [[ site.map, site.name, site.bang, site.args ]]);
242 logger.log("use wedata");
243 var wedata = new libly.Wedata("Multi Requester");
244 wedata.getItems(24 * 60 * 60 * 1000,
246 var site = item.data;
247 if (mergedSiteinfo[site.name]) return;
248 mergedSiteinfo[site.name] = {};
249 $U.extend(mergedSiteinfo[site.name], site);
250 if (!store.get(site.name)) {
251 store.set(site.name, { count: 0, lastPostTime: (new Date()).getTime() });
255 function(isSuccess, data) {
256 if (!isSuccess) return;
257 CommandRegister.register(MultiRequester, $U.A(mergedSiteinfo));
262 return $U.A(mergedSiteinfo);
267 // main controller {{{
268 var MultiRequester = {
269 name: DataAccess.getCommand(),
270 description: "request, and display to the buffer",
271 defaultSites: liberator.globalVariables.multi_requester_default_sites,
276 cmdAction: function(args) { //{{{
278 if (MultiRequester.doProcess) return;
280 var bang = args.bang;
281 var count = args.count;
283 var parsedArgs = this.parseArgs(args);
284 if (parsedArgs.count == 0) { return; } // do nothing
286 MultiRequester.doProcess = true;
287 MultiRequester.requestNames = parsedArgs.names;
288 MultiRequester.requestCount = 0;
289 MultiRequester.echoHash = {};
290 var siteinfo = parsedArgs.siteinfo;
291 for (let i = 0, len = parsedArgs.count; i < len; i++) {
293 let info = siteinfo[i];
294 let name = info.name;
296 let history = store.get(name);
298 history.lastPostTime = (new Date()).getTime();
299 store.set(name, history);
303 // see: http://fifnel.com/2008/11/14/1980/
304 let srcEncode = info.srcEncode || "UTF-8";
305 let urlEncode = info.urlEncode || srcEncode;
307 let m = url.match(/%s/g);
308 let repStrCount = m && m.length;
309 if (repStrCount && !parsedArgs.strs.length) continue;
311 // via. lookupDictionary.js
312 let ttbu = Components.classes["@mozilla.org/intl/texttosuburi;1"]
313 .getService(Components.interfaces.nsITextToSubURI);
316 url = url.replace(/%s/g, function(m, i) ttbu.ConvertAndEscape(urlEncode,
317 (cnt >= parsedArgs.strs.length ? parsedArgs.strs[cnt - 1] :
318 cnt >= (repStrCount - 1) ? parsedArgs.strs.splice(cnt).join(' ') :
319 parsedArgs.strs[cnt++])));
320 logger.log(url + "[" + srcEncode + "][" + urlEncode + "]::" + info.xpath);
323 liberator.open(url, liberator.NEW_TAB);
325 let req = new libly.Request(url, null, {
334 req.addEventListener("exception", $U.bind(this, this.onException));
335 req.addEventListener("success", $U.bind(this, this.onSuccess));
336 req.addEventListener("failure", $U.bind(this, this.onFailure));
338 MultiRequester.requestCount++;
342 if (MultiRequester.requestCount) {
343 logger.echo("Loading " + parsedArgs.names + " ...", commandline.FORCE_SINGLELINE);
345 MultiRequester.doProcess = false;
348 // return {names: "", strs: [""], count: 0, siteinfo: [{}]}
349 parseArgs: function(args) {
356 var sel = $U.getSelectedString();
358 if (args.length < 1 && !sel.length) return ret;
360 function parse(args, names) {
361 args = Array.concat(args);
363 ret.names = names || args.shift() || "";
364 ret.strs = (args.length < 1 ? [ sel.replace(/[\n\r]+/g, "") ] : args);
366 ret.names.split(",").forEach(function(name) {
367 var site = self.getSite(name);
370 ret.siteinfo.push(site);
377 if (!ret.siteinfo.length && this.defaultSites)
378 parse(args, this.defaultSites);
382 getSite: function(name) {
383 if (!name) this.siteinfo[0];
385 this.siteinfo.forEach(function(s) {
386 if (s.name == name) ret = s;
390 extractLink: function(res, extractLink) { //{{{
392 var el = res.getHTMLDocument(extractLink);
393 if (!el) throw "extract link failed.: extractLink -> " + extractLink;
394 var url = $U.pathToURL(el[0], res.req.url);
395 var req = new libly.Request(url, null, $U.extend(res.req.options, { extractLink: true }));
396 req.addEventListener("exception", $U.bind(this, this.onException));
397 req.addEventListener("success", $U.bind(this, this.onSuccess));
398 req.addEventListener("failure", $U.bind(this, this.onFailure));
400 MultiRequester.requestCount++;
401 MultiRequester.doProcess = true;
404 onSuccess: function(res) { //{{{
406 if (!MultiRequester.doProcess) {
407 MultiRequester.requestCount = 0;
411 logger.log("success!!: " + res.req.url);
412 MultiRequester.requestCount--;
413 if (MultiRequester.requestCount == 0) {
414 MultiRequester.doProcess = false;
417 var url, escapedUrl, xpath, doc, html, extractLink, ignoreTags;
421 if (!res.isSuccess() || res.responseText == "") throw "response is fail or null";
424 escapedUrl = util.escapeHTML(url);
425 xpath = res.req.options.siteinfo.xpath;
426 extractLink = res.req.options.siteinfo.extractLink;
428 if (extractLink && !res.req.options.extractLink) {
429 this.extractLink(res, extractLink);
432 ignoreTags = [ "script" ].concat(libly.$U.A(res.req.options.siteinfo.ignoreTags));
433 doc = document.createElementNS(null, "div");
434 res.getHTMLDocument(xpath, null, ignoreTags, function(node, i) {
435 if (node.tagName.toLowerCase() != "html")
436 doc.appendChild(node);
438 if (!doc || !doc.childNodes.length) throw "XPath result is undefined or null.: XPath -> " + xpath;
440 $U.getNodesFromXPath("descendant-or-self::a | descendant-or-self::img", doc, function(node) {
441 var tagName = node.tagName.toLowerCase();
442 if (tagName == "a") {
443 node.href = $U.pathToURL(node, url, res.doc);
444 } else if (tagName == "img") {
445 node.src = $U.pathToURL(node, url, res.doc);
449 html = '<a href="' + escapedUrl + '" class="hl-Title" target="_self">' + escapedUrl + '</a>' +
450 $U.xmlSerialize(doc);
452 MultiRequester.echoHash[res.req.options.siteinfo.name] = html;
455 logger.log("error!!: " + e);
456 MultiRequester.echoHash[res.req.options.siteinfo.name] =
457 '<span style="color: red;">error!!: ' + e + '</span>';
460 if (MultiRequester.requestCount == 0) {
462 MultiRequester.requestNames.split(",").forEach(function(name) {
463 echoList.push(MultiRequester.echoHash[name]);
465 html = '<div style="white-space:normal;"><base href="' + escapedUrl + '"/>' +
468 try { logger.echo(new XMLList(html)); } catch (e) { logger.log(e); logger.echo(html); }
472 onFailure: function(res) {
473 MultiRequester.doProcess = false;
474 logger.echoerr("request failure!!: " + res.statusText);
476 onException: function(e) {
477 MultiRequester.doProcess = false;
478 logger.echoerr("exception!!: " + e);
484 CommandRegister.register(MultiRequester, DataAccess.getSiteInfo());
485 if (liberator.globalVariables.multi_requester_mappings) {
486 CommandRegister.addUserMaps(MultiRequester.name[0], liberator.globalVariables.multi_requester_mappings);
490 return MultiRequester;
493 // vim: set fdm=marker sw=2 ts=2 sts=0 et: