page-modes/gmail.js: add more fall-throughs, fix focus, support other input modes
[conkeror.git] / modules / utils.js
blob418f3343eb9619e681c49d6390e97618640c1dc7
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 *****/
32  * Utility functions for application scope.
33  *
34  */
37 function string_hashset() {
40 string_hashset.prototype = {
41     constructor : string_hashset,
43     add : function(s) {
44         this["-" + s] = true;
45     },
46     
47     contains : function(s) {
48         return (("-" + s) in this);
49     },
51     remove : function (s) {
52         delete this["-" + s];
53     },
55     for_each : function (f) {
56         for (var i in this) {
57             if (i[0] == "-")
58                 f(i.slice(1));
59         }
60     }
63 function string_hashmap() {
66 string_hashmap.prototype = {
67     constructor : string_hashmap,
69     put : function(s,value) {
70         this["-" + s] = value;
71     },
72     
73     contains : function(s) {
74         return (("-" + s) in this);
75     },
77     get : function(s, default_value) {
78         if (this.contains(s))
79             return this["-" + s];
80         return default_value;
81     },
83     get_put_default : function(s, default_value) {
84         if (this.contains(s))
85             return this["-" + s];
86         return (this["-" + s] = default_value);
87     },
89     remove : function (s) {
90         delete this["-" + s];
91     },
93     for_each : function (f) {
94         for (var i in this) {
95             if (i[0] == "-")
96                 f(i.slice(1), this[i]);
97         }
98     },
100     for_each_value : function (f) {
101         for (var i in this) {
102             if (i[0] == "-")
103                 f(this[i]);
104         }
105     }
108 /// Window title formatting
111  * Default tile formatter.  The page url is ignored.  If there is a
112  * page_title, returns: "Page title - Conkeror".  Otherwise, it
113  * returns just: "Conkeror".
114  */
115 function default_title_formatter (window)
117     var page_title = window.buffers.current.title;
119     if (page_title && page_title.length > 0)
120         return page_title + " - Conkeror";
121     else
122         return "Conkeror";
125 var title_format_fn = null;
127 function set_window_title (window)
129     window.document.title = title_format_fn(window);
132 function init_window_title ()
134     title_format_fn = default_title_formatter;
136     add_hook("window_initialize_late_hook", set_window_title);
137     add_hook("current_content_buffer_location_change_hook",
138              function (buffer) {
139                  set_window_title(buffer.window);
140              });
141     add_hook("select_buffer_hook", function (buffer) { set_window_title(buffer.window); }, true);
142     add_hook("current_buffer_title_change_hook",
143              function (buffer) {
144                  set_window_title(buffer.window);
145              });
148 init_window_title ();
153 // Put the string on the clipboard
154 function writeToClipboard(str)
156     const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
157         .getService(Components.interfaces.nsIClipboardHelper);
158     gClipboardHelper.copyString(str);
162 function makeURLAbsolute (base, url)
164     // Construct nsIURL.
165     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
166         .getService(Components.interfaces.nsIIOService);
167     var baseURI  = ioService.newURI(base, null, null);
169     return ioService.newURI (baseURI.resolve (url), null, null).spec;
173 function get_link_location (element)
175     if (element && element.getAttribute("href")) {
176         var loc = element.getAttribute("href");
177         return makeURLAbsolute(element.baseURI, loc);
178     }
179     return null;
183 function makeURL(aURL)
185     var ioService = Cc["@mozilla.org/network/io-service;1"]
186         .getService(Ci.nsIIOService);
187     return ioService.newURI(aURL, null, null);
190 function make_uri(uri) {
191     if (uri instanceof Ci.nsIURI)
192         return uri;
193     var io_service = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
194     return io_service.newURI(uri, null, null);
197 function makeFileURL(aFile)
199     var ioService = Cc["@mozilla.org/network/io-service;1"]
200         .getService(Ci.nsIIOService);
201     return ioService.newFileURI(aFile);
205 function get_document_content_disposition (document_o)
207     var content_disposition = null;
208     try {
209         content_disposition =
210             document_o.defaultView
211             .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
212             .getInterface(Components.interfaces.nsIDOMWindowUtils)
213             .getDocumentMetadata("content-disposition");
214     } catch (e) { }
215     return content_disposition;
219 function set_focus_no_scroll(window, element)
221     window.document.commandDispatcher.suppressFocusScroll = true;
222     element.focus();
223     window.document.commandDispatcher.suppressFocusScroll = false;
226 function do_repeatedly_positive(func, n) {
227     var args = Array.prototype.slice.call(arguments, 2);
228     while (n-- > 0)
229         func.apply(null, args);
232 function do_repeatedly(func, n, positive_args, negative_args) {
233     if (n < 0)
234         do func.apply(null, negative_args); while (++n < 0);
235     else
236         while (n-- > 0) func.apply(null, positive_args);
239 // remove whitespace from the beginning and end
240 function trim_whitespace (str)
242     var tmp = new String (str);
243     return tmp.replace (/^\s+/, "").replace (/\s+$/, "");
246 function abs_point (node)
248     var orig = node;
249     var pt = {};
250     try {
251         pt.x = node.offsetLeft;
252         pt.y = node.offsetTop;
253         // find imagemap's coordinates
254         if (node.tagName == "AREA") {
255             var coords = node.getAttribute("coords").split(",");
256             pt.x += Number(coords[0]);
257             pt.y += Number(coords[1]);
258         }
260         node = node.offsetParent;
261         // Sometimes this fails, so just return what we got.
263         while (node.tagName != "BODY") {
264             pt.x += node.offsetLeft;
265             pt.y += node.offsetTop;
266             node = node.offsetParent;
267         }
268     } catch(e) {
269 //      node = orig;
270 //      while (node.tagName != "BODY") {
271 //          alert("okay: " + node + " " + node.tagName + " " + pt.x + " " + pt.y);
272 //          node = node.offsetParent;
273 //      }
274     }
275     return pt;
278 var xul_app_info = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
279 var xul_runtime = Cc['@mozilla.org/xre/app-info;1'].getService(Ci.nsIXULRuntime);
282 function get_os ()
284     // possible return values: 'Darwin', 'Linux', 'WINNT', ...
285     return xul_runtime.OS;
288 var default_directory = null;
290 var env = Cc['@mozilla.org/process/environment;1'].getService(Ci.nsIEnvironment);
291 function getenv (variable) {
292     if (env.exists (variable))
293         return env.get(variable);
294     return null;
297 function set_default_directory(directory_s) {
298     if (! directory_s)
299     {
300         if ( get_os() == "WINNT")
301         {
302             directory_s = getenv ('USERPROFILE') ||
303                 getenv ('HOMEDRIVE') + getenv ('HOMEPATH');
304         }
305         else {
306             directory_s = getenv ('HOME');
307         }
308     }
310     default_directory = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
311     default_directory.initWithPath (directory_s);
314 set_default_directory();
316 const XHTML_NS = "http://www.w3.org/1999/xhtml";
317 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
318 const MATHML_NS = "http://www.w3.org/1998/Math/MathML";
319 const XLINK_NS = "http://www.w3.org/1999/xlink";
321 function create_XUL(window, tag_name)
323     return window.document.createElementNS(XUL_NS, tag_name);
327 /* Used in calls to XPath evaluate */
328 function xpath_lookup_namespace(prefix) {
329     if (prefix == "xhtml")
330         return XHTML_NS;
331     if (prefix == "m")
332         return MATHML_NS;
333     if (prefix == "xul")
334         return XUL_NS;
335     return null;
338 function method_caller(obj, func) {
339     return function () {
340         func.apply(obj, arguments);
341     }
344 function shell_quote(str) {
345     var s = str.replace("\"", "\\\"", "g");
346     s = s.replace("$", "\$", "g");
347     return s;
350 function get_window_from_frame(frame) {
351     try {
352         var window = frame.QueryInterface(Ci.nsIInterfaceRequestor)
353             .getInterface(Ci.nsIWebNavigation)
354             .QueryInterface(Ci.nsIDocShellTreeItem)
355             .rootTreeItem
356             .QueryInterface(Ci.nsIInterfaceRequestor)
357             .getInterface(Ci.nsIDOMWindow).wrappedJSObject;
358         /* window is now an XPCSafeJSObjectWrapper */
359         window.escape_wrapper(function (w) { window = w; });
360         /* window is now completely unwrapped */
361         return window;
362     } catch (e) {
363         return null;
364     }
367 function get_buffer_from_frame(window, frame) {
368     var count = window.buffers.count;
369     for (var i = 0; i < count; ++i) {
370         var b = window.buffers.get_buffer(i);
371         if (b.top_frame == frame)
372             return b;
373     }
374     return null;
377 var file_locator = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
379 function get_shortdoc_string(doc) {
380     var shortdoc = null;
381     if (doc != null) {
382         var idx = doc.indexOf("\n");
383         if (idx >= 0)
384             shortdoc = doc.substring(0,idx);
385         else
386             shortdoc = doc;
387     }
388     return shortdoc;
391 var conkeror_source_code_path = null;
393 function source_code_reference(uri, line_number) {
394     this.uri = uri;
395     this.line_number = line_number;
397 source_code_reference.prototype = {
398     get module_name () {
399         if (this.uri.indexOf(module_uri_prefix) == 0)
400             return this.uri.substring(module_uri_prefix.length);
401         return null;
402     },
404     get file_name () {
405         var file_uri_prefix = "file://";
406         if (this.uri.indexOf(file_uri_prefix) == 0)
407             return this.uri.substring(file_uri_prefix.length);
408         return null;
409     },
411     get best_uri () {
412         if (conkeror_source_code_path != null) {
413             var module_name = this.module_name;
414             if (module_name != null)
415                 return "file://" + conkeror_source_code_path + "/modules/" + module_name;
416         }
417         return this.uri;
418     },
420     open_in_editor : function() {
421         yield open_with_external_editor(this.best_uri, $line = this.line_number);
422     }
425 var get_caller_source_code_reference_ignored_functions = {};
427 function get_caller_source_code_reference(extra_frames_back) {
428     /* Skip at least this function itself and whoever called it (and
429      * more if the caller wants to be skipped). */
430     var frames_to_skip = 2;
431     if (extra_frames_back != null)
432         frames_to_skip += extra_frames_back;
434     for (let f = Components.stack; f != null; f = f.caller) {
435         if (frames_to_skip > 0) {
436             --frames_to_skip;
437             continue;
438         }
439         if (get_caller_source_code_reference_ignored_functions[f.name])
440             continue;
441         return new source_code_reference(f.filename, f.lineNumber);
442     }
444     return null;
447 function ignore_function_for_get_caller_source_code_reference(func_name) {
448     get_caller_source_code_reference_ignored_functions[func_name] = 1;
451 require_later("external-editor.js");
453 function dom_generator(document, ns) {
454     this.document = document;
455     this.ns = ns;
457 dom_generator.prototype = {
458     element : function(tag, parent) {
459         var node = this.document.createElementNS(this.ns, tag);
460         var i = 1;
461         if (parent != null && (parent instanceof Ci.nsIDOMNode)) {
462             parent.appendChild(node);
463             i = 2;
464         }
465         for (; i < arguments.length; i += 2)
466             node.setAttribute(arguments[i], arguments[i+1]);
467         return node;
468     },
470     text : function(str, parent) {
471         var node = this.document.createTextNode(str);
472         if (parent)
473             parent.appendChild(node);
474         return node;
475     },
478     stylesheet_link : function(href, parent) {
479         var node = this.element("link");
480         node.setAttribute("rel", "stylesheet");
481         node.setAttribute("type", "text/css");
482         node.setAttribute("href", href);
483         if (parent)
484             parent.appendChild(node);
485         return node;
486     },
489     add_stylesheet : function (url) {
490         var head = this.document.documentElement.firstChild;
491         this.stylesheet_link(url, head);
492     }
496  * Generates a QueryInterface function suitable for an implemenation
497  * of an XPCOM interface.  Unlike XPCOMUtils, this uses the Function
498  * constructor to generate a slightly more efficient version.  The
499  * arguments can be either Strings or elements of
500  * Components.interfaces.
501  */
502 function generate_QI() {
503     var args = Array.prototype.slice.call(arguments).map(String).concat(["nsISupports"]);
504     var fstr = "if(" +
505         Array.prototype.map.call(args,
506                                  function (x)
507                                      "iid.equals(Components.interfaces." + x + ")")
508         .join("||") +
509         ") return this; throw Components.results.NS_ERROR_NO_INTERFACE;";
510     return new Function("iid", fstr);
513 function set_branch_pref(branch, name, value) {
514     if (typeof(value) == "string") {
515         branch.setCharPref(name, value);
516     } else if (typeof(value) == "number") {
517         branch.setIntPref(name, value);
518     } else if (typeof(value) == "boolean") {
519         branch.setBoolPref(name, value);
520     }
523 function default_pref(name, value) {
524     var branch = preferences.getDefaultBranch(null);
525     set_branch_pref(branch, name, value);
528 function user_pref(name, value) {
529     var branch = preferences.getBranch(null);
530     set_branch_pref(branch, name, value);
533 function get_branch_pref(branch, name) {
534     switch (branch.getPrefType(name)) {
535     case branch.PREF_STRING:
536         return branch.getCharPref(name);
537     case branch.PREF_INT:
538         return branch.getIntPref(name);
539     case branch.PREF_BOOL:
540         return branch.getBoolPref(name);
541     default:
542         return null;
543     }
546 function get_pref(name) {
547     var branch = preferences.getBranch(null);
548     return get_branch_pref(branch, name);
551 function get_default_pref(name) {
552     var branch = preferences.getDefaultBranch(null);
553     return get_branch_pref(branch, name);
556 function clear_pref(name) {
557     var branch = preferences.getBranch(null);
558     return branch.clearUserPref(name);
561 function clear_default_pref(name) {
562     var branch = preferences.getDefaultBranch(null);
563     return branch.clearUserPref(name);
566 function pref_has_user_value(name) {
567     var branch = preferences.getBranch(null);
568     return branch.prefHasUserValue(name);
571 function pref_has_default_value(name) {
572     var branch = preferences.getDefaultBranch(null);
573     return branch.prefHasUserValue(name);
576 function session_pref (name, value) {
577     try { clear_pref (name); }
578     catch (e) {}
579     return default_pref (name, value);
582 const USER_AGENT_OVERRIDE_PREF = "general.useragent.override";
584 function set_user_agent(str) {
585     session_pref(USER_AGENT_OVERRIDE_PREF, str);
588 function define_builtin_commands(prefix, do_command_function, toggle_mark, mark_active_predicate) {
590     // Specify a docstring
591     function D(cmd, docstring) {
592         var o = new String(cmd);
593         o.doc = docstring;
594         return o;
595     }
597     // Specify a forward/reverse pair
598     function R(a, b) {
599         var o = [a,b];
600         o.is_reverse_pair = true;
601         return o;
602     }
604     // Specify a movement/select command pair.
605     function S(command, movement, select) {
606         var o = [movement, select];
607         o.command = command;
608         o.is_move_select_pair = true;
609         return o;
610     }
612     var builtin_commands = [
613         S(D("beginning-of-line", "Move or extend the selection to the beginning of the current line."),
614           D("cmd_beginLine", "Move point to the beginning of the current line."),
615           D("cmd_selectBeginLine", "Extend selection to the beginning of the current line.")),
616         S(D("end-of-line", "Move or extend the selection to the end of the current line."),
617           D("cmd_endLine", "Move point to the end of the current line."),
618           D("cmd_selectEndLine", "Extend selection to the end of the current line.")),
619         D("cmd_copy", "Copy the selection into the clipboard."),
620         "cmd_copyOrDelete",
621         D("cmd_cut", "Cut the selection into the clipboard."),
622         "cmd_cutOrDelete",
623         D("cmd_deleteToBeginningOfLine", "Delete to the beginning of the current line."),
624         D("cmd_deleteToEndOfLine", "Delete to the end of the current line."),
625         S(D("beginning-of-first-line", "Move or extend the selection to the beginning of the first line."),
626           D("cmd_moveTop", "Move point to the beginning of the first line."),
627           D("cmd_selectTop", "Extend selection to the beginning of the first line.")),
628         S(D("end-of-last-line", "Move or extend the selection to the end of the last line."),
629           D("cmd_moveBottom", "Move point to the end of the last line."),
630           D("cmd_selectBottom", "Extend selection to the end of the last line.")),
631         D("cmd_selectAll", "Select all."),
632         "cmd_scrollBeginLine",
633         "cmd_scrollEndLine",
634         D("cmd_scrollTop", "Scroll to the top of the buffer."),
635         D("cmd_scrollBottom", "Scroll to the bottom of the buffer.")];
637     var builtin_commands_with_count = [
638         R(S(D("forward-char", "Move or extend the selection forward one character."),
639             D("cmd_charNext", "Move point forward one character."),
640             D("cmd_selectCharNext", "Extend selection forward one character.")),
641           S(D("backward-char", "Move or extend the selection backward one character."),
642             D("cmd_charPrevious", "Move point backward one character."),
643             D("cmd_selectCharPrevious", "Extend selection backward one character."))),
644         R(D("cmd_deleteCharForward", "Delete the following character."),
645           D("cmd_deleteCharBackward", "Delete the previous character.")),
646         R(D("cmd_deleteWordForward", "Delete the following word."),
647           D("cmd_deleteWordBackward", "Delete the previous word.")),
648         R(S(D("forward-line", "Move or extend the selection forward one line."),
649             D("cmd_lineNext", "Move point forward one line."),
650             "cmd_selectLineNext", "Extend selection forward one line."),
651           S(D("backward-line", "Move or extend the selection backward one line."),
652             D("cmd_linePrevious", "Move point backward one line."),
653             D("cmd_selectLinePrevious", "Extend selection backward one line."))),
654         R(S(D("forward-page", "Move or extend the selection forward one page."),
655             D("cmd_movePageDown", "Move point forward one page."),
656             D("cmd_selectPageDown", "Extend selection forward one page.")),
657           S(D("backward-page", "Move or extend the selection backward one page."),
658             D("cmd_movePageUp", "Move point backward one page."),
659             D("cmd_selectPageUp", "Extend selection backward one page."))),
660         R(D("cmd_undo", "Undo last editing action."),
661           D("cmd_redo", "Redo last editing action.")),
662         R(S(D("forward-word", "Move or extend the selection forward one word."),
663             D("cmd_wordNext", "Move point forward one word."),
664             D("cmd_selectWordNext", "Extend selection forward one word.")),
665           S(D("backward-word", "Move or extend the selection backward one word."),
666             D("cmd_wordPrevious", "Move point backward one word."),
667             D("cmd_selectWordPrevious", "Extend selection backward one word."))),
668         R(D("cmd_scrollPageUp", "Scroll up one page."),
669           D("cmd_scrollPageDown", "Scroll down one page.")),
670         R(D("cmd_scrollLineUp", "Scroll up one line."),
671           D("cmd_scrollLineDown", "Scroll down one line.")),
672         R(D("cmd_scrollLeft", "Scroll left."),
673           D("cmd_scrollRight", "Scroll right.")),
674         D("cmd_paste", "Insert the contents of the clipboard.")];
676     interactive(prefix + "set-mark",
677                 "Toggle whether the mark is active.\n" +
678                 "When the mark is active, movement commands affect the selection.",
679                 toggle_mark);
681     function doc_for_builtin(c) {
682         var s = "";
683         if (c.doc != null)
684             s += c.doc + "\n";
685         return s + "Run the built-in command " + c + ".";
686     }
688     function define_simple_command(c) {
689         interactive(prefix + c, doc_for_builtin(c), function (I) { do_command_function(I, c); });
690     }
692     function get_move_select_doc_string(c) {
693         return c.command.doc +
694             "\nSpecifically, if the mark is inactive, runs `" + prefix + c[0] + "'.  " +
695             "Otherwise, runs `" + prefix + c[1] + "'.\n" +
696             "To toggle whether the mark is active, use `" + prefix + "set-mark'.";
697     }
699     for each (let c_temp in builtin_commands)  {
700         let c = c_temp;
701         if (c.is_move_select_pair) {
702             interactive(prefix + c.command, get_move_select_doc_string(c), function (I) {
703                 do_command_function(I, mark_active_predicate(I) ? c[1] : c[0]);
704             });
705             define_simple_command(c[0]);
706             define_simple_command(c[1]);
707         }
708         else
709             define_simple_command(c);
710     }
712     function get_reverse_pair_doc_string(main_doc, alt_command) {
713         return main_doc + "\n" +
714             "The prefix argument specifies a repeat count for this command.  " +
715             "If the count is negative, `" + prefix + alt_command + "' is performed instead with " +
716             "a corresponding positive repeat count.";
717     }
719     function define_simple_reverse_pair(a, b) {
720         interactive(prefix + a, get_reverse_pair_doc_string(doc_for_builtin(a), b),
721                     function (I) {
722                         do_repeatedly(do_command_function, I.p, [I, a], [I, b]);
723                     });
724         interactive(prefix + b, get_reverse_pair_doc_string(doc_for_builtin(b), a),
725                     function (I) {
726                         do_repeatedly(do_command_function, I.p, [I, b], [I, a]);
727                     });
728     }
730     for each (let c_temp in builtin_commands_with_count)
731     {
732         let c = c_temp;
733         if (c.is_reverse_pair) {
734             if (c[0].is_move_select_pair) {
735                 interactive(prefix + c[0].command, get_reverse_pair_doc_string(get_move_select_doc_string(c[0]),
736                                                                                c[1].command),
737                             function (I) {
738                                 var idx = mark_active_predicate(I) ? 1 : 0;
739                                 do_repeatedly(do_command_function, I.p, [I, c[0][idx]], [I, c[1][idx]]);
740                             });
741                 interactive(prefix + c[1].command, get_reverse_pair_doc_string(get_move_select_doc_string(c[1]),
742                                                                                c[0].command),
743                             function (I) {
744                                 var idx = mark_active_predicate(I) ? 1 : 0;
745                                 do_repeatedly(do_command_function, I.p, [I, c[1][idx]], [I, c[0][idx]]);
746                             });
747                 define_simple_reverse_pair(c[0][0], c[1][0]);
748                 define_simple_reverse_pair(c[0][1], c[1][1]);
749             } else
750                 define_simple_reverse_pair(c[0], c[1]);
751         } else {
752             let doc = doc_for_builtin(c) +
753                 "\nThe prefix argument specifies a positive repeat count for this command.";
754             interactive(prefix + c, doc, function (I) {
755                 do_repeatedly_positive(do_command_function, I.p, I, c);
756             });
757         }
758     }
761 var observer_service = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
763 function abort(str) {
764     var e = new Error(str);
765     e.__proto__ = abort.prototype;
766     return e;
768 abort.prototype.__proto__ = Error.prototype;
771 function get_temporary_file(name) {
772     if (name == null)
773         name = "temp.txt";
774     var file = file_locator.get("TmpD", Ci.nsIFile);
775     file.append(name);
776     // Create the file now to ensure that no exploits are possible
777     file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
778     return file;
782 /* FIXME: This should be moved somewhere else, perhaps. */
783 function create_info_panel(window, panel_class, row_arr) {
784     /* Show information panel above minibuffer */
786     var g = new dom_generator(window.document, XUL_NS);
788     var p = g.element("vbox", "class", "panel " + panel_class, "flex", "0");
789     var grid = g.element("grid", p);
790     var cols = g.element("columns", grid);
791     g.element("column", cols, "flex", "0");
792     g.element("column", cols, "flex", "1");
794     var rows = g.element("rows", grid);
795     var row;
797     for each (let [row_class, row_label, row_value] in row_arr) {
798         row = g.element("row", rows, "class", row_class);
799         g.element("label", row,
800                   "value", row_label,
801                   "class", "panel-row-label");
802         g.element("label", row,
803                   "value", row_value,
804                   "class", "panel-row-value");
805     }
806     window.minibuffer.insert_before(p);
808     p.destroy = function () {
809         this.parentNode.removeChild(this);
810     };
812     return p;
816 // read_from_x_primary_selection favors the X PRIMARY SELECTION, when
817 // it exists.  The builtin cmd_paste always uses X CLIPBOARD.  So this
818 // is an auxiliary utility, in case you need to work with the primary
819 // selection.
821 function read_from_x_primary_selection ()
823     // Get clipboard.
824     var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
825         .getService(Components.interfaces.nsIClipboard);
827     // Create tranferable that will transfer the text.
828     var trans = Components.classes["@mozilla.org/widget/transferable;1"]
829         .createInstance(Components.interfaces.nsITransferable);
831     trans.addDataFlavor("text/unicode");
832     // If available, use selection clipboard, otherwise global one
833     if (clipboard.supportsSelectionClipboard())
834         clipboard.getData(trans, clipboard.kSelectionClipboard);
835     else
836         clipboard.getData(trans, clipboard.kGlobalClipboard);
838     var data = {};
839     var dataLen = {};
840     trans.getTransferData("text/unicode", data, dataLen);
842     if (data) {
843         data = data.value.QueryInterface(Components.interfaces.nsISupportsString);
844         return data.data.substring(0, dataLen.value / 2);
845     } else {
846         return "";
847     }
850 var user_variables = new string_hashmap();
852 function define_variable(name, default_value, doc) {
853     conkeror[name] = default_value;
854     user_variables.put(name, {
855         default_value: default_value,
856         doc: doc,
857         shortdoc: get_shortdoc_string(doc),
858         source_code_reference: get_caller_source_code_reference() });
862 function register_user_stylesheet(url)
864     var uri = makeURL(url);
865     var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
866     sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
869 function unregister_user_stylesheet(url)
871     var uri = makeURL(url);
872     var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
873     if (sss.sheetRegistered(uri, sss.USER_SHEET))
874         ss.unregisterSheet(uri, sss.USER_SHEET);
877 function predicate_alist_match(alist, key) {
878     for each (let i in alist) {
879         if (i[0](key))
880             return i[1];
881     }
882     return undefined;