Add initial OpenSearch search engine support
[conkeror.git] / modules / commands.js
blobd9baa51b64dda3f5dc5079d279bc7c96ad0c776b
1 /***** BEGIN LICENSE BLOCK *****
2 Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 The contents of this file are subject to the Mozilla Public License Version
5 1.1 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7 http://www.mozilla.org/MPL/
9 Software distributed under the License is distributed on an "AS IS" basis,
10 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 for the specific language governing rights and limitations under the
12 License.
14 The Initial Developer of the Original Code is Shawn Betts.
15 Portions created by the Initial Developer are Copyright (C) 2004,2005
16 by the Initial Developer. All Rights Reserved.
18 Alternatively, the contents of this file may be used under the terms of
19 either the GNU General Public License Version 2 or later (the "GPL"), or
20 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
21 in which case the provisions of the GPL or the LGPL are applicable instead
22 of those above. If you wish to allow use of your version of this file only
23 under the terms of either the GPL or the LGPL, and not to allow others to
24 use your version of this file under the terms of the MPL, indicate your
25 decision by deleting the provisions above and replace them with the notice
26 and other provisions required by the GPL or the LGPL. If you do not delete
27 the provisions above, a recipient may use your version of this file under
28 the terms of any one of the MPL, the GPL or the LGPL.
29 ***** END LICENSE BLOCK *****/
31 require("content-buffer.js");
33 define_hook("quit_hook");
35 function quit ()
37     quit_hook.run();
38     var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
39         .getService(Ci.nsIAppStartup);
40     appStartup.quit(appStartup.eAttemptQuit);
42 interactive("quit",
43             "Quit Conkeror",
44             quit);
47 function show_conkeror_version (window)
49     window.minibuffer.message (conkeror.version);
51 interactive ("conkeror-version",
52              "Show version information for Conkeror.",
53              function (I) {show_conkeror_version(I.window);});
55 /* FIXME: maybe this should be supported for non-browser buffers */
56 function scroll_horiz_complete (buffer, n)
58     var w = buffer.focused_frame;
59     w.scrollTo (n > 0 ? w.scrollMaxX : 0, w.scrollY);
61 interactive("scroll-beginning-of-line",
62             "Scroll the current frame all the way to the left.",
63             function (I) {scroll_horiz_complete(I.buffer, -1);});
65 interactive("scroll-end-of-line",
66             "Scroll the current frame all the way to the right.",
67             function (I) {scroll_horiz_complete(I.buffer, 1);});
69 interactive("make-window",
70             "Make a new window.",
71             function (I) {
72                 make_window(buffer_creator(content_buffer,
73                                            $load = homepage,
74                                            $configuration = I.buffer.configuration));
75             });
77 function delete_window (window)
79     window.window.close();
81 interactive("delete-window",
82             "Delete the current window.",
83             function (I) {delete_window(I.window);});
85 interactive("jsconsole",
86             "Open the JavaScript console.",
87             function (I) {
88                 open_in_browser(I.buffer,
89                                 I.browse_target("jsconsole"),
90                                 "chrome://global/content/console.xul");
91             });
92 default_browse_targets["jsconsole"] = "find-url";
95 function paste_x_primary_selection (field) {
96     var str = read_from_x_primary_selection ();
97     var point = field.selectionEnd;
98     field.value = field.value.substr (0, field.selectionStart) +
99         str + field.value.substr (field.selectionEnd);
100     field.setSelectionRange (point, point);
102 interactive (
103     "paste-x-primary-selection",
104     function (I) {
105         var m = I.window.minibuffer;
106         var s = m.current_state;
107         if (m._input_mode_enabled) {
108             m._restore_normal_state();
109             var e = m.input_element;
110         } else
111             var e = I.buffer.focused_element;
112         paste_x_primary_selection (e);
113         if (s && s.handle_input)
114             s.handle_input(m);
115     });
118 function meta_x (window, prefix, command)
120     call_interactively({window: window, prefix_argument: prefix}, command);
122 interactive("execute-extended-command",
123             "Execute a Conkeror command specified in the minibuffer.",
124             function (I) {
125                 var prefix = I.P;
126                 var prompt = "";
127                 if (prefix == null)
128                     prompt = "";
129                 else if (typeof prefix == "object")
130                     prompt = prefix[0] == 4 ? "C-u " : prefix[0] + " ";
131                 else
132                     prompt = prefix + " ";
133                 meta_x(I.window, I.P,
134                        (yield I.minibuffer.read_command(
135                            $prompt = "M-x" + prompt)));
136             });
138 /// built in commands
139 // see: http://www.xulplanet.com/tutorials/xultu/commandupdate.html
141 // Performs a command on a browser buffer content area
144 define_builtin_commands(
145     "",
146     function (I, command) { 
147         var buffer = I.buffer;
148         try {
149             buffer.do_command(command);
150         } catch (e) {
151             /* Ignore exceptions */
152         }
153     },
154     function (I) {
155         I.buffer.mark_active = !I.buffer.mark_active;
156     },
157     function (I) I.buffer.mark_active
160 function get_link_text()
162     var e = document.commandDispatcher.focusedElement;   
163     if (e && e.getAttribute("href")) {
164         return e.getAttribute("href");
165     }
166     return null;
171 function copy_email_address (loc)
173     // Copy the comma-separated list of email addresses only.
174     // There are other ways of embedding email addresses in a mailto:
175     // link, but such complex parsing is beyond us.
176     var qmark = loc.indexOf( "?" );
177     var addresses;
179     if ( qmark > 7 ) {                   // 7 == length of "mailto:"
180         addresses = loc.substring( 7, qmark );
181     } else {
182         addresses = loc.substr( 7 );
183     }
185     //XXX: the original code, which we got from firefox, unescapes the string
186     //     using the current character set.  To do this in conkeror, we
187     //     *should* use an interactive method that gives us the character set,
188     //     rather than fetching it by side-effect.
190     //     // Let's try to unescape it using a character set
191     //     // in case the address is not ASCII.
192     //     try {
193     //         var characterSet = this.target.ownerDocument.characterSet;
194     //         const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
195     //             .getService(Components.interfaces.nsITextToSubURI);
196     //         addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
197     //     }
198     //     catch(ex) {
199     //         // Do nothing.
200     //     }
201     
202     writeToClipboard(addresses);
203     message("Copied '" + addresses + "'");
205 interactive("copy-email-address", copy_email_address, ['focused_link_url']);
208 /* FIXME: fix this command */
210 interactive("source",
211             "Load a JavaScript file.",
212             function (fo) { load_rc (fo.path); }, [['f', function (a) { return "Source File: "; }, null, "source"]]);
214 function reinit (window, fn)
216     try {
217         load_rc (fn);
218         window.minibuffer.message ("Loaded: " + fn);
219     } catch (e) {
220         window.minibuffer.message ("Failed to load: "+fn);
221     }
224 interactive ("reinit",
225              "Reload the Conkeror rc file.",
226              function (I) {
227                  reinit(I.window, get_pref("conkeror.rcfile"));
228              });
230 interactive("help-page",
231             "Open the Conkeror help page.",
232             function (I) {
233                 open_in_browser(I.buffer, I.browse_target("open"),
234                                 "chrome://conkeror/content/help.html");
235             });
237 interactive("help-with-tutorial",
238             "Open the Conkeror tutorial.",
239             function (I) {
240                 open_in_browser(I.buffer, I.browse_target("open"),
241                                 "chrome://conkeror/content/tutorial.html");
242             });
244 function univ_arg_to_number(prefix, default_value)
246     if (prefix == null) {
247         if (default_value == null)
248             return 1;
249         else
250             return default_value;
251     }
252     if (typeof prefix == "object")
253         return prefix[0];
254     return prefix;
257 function eval_expression(window, s)
259     // eval in the global scope.
261     // In addition, the following variables are available:
262     // var window;
263     var buffer = window.buffers.current;
264     var result = eval(s);
265     if (result !== undefined) {
266         window.minibuffer.message(String(result));
267     }
269 interactive("eval-expression",
270             "Evaluate JavaScript statements.",
271             function (I) {
272                 eval_expression(
273                     I.window,
274                     (yield I.minibuffer.read($prompt = "Eval:",
275                                              $history = "eval-expression",
276                                              $completer = javascript_completer(I.buffer))));
277             });
280 // our little hack. Add a big blank chunk to the bottom of the
281 // page
282 const scrolly_document_observer = {
284     enabled : false,
286     observe: function(subject, topic, url)
287     {
288         // We asume the focused window is the one loading. Not always
289         // the case..tho pretty safe since conkeror is only one window.
290         try {
291             var win = document.commandDispatcher.focusedWindow;
292             var doc;
293             if (win) 
294                 doc = win.content.document;
295             else
296                 doc = content.document;
298             // Make sure we haven't already added the image
299             if (!doc.__conkeror_scrolly_hack__) {
300                 doc.__conkeror_scrolly_hack__ = true;
301                 var spc = doc.createElement("img");
302                 spc.setAttribute("width", "1");
303                 spc.setAttribute("height", getBrowser().mCurrentBrowser.boxObject.height);
304                 spc.setAttribute("src", "chrome://conkeror/content/pixel.png");
305                 doc.lastChild.appendChild(spc);
306             }
307         } catch(e) {alert(e);}
308     }
312 function toggle_eod_space()
314     var observerService = Components.classes["@mozilla.org/observer-service;1"]
315         .getService(Components.interfaces.nsIObserverService);
316     if (scrolly_document_observer.enabled) {
317         observerService.removeObserver(scrolly_document_observer, "page-end-load", false);
318         scrolly_document_observer.enabled = false;
319     } else {
320         observerService.addObserver(scrolly_document_observer, "page-end-load", false);
321         scrolly_document_observer.enabled = true;
322     }
324 interactive("toggle-eod-space", toggle_eod_space);
327 function show_extension_manager () {
328     return conkeror.window_watcher.openWindow (
329         null,
330         "chrome://mozapps/content/extensions/extensions.xul?type=extensions",
331         "ExtensionsWindow",
332         "resizable=yes,dialog=no",
333         null);
335 interactive("extensions",
336             "Open the extensions manager in a new window.",
337             show_extension_manager);
339 function print_buffer(buffer)
341     buffer.top_frame.print();
343 interactive("print-buffer",
344             "Print the currently loaded page.",
345             function (I) {print_buffer(I.buffer);});
347 function view_partial_source (window, charset, selection) {
348     if (charset) { charset = "charset=" + charset; }
349     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
350                             "_blank", "scrollbars,resizable,chrome,dialog=no",
351                             null, charset, selection, 'selection');
353 //interactive ('view-partial-source', view_partial_source, I.current_window, I.content_charset, I.content_selection);
356 function  view_mathml_source (window, charset, target) {
357     if (charset) { charset = "charset=" + charset; }
358     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
359                             "_blank", "scrollbars,resizable,chrome,dialog=no",
360                             null, charset, target, 'mathml');
364 function send_key_as_event (window, element, key) {
365     key = kbd (key)[0];
366     var event = window.document.createEvent ("KeyboardEvent");
367     event.initKeyEvent (
368         "keypress",
369         true,
370         true,
371         null,
372         key.modifiers & MOD_CTRL, // ctrl
373         key.modifiers & MOD_META, // alt
374         key.modifiers & MOD_SHIFT, // shift
375         key.modifiers & MOD_META, // meta
376         key.keyCode,
377         null);    // charcode
378     // bit of a hack here.. we have to fake a keydown event for conkeror
379     window.keyboard.last_key_down_event = copy_event (event);
380     if (element) {
381         return element.dispatchEvent (event);
382     } else {
383         return window.dispatchEvent (event);
384     }
386 interactive (
387     "send-ret",
388     function (I) {
389         send_key_as_event (I.window, I.buffer.focused_element, "return");
390     });
392 function ensure_content_focused(buffer) {
393     var foc = buffer.focused_frame_or_null;
394     if (!foc)
395         buffer.top_frame.focus();
397 interactive("ensure-content-focused", "Ensure that the content document has focus.",
398             function (I) { ensure_content_focused(I.buffer); });