Access hints_default_object_classes and hints_xpath_expressions as buffer-local variables
[conkeror.git] / modules / commands.js
blob214ff218b57d1ac1b8ade12b4dcd839d3f53a822
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         paste_x_primary_selection (I.buffer.focused_element);
106     });
109 function meta_x (window, prefix, command)
111     call_interactively({window: window, prefix_argument: prefix}, command);
113 interactive("execute-extended-command",
114             "Execute a Conkeror command specified in the minibuffer.",
115             function (I) {
116                 var prefix = I.P;
117                 var prompt = "";
118                 if (prefix == null)
119                     prompt = "";
120                 else if (typeof prefix == "object")
121                     prompt = prefix[0] == 4 ? "C-u " : prefix[0] + " ";
122                 else
123                     prompt = prefix + " ";
124                 meta_x(I.window, I.P,
125                        (yield I.minibuffer.read_command(
126                            $prompt = "M-x" + prompt)));
127             });
129 /// built in commands
130 // see: http://www.xulplanet.com/tutorials/xultu/commandupdate.html
132 // Performs a command on a browser buffer content area
135 define_builtin_commands(
136     "",
137     function (I, command) { 
138         var buffer = I.buffer;
139         try {
140             buffer.do_command(command);
141         } catch (e) {
142             /* Ignore exceptions */
143         }
144     },
145     function (I) {
146         I.buffer.mark_active = !I.buffer.mark_active;
147     },
148     function (I) I.buffer.mark_active
151 function get_link_text()
153     var e = document.commandDispatcher.focusedElement;   
154     if (e && e.getAttribute("href")) {
155         return e.getAttribute("href");
156     }
157     return null;
162 function copy_email_address (loc)
164     // Copy the comma-separated list of email addresses only.
165     // There are other ways of embedding email addresses in a mailto:
166     // link, but such complex parsing is beyond us.
167     var qmark = loc.indexOf( "?" );
168     var addresses;
170     if ( qmark > 7 ) {                   // 7 == length of "mailto:"
171         addresses = loc.substring( 7, qmark );
172     } else {
173         addresses = loc.substr( 7 );
174     }
176     //XXX: the original code, which we got from firefox, unescapes the string
177     //     using the current character set.  To do this in conkeror, we
178     //     *should* use an interactive method that gives us the character set,
179     //     rather than fetching it by side-effect.
181     //     // Let's try to unescape it using a character set
182     //     // in case the address is not ASCII.
183     //     try {
184     //         var characterSet = this.target.ownerDocument.characterSet;
185     //         const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
186     //             .getService(Components.interfaces.nsITextToSubURI);
187     //         addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
188     //     }
189     //     catch(ex) {
190     //         // Do nothing.
191     //     }
192     
193     writeToClipboard(addresses);
194     message("Copied '" + addresses + "'");
196 interactive("copy-email-address", copy_email_address, ['focused_link_url']);
199 /* FIXME: fix this command */
201 interactive("source",
202             "Load a JavaScript file.",
203             function (fo) { load_rc (fo.path); }, [['f', function (a) { return "Source File: "; }, null, "source"]]);
205 function reinit (window, fn)
207     try {
208         load_rc (fn);
209         window.minibuffer.message ("Loaded: " + fn);
210     } catch (e) {
211         window.minibuffer.message ("Failed to load: "+fn);
212     }
215 interactive ("reinit",
216              "Reload the Conkeror rc file.",
217              function (I) {
218                  reinit(I.window, get_pref("conkeror.rcfile"));
219              });
221 interactive("help-page",
222             "Open the Conkeror help page.",
223             function (I) {
224                 open_in_browser(I.buffer, I.browse_target("open"),
225                                 "chrome://conkeror/content/help.html");
226             });
228 interactive("help-with-tutorial",
229             "Open the Conkeror tutorial.",
230             function (I) {
231                 open_in_browser(I.buffer, I.browse_target("open"),
232                                 "chrome://conkeror/content/tutorial.html");
233             });
235 function univ_arg_to_number(prefix, default_value)
237     if (prefix == null) {
238         if (default_value == null)
239             return 1;
240         else
241             return default_value;
242     }
243     if (typeof prefix == "object")
244         return prefix[0];
245     return prefix;
248 function eval_expression(window, s)
250     // eval in the global scope.
252     // In addition, the following variables are available:
253     // var window;
254     var buffer = window.buffers.current;
255     var result = eval(s);
256     if (result !== undefined) {
257         window.minibuffer.message(String(result));
258     }
260 interactive("eval-expression",
261             "Evaluate JavaScript statements.",
262             function (I) {
263                 eval_expression(
264                     I.window,
265                     (yield I.minibuffer.read($prompt = "Eval:",
266                                              $history = "eval-expression",
267                                              $completer = javascript_completer(I.buffer))));
268             });
271 // our little hack. Add a big blank chunk to the bottom of the
272 // page
273 const scrolly_document_observer = {
275     enabled : false,
277     observe: function(subject, topic, url)
278     {
279         // We asume the focused window is the one loading. Not always
280         // the case..tho pretty safe since conkeror is only one window.
281         try {
282             var win = document.commandDispatcher.focusedWindow;
283             var doc;
284             if (win) 
285                 doc = win.content.document;
286             else
287                 doc = content.document;
289             // Make sure we haven't already added the image
290             if (!doc.__conkeror_scrolly_hack__) {
291                 doc.__conkeror_scrolly_hack__ = true;
292                 var spc = doc.createElement("img");
293                 spc.setAttribute("width", "1");
294                 spc.setAttribute("height", getBrowser().mCurrentBrowser.boxObject.height);
295                 spc.setAttribute("src", "chrome://conkeror/content/pixel.png");
296                 doc.lastChild.appendChild(spc);
297             }
298         } catch(e) {alert(e);}
299     }
303 function toggle_eod_space()
305     var observerService = Components.classes["@mozilla.org/observer-service;1"]
306         .getService(Components.interfaces.nsIObserverService);
307     if (scrolly_document_observer.enabled) {
308         observerService.removeObserver(scrolly_document_observer, "page-end-load", false);
309         scrolly_document_observer.enabled = false;
310     } else {
311         observerService.addObserver(scrolly_document_observer, "page-end-load", false);
312         scrolly_document_observer.enabled = true;
313     }
315 interactive("toggle-eod-space", toggle_eod_space);
318 function show_extension_manager () {
319     return conkeror.window_watcher.openWindow (
320         null,
321         "chrome://mozapps/content/extensions/extensions.xul?type=extensions",
322         "ExtensionsWindow",
323         "resizable=yes,dialog=no",
324         null);
326 interactive("extensions",
327             "Open the extensions manager in a new window.",
328             show_extension_manager);
330 function print_buffer(buffer)
332     buffer.top_frame.print();
334 interactive("print-buffer",
335             "Print the currently loaded page.",
336             function (I) {print_buffer(I.buffer);});
338 function view_partial_source (window, charset, selection) {
339     if (charset) { charset = "charset=" + charset; }
340     window.window.openDialog("chrome://global/content/viewPartialSource.xul",
341                             "_blank", "scrollbars,resizable,chrome,dialog=no",
342                             null, charset, selection, 'selection');
344 //interactive ('view-partial-source', view_partial_source, I.current_window, I.content_charset, I.content_selection);
347 function  view_mathml_source (window, charset, target) {
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, target, 'mathml');
355 function send_key_as_event (window, element, key) {
356     key = kbd (key);
357     var event = window.document.createEvent ("KeyboardEvent");
358     event.initKeyEvent (
359         "keypress",
360         true,
361         true,
362         null,
363         key.modifiers & MOD_CTRL, // ctrl
364         key.modifiers & MOD_META, // alt
365         key.modifiers & MOD_SHIFT, // shift
366         key.modifiers & MOD_META, // meta
367         key.keyCode,
368         null);    // charcode
369     // bit of a hack here.. we have to fake a keydown event for conkeror
370     window.keyboard.last_key_down_event = copy_event (event);
371     if (element) {
372         return element.dispatchEvent (event);
373     } else {
374         return window.dispatchEvent (event);
375     }
377 interactive (
378     "send-ret",
379     function (I) {
380         send_key_as_event (I.window, I.buffer.focused_element, "return");
381     });