keyboard.js: properly assign parent keymap for auto-generated prefix keymaps
[conkeror.git] / modules / webjump.js
blobe449209dee03fa0b41e90d1a13da76709ec2f99a
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  *
6  * Use, modification, and distribution are subject to the terms specified in the
7  * COPYING file.
8 **/
10 var webjumps = new string_hashmap();
12 define_keywords("$completer", "$description", "$no_argument");
13 function define_webjump(key, handler) {
14     keywords(arguments);
15     var no_argument;
17     // handler may be a function, a string, or an array
18     // of a string and a "no args" alternate string.
19     //
20     // if the no_argument property is set on a webjump,
21     // completing on the name of the webjump will not
22     // result in a space being appended.
23     //
24     // we only pay attention to the no_argument keyword
25     // if the handler is a function.  for string webjumps,
26     // we simply see if there is a "%s" in the string.
27     //
28     if (typeof(handler) == "function") {
29         no_argument = arguments.$no_argument;
30     } else if (typeof(handler) == "string") {
31         if (handler.indexOf('%s') == -1)
32             no_argument = true;
33     }
35     function make_handler (template, alternative) {
36         if (alternative == null)
37             alternative = url_path_trim(template);
38         var b = template.indexOf('%s');
39         return function (arg) {
40             var a = b + 2;
41             if (arg == null && b > -1)
42                 return alternative;
43             // Just return the same string if it doesn't contain a %s
44             if (b == -1)
45                 return template;
46             return template.substr(0,b) + encodeURIComponent(arg) + template.substring(a);
47         };
48     }
50     if (typeof(handler) == "string")
51         handler = make_handler(handler);
52     if (typeof(handler) == "object")
53         // An array of a template and an alternative url (for no args)
54         handler = make_handler(handler[0], handler[1]);
56     webjumps.put(key,
57                  {key: key,
58                   handler: handler, completer: arguments.$completer,
59                   description: arguments.$description,
60                   no_argument: no_argument});
63 // Compatibility
64 var add_webjump = define_webjump;
66 function add_delicious_webjumps (username)
68     define_webjump("delicious", "http://del.icio.us/" + username);
69     define_webjump("adelicious", "javascript:location.href='http://del.icio.us/"+username+
70                    "?v=2&url='+encodeURIComponent(location.href)+'&title='+"+
71                    "encodeURIComponent(document.title);");
72     define_webjump("sdelicious", "http://delicious.com/search?p=%s&u="+username+
73                    "&chk=&context=userposts&fr=del_icio_us&lc=1");
74     define_webjump("sadelicious", "http://del.icio.us/search/all?search=%s");
77 function add_lastfm_webjumps(username)
79     if (! username) username = "";
80     define_webjump("lastfm", "http://www.last.fm/user/"+username);
81     define_webjump("lastfm-user", "http://www.last.fm/user/%s");
82     define_webjump("lastfm-music", "http://www.last.fm/search?m=all&q=%s");
83     define_webjump("lastfm-group", "http://www.last.fm/users/groups?s_bio=%s");
84     define_webjump("lastfm-tag", "http://www.last.fm/search?m=tag&q=%s");
85     define_webjump("lastfm-label", "http://www.last.fm/search?m=label&q=%s");
86     define_webjump("lastfm-event", "http://www.last.fm/events?by=artists&q=%s");
89 function clear_webjumps()
91     webjumps = {};
94 // Some built in web jumps
95 function define_default_webjumps()
97     define_webjump("conkerorwiki",
98                 "http://conkeror.org/?action=fullsearch&context=60&value=%s&fullsearch=Text");
99     define_webjump("lucky",      "http://www.google.com/search?q=%s&btnI=I'm Feeling Lucky");
100     define_webjump("maps",       "http://maps.google.com/?q=%s");
101     define_webjump("scholar",    "http://scholar.google.com/scholar?q=%s");
102     define_webjump("clusty",     "http://www.clusty.com/search?query=%s");
103     define_webjump("slang",      "http://www.urbandictionary.com/define.php?term=%s");
104     define_webjump("dictionary", "http://dictionary.reference.com/search?q=%s");
105     define_webjump("xulplanet",  ["http://www.google.com/custom?q=%s&cof=S%3A"+
106                                   "http%3A%2F%2Fwww.xulplanet.com%3BAH%3Aleft%3BLH%3A65%3BLC"+
107                                   "%3A4682B4%3BL%3Ahttp%3A%2F%2Fwww.xulplanet.com%2Fimages%2F"+
108                                   "xulplanet.png%3BALC%3Ablue%3BLW%3A215%3BAWFID%3A0979f384d5"+
109                                   "181409%3B&domains=xulplanet.com&sitesearch=xulplanet.com&sa=Go",
110                                   "http://xulplanet.com"]);
111     define_webjump("image",      "http://images.google.com/images?q=%s");
112     define_webjump("imdb",       "http://www.imdb.com/find?s=all&q=%s&x=0&y=0");
113     define_webjump("clhs",       ["http://www.xach.com/clhs?q=%s", "http://www.lispworks.com/documentation/HyperSpec/Front/index.htm"]);
114     define_webjump("emacswiki",  "http://www.emacswiki.org/cgi-bin/wiki?search=%s");
115     define_webjump("cliki",      "http://www.cliki.net/admin/search?words=%s");
116     define_webjump("ratpoisonwiki", "http://ratpoison.antidesktop.net/?search=%s");
117     define_webjump("stumpwmwiki", "http://stumpwm.antidesktop.net/wiki?search=%s");
118     define_webjump("savannah", "http://savannah.gnu.org/search/?words=%s&type_of_search=soft&Search=Search&exact=1");
119     define_webjump("sourceforge", "http://sourceforge.net/search/?words=%s");
120     define_webjump("freshmeat", "http://freshmeat.net/search/?q=%s");
121     define_webjump("slashdot", "http://slashdot.org/search.pl?query=%s");
122     define_webjump("kuro5hin", "http://www.kuro5hin.org/?op=search&string=%s");
123     define_webjump("sheldonbrown",     "http://www.google.com/search?q=site:sheldonbrown.com %s");
124     define_webjump("youtube", "http://www.youtube.com/results?search_query=%s&search=Search");
127 function match_webjump(str) {
128     var sp = str.indexOf(' ');
130     var key, arg;
131     if (sp == -1) {
132         key = str;
133         arg = null;
134     } else {
135         key = str.substring(0, sp);
136         arg = str.substring(sp + 1);
137         if (/^\s*$/.test(arg))
138             arg = null;
139     }
141     // Look for an exact match
142     var match = webjumps.get(key);
144     // Look for a partial match
145     if (!match) {
146         for (let [k,v] in webjumps.iterator()) {
147             if (k.substring(0, key.length) == key) {
148                 if (match) {
149                     // key is not a unique prefix, as there are multiple partial matches
150                     return null;
151                 }
152                 match = v;
153             }
154         }
155     }
157     if (match) {
158         if (arg == null && !match.no_argument) {
159             throw interactive_error('Webjump '+key+' requires an argument.');
160         }
161         return [match, key, arg];
162     }
163     return null;
167 function getWebJump(value)
169     var res = match_webjump(value);
170     if (!res)
171         return null;
172     let [match,key,arg] = res;
173     return match.handler(arg);
176 function get_url_or_webjump(input)
178     var url = getWebJump(input);
180     if (url != null) {
181         return url;
182     } else {
183         return input;
184     }
187 define_default_webjumps();
189 function webjump_completer()
191     let base_completer = prefix_completer(
192         $completions = [ v for ([k,v] in webjumps.iterator()) ],
193         $get_string = function (x) { return x.key + (x.no_argument==true ? "" : " "); },
194         $get_description = function (x) { return x.description || ""; });
196     return function(input, pos, conservative) {
197         let str = input.substring(0,pos);
198         let res;
199         try { res = match_webjump(str); }
200         catch (e) { res = null; }
201         if (res) {
202             let [match, key, arg] = res;
203             if (arg != null) { // If there is no argument yet, we use the base completer
204                 if (match.completer) {
205                     let c = yield match.completer.call(null, arg, pos - key.length - 1, conservative);
206                     yield co_return(nest_completions(c, match.key + " "));
207                 }
208                 yield co_return(null);
209             }
210         }
211         yield co_return(base_completer(input, pos, conservative));
212     };