kludge issue 513
[conkeror.git] / modules / webjump.js
blob86a45f224b6b450f25fe7089db7963fa214d2bce
1 /**
2 * (C) Copyright 2004-2007 Shawn Betts
3 * (C) Copyright 2007-2008,2012 John J. Foerch
4 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
6 * Use, modification, and distribution are subject to the terms specified in the
7 * COPYING file.
8 **/
10 define_keywords("$alternative", "$completer", "$doc", "$post_data",
11 "$require_match");
12 function webjump (name, handler) {
13 keywords(arguments,
14 $alternative = null,
15 $require_match = false);
16 this.name = name;
17 this.alternative = arguments.$alternative;
18 this.completer = arguments.$completer;
19 this.doc = arguments.$doc;
20 this.post_data = arguments.$post_data;
21 this.require_match = arguments.$require_match;
22 if (typeof handler == "function") {
23 if (handler.length == 0)
24 this.argument = false;
25 else if (this.alternative == null)
26 this.argument = true;
27 this.handler = handler;
28 } else if (typeof handler == "string") {
29 if (handler.indexOf("%s") == -1 &&
30 (! this.post_data || this.post_data.every(function (x) x[1] != "%s")))
32 this.argument = false;
33 } else if (this.alternative == null) {
34 if (this.post_data)
35 this.alternative = true; // use same handler
36 else
37 this.alternative = url_path_trim(handler);
39 if (this.post_data)
40 this.handler = this._make_post_handler(handler);
41 else
42 this.handler = this._make_string_handler(handler);
43 } else
44 throw Error("bad handler type");
46 webjump.prototype = {
47 constructor: webjump,
48 toString: function () "#<webjump>",
49 name: null,
50 handler: null,
51 alternative: null,
52 completer: null,
53 doc: null,
54 argument: null, // null represents optional argument
55 require_match: false,
56 _make_string_handler: function (template) {
57 var b = template.indexOf('%s');
58 return function (arg) {
59 var a = b + 2;
60 // Just return the same string if it doesn't contain a %s
61 if (b == -1)
62 return template;
63 return template.substr(0,b) + encodeURIComponent(arg) + template.substring(a);
66 _make_post_handler: function (uri) {
67 var w = this;
68 return function (arg) {
69 return load_spec({
70 uri: uri,
71 post_data: make_post_data(w.post_data.map(function (pair) {
72 if (pair[1] == '%s')
73 return [pair[0], arg];
74 else
75 return pair;
76 }))
77 });
80 call: function (arg) {
81 if (arg == null && this.argument == true)
82 throw interactive_error("Webjump "+this.name+" requires an argument.");
83 if (arg || this.alternative == true || this.argument == false)
84 return this.handler(arg);
85 return this.alternative
90 var webjumps = {};
92 function define_webjump (name, handler) {
93 keywords(arguments);
94 var w = new webjump(name, handler, forward_keywords(arguments));
95 webjumps[w.name] = w;
98 function clear_webjumps () {
99 webjumps = {};
102 define_variable("webjump_partial_match", true,
103 "When entering a url, if the input is not a webjump, " +
104 "but would uniquely complete to a webjump, then accept " +
105 "that webjump only if this is true.");
107 function match_webjump (str) {
108 var sp = str.split(/(\s+)/, 2);
109 var key = sp[0];
110 if (sp.length > 1)
111 var sep = sp[1];
112 if (sep)
113 var arg = str.substr(key.length + sep.length);
115 // Look for an exact match
116 var match = webjumps[key];
118 // Look for a partial match
119 if (! match && webjump_partial_match) {
120 for (let [k, v] in Iterator(webjumps)) {
121 if (String(k).substring(0, key.length) == key) {
122 if (match) // prefix must be unique for a partial match
123 return [null, null, null, null];
124 match = v;
128 if (match)
129 return [match, key, sep, arg];
130 return [null, null, null, null];
134 function get_webjump (value) {
135 let [w, key, sep, arg] = match_webjump(value);
136 if (! w)
137 return null;
138 return w.call(arg);
141 function get_url_or_webjump (input) {
142 return get_webjump(input) || input;
146 // a webjump completer is a nesting of two completers: one that completes
147 // on webjump names, and one specific to the individual webjump.
148 function webjump_name_completer () {
149 prefix_completer.call(this,
150 $completions = object_values(webjumps),
151 $get_string = function (x) x.name + (x.argument == false ? "" : " "),
152 $get_description = function (x) x.doc || "");
154 webjump_name_completer.prototype = {
155 constructor: webjump_name_completer,
156 __proto__: prefix_completer.prototype,
157 toString: function () "#<webjump_name_completer>"
161 function webjump_completer () {
162 completer.call(this);
163 this.webjump_name_completer = new webjump_name_completer();
165 webjump_completer.prototype = {
166 constructor: webjump_completer,
167 __proto__: completer.prototype,
168 toString: function () "#<webjump_completer>",
169 webjump_name_completer: null,
170 require_match: false,
171 complete: function (input, pos) {
172 this.require_match = false;
173 let [w, key, sep, arg] = match_webjump(input);
174 var current_part = position_in_strings([key, sep, arg], pos);
175 if (current_part % 2)
176 current_part++;
177 if (current_part) { // complete on the argument
178 if (w.completer) {
179 this.require_match = w.require_match;
180 var c = yield w.completer.complete(arg, pos - key.length - sep.length);
181 yield co_return(nest_completions(c, w.name + " "));
182 } else {
183 yield co_return(null);
186 // complete on the webjump name
187 yield co_return(this.webjump_name_completer.complete(input, pos));
193 * Built-in webjumps
196 function define_delicious_webjumps (username) {
197 define_webjump("delicious", "http://www.delicious.com/" + username + "/%s",
198 $alternative = "http://www.delicious.com/" + username);
199 define_webjump("adelicious", "javascript:location.href='http://www.delicious.com/save"+
200 "?v=2&url='+encodeURIComponent(location.href)+'&title='+"+
201 "encodeURIComponent(document.title);");
202 define_webjump("sdelicious", "http://www.delicious.com/search?p=%s&u="+username+
203 "&chk=&context=userposts&fr=del_icio_us&lc=1");
204 define_webjump("sadelicious", "http://www.delicious.com/search/all?search=%s");
207 function define_lastfm_webjumps (username) {
208 if (! username) username = "";
209 define_webjump("lastfm", "http://www.last.fm/user/"+username);
210 define_webjump("lastfm-user", "http://www.last.fm/user/%s");
211 define_webjump("lastfm-music", "http://www.last.fm/search?m=all&q=%s");
212 define_webjump("lastfm-group", "http://www.last.fm/users/groups?s_bio=%s");
213 define_webjump("lastfm-tag", "http://www.last.fm/search?m=tag&q=%s");
214 define_webjump("lastfm-label", "http://www.last.fm/search?m=label&q=%s");
215 define_webjump("lastfm-event", "http://www.last.fm/events?by=artists&q=%s");
218 function define_default_webjumps () {
219 define_webjump("conkerorwiki",
220 "http://conkeror.org/?action=fullsearch&context=60&value=%s&fullsearch=Text");
221 define_webjump("lucky", "https://www.google.com/search?q=%s&btnI=I'm Feeling Lucky");
222 define_webjump("maps", "https://maps.google.com/?q=%s");
223 define_webjump("scholar", "https://scholar.google.com/scholar?q=%s");
224 define_webjump("slang", "https://www.urbandictionary.com/define.php?term=%s");
225 define_webjump("dictionary", "http://dictionary.reference.com/search?q=%s");
226 define_webjump("image", "https://www.google.com/images?q=%s");
229 define_default_webjumps();
231 provide("webjump");