application.js: fix matching of module load error messages to work with Firefox 36
[conkeror.git] / modules / webjump.js
blob1244bc178d99302b9489f47c09a5e6a9dda1d433
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
5  *
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")))
31         {
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);
38         }
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);
64         };
65     },
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             });
78         };
79     },
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
86     }
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;
125             }
126         }
127     }
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 = [v for ([k, v] in Iterator(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);
184             }
185         }
186         // complete on the webjump name
187         yield co_return(this.webjump_name_completer.complete(input, pos));
188     }
193  * Built-in webjumps
194  */
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",    "http://scholar.google.com/scholar?q=%s");
224     define_webjump("slang",      "http://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");