added webjump_separator user variable
[conkeror/arlinius.git] / modules / webjump.js
blobb754b42d996b806c722673930d8702aee7d7d33b
1 /**
2  * (C) Copyright 2004-2007 Shawn Betts
3  * (C) Copyright 2007-2008 John J. Foerch
4  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
5  * (C) Copyright 2011 Peter Lunicks
6  *
7  * Use, modification, and distribution are subject to the terms specified in the
8  * COPYING file.
9 **/
11 define_variable("webjump_separator", ' ',
12                 "The separator character between a webjump name "+
13                 "and its arguments.");
15 var webjumps = {};
17 define_keywords("$completer", "$description", "$argument", "$alternative",
18                 "$post_data");
19 function define_webjump (key, handler) {
20     keywords(arguments);
21     var argument = arguments.$argument;
22     let alternative = arguments.$alternative;
23     var post_data = arguments.$post_data;
25     // handler may be a function or a string.  An alternative url may
26     // be passed using the $alternative keyword; it is used in place
27     // of the handler when no arguments are supplied by the user when
28     // invoking the webjump (see get_webjump).  For string webjumps
29     // that contain %s and for which no alternative is provided, an
30     // alternative is autogenerated by trimming the path from the url.
31     // A webjump can thus function both as a way to invoke a search
32     // and as a bookmark.
33     //
34     // When the handler is a string and post_data is given the webjump
35     // will result in a POST.  A '%s' element in post_data will be
36     // replaced by the webjump argument and the alternative is the
37     // same as the handler (but as a GET).
38     //
39     // The argument property may be false (no arguments will be
40     // accepted for the webjump), true (arguments are required for the
41     // webjump) or 'optional' (arguments are accepted but not
42     // required).  If the property is not specified, a sensible default
43     // is chosen depending on the type of the handler and whether an
44     // alternative is specified.  If the property is false, then
45     // completing on the name of the webjump in the minibuffer will
46     // not result in a space being appended.
47     //
48     if (typeof(handler) == "function") {
49         if (argument == null && alternative == null)
50             argument = true;
51     } else if (typeof(handler) == "string") {
52         if (post_data && alternative == null)
53             alternative = handler;
54         else if (handler.indexOf('%s') == -1)
55             argument = false;
56         else if (alternative == null)
57             alternative = url_path_trim(handler);
58     }
59     if (alternative && argument == null)
60         argument = 'optional';
62     function make_string_handler (template) {
63         var b = template.indexOf('%s');
64         return function (arg) {
65             var a = b + 2;
66             // Just return the same string if it doesn't contain a %s
67             if (b == -1)
68                 return template;
69             return template.substr(0,b) + encodeURIComponent(arg) + template.substring(a);
70         };
71     }
73     function make_post_handler (uri, post_data) {
74         return function (arg) {
75             return load_spec({
76                 uri: uri,
77                 post_data: make_post_data(post_data.map(function (pair) {
78                     if (pair[1] == '%s')
79                         return [pair[0], arg];
80                     else
81                         return pair;
82                 }))
83             });
84         };
85     }
87     if (typeof(handler) == "string") {
88         if (post_data)
89             handler = make_post_handler(handler, post_data);
90         else
91             handler = make_string_handler(handler);
92     }
94     webjumps[key] = { key: key,
95                       handler: handler,
96                       completer: arguments.$completer,
97                       description: arguments.$description,
98                       argument: argument,
99                       alternative: alternative};
102 function define_delicious_webjumps (username) {
103     define_webjump("delicious", "http://www.delicious.com/" + username + "/%s",
104                    $alternative = "http://www.delicious.com/" + username);
105     define_webjump("adelicious", "javascript:location.href='http://www.delicious.com/save"+
106                    "?v=2&url='+encodeURIComponent(location.href)+'&title='+"+
107                    "encodeURIComponent(document.title);");
108     define_webjump("sdelicious", "http://www.delicious.com/search?p=%s&u="+username+
109                    "&chk=&context=userposts&fr=del_icio_us&lc=1");
110     define_webjump("sadelicious", "http://www.delicious.com/search/all?search=%s");
113 add_delicious_webjumps = define_delicious_webjumps;
115 function define_lastfm_webjumps (username) {
116     if (! username) username = "";
117     define_webjump("lastfm", "http://www.last.fm/user/"+username);
118     define_webjump("lastfm-user", "http://www.last.fm/user/%s");
119     define_webjump("lastfm-music", "http://www.last.fm/search?m=all&q=%s");
120     define_webjump("lastfm-group", "http://www.last.fm/users/groups?s_bio=%s");
121     define_webjump("lastfm-tag", "http://www.last.fm/search?m=tag&q=%s");
122     define_webjump("lastfm-label", "http://www.last.fm/search?m=label&q=%s");
123     define_webjump("lastfm-event", "http://www.last.fm/events?by=artists&q=%s");
126 add_lastfm_webjumps = define_lastfm_webjumps;
128 function clear_webjumps () {
129     webjumps = {};
132 // Some built in web jumps
133 function define_default_webjumps () {
134     define_webjump("conkerorwiki",
135                    "http://conkeror.org/?action=fullsearch&context=60&value=%s&fullsearch=Text");
136     define_webjump("lucky",      "http://www.google.com/search?q=%s&btnI=I'm Feeling Lucky");
137     define_webjump("maps",       "http://maps.google.com/?q=%s");
138     define_webjump("scholar",    "http://scholar.google.com/scholar?q=%s");
139     define_webjump("slang",      "http://www.urbandictionary.com/define.php?term=%s");
140     define_webjump("dictionary", "http://dictionary.reference.com/search?q=%s");
141     define_webjump("image",      "http://images.google.com/images?q=%s");
142     define_webjump("clhs",
143                    "http://www.xach.com/clhs?q=%s",
144                    $alternative = "http://www.lispworks.com/documentation/HyperSpec/Front/index.htm");
145     define_webjump("cliki",      "http://www.cliki.net/admin/search?words=%s");
146     define_webjump("ratpoisonwiki", "http://ratpoison.antidesktop.net/?search=%s");
147     define_webjump("stumpwmwiki", "http://stumpwm.antidesktop.net/wiki?search=%s");
148     define_webjump("savannah",
149                    "http://savannah.gnu.org/search/?words=%s&type_of_search=soft&Search=Search&exact=1");
150     define_webjump("sourceforge", "http://sourceforge.net/search/?words=%s");
151     define_webjump("freshmeat", "http://freshmeat.net/search/?q=%s");
152     define_webjump("slashdot", "http://slashdot.org/search.pl?query=%s");
153     define_webjump("kuro5hin", "http://www.kuro5hin.org/?op=search&string=%s");
156 define_variable("webjump_partial_match", true,
157                 "When entering a url, if the input is not a webjump, " +
158                 "but would uniquely complete to a webjump, then accept " +
159                 "that webjump only if this is true.");
161 function match_webjump (str) {
162     var sp = str.indexOf(webjump_separator);
164     var key, arg;
165     if (sp == -1) {
166         key = str;
167         arg = null;
168     } else {
169         key = str.substring(0, sp);
170         arg = str.substring(sp + 1);
171         if (/^\s*$/.test(arg))
172             arg = null;
173     }
175     // Look for an exact match
176     var match = webjumps[key];
178     // Look for a partial match
179     if (!match && webjump_partial_match) {
180         for (let [k,v] in Iterator(webjumps)) {
181             if (String(k).substring(0, key.length) == key) {
182                 if (match) {
183                     // key is not a unique prefix, as there are multiple partial matches
184                     return null;
185                 }
186                 match = v;
187             }
188         }
189     }
191     if (match) {
192         if (arg == null && match.argument == true)
193             throw interactive_error('Webjump '+key+' requires an argument.');
194         return [match, key, arg];
195     }
196     return null;
200 function get_webjump (value) {
201     var res = match_webjump(value);
202     if (!res)
203         return null;
204     let [match,key,arg] = res;
205     if (arg == null && match.alternative)
206         return match.alternative;
207     return match.handler(arg);
210 function get_url_or_webjump (input) {
211     var url = get_webjump(input);
212     if (url != null)
213         return url;
214     else
215         return input;
218 define_default_webjumps();
220 function webjump_completer () {
221     let base_completer = prefix_completer(
222         $completions = [ v for ([k,v] in Iterator(webjumps)) ],
223         $get_string = function (x) { return x.key + (x.argument ? webjump_separator : ""); },
224         $get_description = function (x) { return x.description || ""; });
225     return function (input, pos, conservative) {
226         let str = input.substring(0,pos);
227         let res;
228         try { res = match_webjump(str); }
229         catch (e) { res = null; }
230         if (res) {
231             let [match, key, arg] = res;
232             if (arg != null) { // If there is no argument yet, we use the base completer
233                 if (match.completer) {
234                     let c = yield match.completer.call(null, arg, pos - key.length - 1, conservative);
235                     yield co_return(nest_completions(c, match.key + webjump_separator));
236                 }
237                 yield co_return(null);
238             }
239         }
240         yield co_return(base_completer(input, pos, conservative));
241     };
244 provide("webjump");