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