Change youtube-mode and google-video-mode to set suggest_filename_from_uri = false
[conkeror.git] / modules / utils.js
blob75dd657bafd90d96585a82240c10ba573ad8bd48
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              });
150 // Put the string on the clipboard
151 function writeToClipboard(str)
153     const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
154         .getService(Components.interfaces.nsIClipboardHelper);
155     gClipboardHelper.copyString(str);
159 function makeURLAbsolute (base, url)
161     // Construct nsIURL.
162     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
163         .getService(Components.interfaces.nsIIOService);
164     var baseURI  = ioService.newURI(base, null, null);
166     return ioService.newURI (baseURI.resolve (url), null, null).spec;
170 function get_link_location (element)
172     if (element && element.getAttribute("href")) {
173         var loc = element.getAttribute("href");
174         return makeURLAbsolute(element.baseURI, loc);
175     }
176     return null;
180 function makeURL(aURL)
182     var ioService = Cc["@mozilla.org/network/io-service;1"]
183         .getService(Ci.nsIIOService);
184     return ioService.newURI(aURL, null, null);
187 function make_uri(uri) {
188     if (uri instanceof Ci.nsIURI)
189         return uri;
190     var io_service = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
191     return io_service.newURI(uri, null, null);
194 function makeFileURL(aFile)
196     var ioService = Cc["@mozilla.org/network/io-service;1"]
197         .getService(Ci.nsIIOService);
198     return ioService.newFileURI(aFile);
202 function get_document_content_disposition (document_o)
204     var content_disposition = null;
205     try {
206         content_disposition =
207             document_o.defaultView
208             .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
209             .getInterface(Components.interfaces.nsIDOMWindowUtils)
210             .getDocumentMetadata("content-disposition");
211     } catch (e) { }
212     return content_disposition;
216 function set_focus_no_scroll(window, element)
218     window.document.commandDispatcher.suppressFocusScroll = true;
219     element.focus();
220     window.document.commandDispatcher.suppressFocusScroll = false;
223 function do_repeatedly_positive(func, n) {
224     var args = Array.prototype.slice.call(arguments, 2);
225     while (n-- > 0)
226         func.apply(null, args);
229 function do_repeatedly(func, n, positive_args, negative_args) {
230     if (n < 0)
231         do func.apply(null, negative_args); while (++n < 0);
232     else
233         while (n-- > 0) func.apply(null, positive_args);
236 // remove whitespace from the beginning and end
237 function trim_whitespace (str)
239     var tmp = new String (str);
240     return tmp.replace (/^\s+/, "").replace (/\s+$/, "");
243 function abs_point (node)
245     var orig = node;
246     var pt = {};
247     try {
248         pt.x = node.offsetLeft;
249         pt.y = node.offsetTop;
250         // find imagemap's coordinates
251         if (node.tagName == "AREA") {
252             var coords = node.getAttribute("coords").split(",");
253             pt.x += Number(coords[0]);
254             pt.y += Number(coords[1]);
255         }
257         node = node.offsetParent;
258         // Sometimes this fails, so just return what we got.
260         while (node.tagName != "BODY") {
261             pt.x += node.offsetLeft;
262             pt.y += node.offsetTop;
263             node = node.offsetParent;
264         }
265     } catch(e) {
266 //      node = orig;
267 //      while (node.tagName != "BODY") {
268 //          alert("okay: " + node + " " + node.tagName + " " + pt.x + " " + pt.y);
269 //          node = node.offsetParent;
270 //      }
271     }
272     return pt;
275 var xul_app_info = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
276 var xul_runtime = Cc['@mozilla.org/xre/app-info;1'].getService(Ci.nsIXULRuntime);
279 function get_os ()
281     // possible return values: 'Darwin', 'Linux', 'WINNT', ...
282     return xul_runtime.OS;
285 var default_directory = null;
287 var env = Cc['@mozilla.org/process/environment;1'].getService(Ci.nsIEnvironment);
288 function getenv (variable) {
289     if (env.exists (variable))
290         return env.get(variable);
291     return null;
294 function set_default_directory(directory_s) {
295     if (! directory_s)
296     {
297         if ( get_os() == "WINNT")
298         {
299             directory_s = getenv ('USERPROFILE') ||
300                 getenv ('HOMEDRIVE') + getenv ('HOMEPATH');
301         }
302         else {
303             directory_s = getenv ('HOME');
304         }
305     }
307     default_directory = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
308     default_directory.initWithPath (directory_s);
311 set_default_directory();
313 const XHTML_NS = "http://www.w3.org/1999/xhtml";
314 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
315 const MATHML_NS = "http://www.w3.org/1998/Math/MathML";
316 const XLINK_NS = "http://www.w3.org/1999/xlink";
318 function create_XUL(window, tag_name)
320     return window.document.createElementNS(XUL_NS, tag_name);
324 /* Used in calls to XPath evaluate */
325 function xpath_lookup_namespace(prefix) {
326     if (prefix == "xhtml")
327         return XHTML_NS;
328     if (prefix == "m")
329         return MATHML_NS;
330     if (prefix == "xul")
331         return XUL_NS;
332     return null;
335 function method_caller(obj, func) {
336     return function () {
337         func.apply(obj, arguments);
338     }
341 function shell_quote(str) {
342     var s = str.replace("\"", "\\\"", "g");
343     s = s.replace("$", "\$", "g");
344     return s;
347 function get_window_from_frame(frame) {
348     try {
349         var window = frame.QueryInterface(Ci.nsIInterfaceRequestor)
350             .getInterface(Ci.nsIWebNavigation)
351             .QueryInterface(Ci.nsIDocShellTreeItem)
352             .rootTreeItem
353             .QueryInterface(Ci.nsIInterfaceRequestor)
354             .getInterface(Ci.nsIDOMWindow).wrappedJSObject;
355         /* window is now an XPCSafeJSObjectWrapper */
356         window.escape_wrapper(function (w) { window = w; });
357         /* window is now completely unwrapped */
358         return window;
359     } catch (e) {
360         return null;
361     }
364 function get_buffer_from_frame(window, frame) {
365     var count = window.buffers.count;
366     for (var i = 0; i < count; ++i) {
367         var b = window.buffers.get_buffer(i);
368         if (b.top_frame == frame)
369             return b;
370     }
371     return null;
374 var file_locator = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
376 function get_shortdoc_string(doc) {
377     var shortdoc = null;
378     if (doc != null) {
379         var idx = doc.indexOf("\n");
380         if (idx >= 0)
381             shortdoc = doc.substring(0,idx);
382         else
383             shortdoc = doc;
384     }
385     return shortdoc;
388 var conkeror_source_code_path = null;
390 function source_code_reference(uri, line_number) {
391     this.uri = uri;
392     this.line_number = line_number;
394 source_code_reference.prototype = {
395     get module_name () {
396         if (this.uri.indexOf(module_uri_prefix) == 0)
397             return this.uri.substring(module_uri_prefix.length);
398         return null;
399     },
401     get file_name () {
402         var file_uri_prefix = "file://";
403         if (this.uri.indexOf(file_uri_prefix) == 0)
404             return this.uri.substring(file_uri_prefix.length);
405         return null;
406     },
408     get best_uri () {
409         if (conkeror_source_code_path != null) {
410             var module_name = this.module_name;
411             if (module_name != null)
412                 return "file://" + conkeror_source_code_path + "/modules/" + module_name;
413         }
414         return this.uri;
415     },
417     open_in_editor : function() {
418         yield open_with_external_editor(this.best_uri, $line = this.line_number);
419     }
422 var get_caller_source_code_reference_ignored_functions = {};
424 function get_caller_source_code_reference(extra_frames_back) {
425     /* Skip at least this function itself and whoever called it (and
426      * more if the caller wants to be skipped). */
427     var frames_to_skip = 2;
428     if (extra_frames_back != null)
429         frames_to_skip += extra_frames_back;
431     for (let f = Components.stack; f != null; f = f.caller) {
432         if (frames_to_skip > 0) {
433             --frames_to_skip;
434             continue;
435         }
436         if (get_caller_source_code_reference_ignored_functions[f.name])
437             continue;
438         return new source_code_reference(f.filename, f.lineNumber);
439     }
441     return null;
444 function ignore_function_for_get_caller_source_code_reference(func_name) {
445     get_caller_source_code_reference_ignored_functions[func_name] = 1;
448 require_later("external-editor.js");
450 function dom_generator(document, ns) {
451     this.document = document;
452     this.ns = ns;
454 dom_generator.prototype = {
455     element : function(tag, parent) {
456         var node = this.document.createElementNS(this.ns, tag);
457         var i = 1;
458         if (parent != null && (parent instanceof Ci.nsIDOMNode)) {
459             parent.appendChild(node);
460             i = 2;
461         }
462         for (; i < arguments.length; i += 2)
463             node.setAttribute(arguments[i], arguments[i+1]);
464         return node;
465     },
467     text : function(str, parent) {
468         var node = this.document.createTextNode(str);
469         if (parent)
470             parent.appendChild(node);
471         return node;
472     },
475     stylesheet_link : function(href, parent) {
476         var node = this.element("link");
477         node.setAttribute("rel", "stylesheet");
478         node.setAttribute("type", "text/css");
479         node.setAttribute("href", href);
480         if (parent)
481             parent.appendChild(node);
482         return node;
483     },
486     add_stylesheet : function (url) {
487         var head = this.document.documentElement.firstChild;
488         this.stylesheet_link(url, head);
489     }
493  * Generates a QueryInterface function suitable for an implemenation
494  * of an XPCOM interface.  Unlike XPCOMUtils, this uses the Function
495  * constructor to generate a slightly more efficient version.  The
496  * arguments can be either Strings or elements of
497  * Components.interfaces.
498  */
499 function generate_QI() {
500     var args = Array.prototype.slice.call(arguments).map(String).concat(["nsISupports"]);
501     var fstr = "if(" +
502         Array.prototype.map.call(args,
503                                  function (x)
504                                      "iid.equals(Components.interfaces." + x + ")")
505         .join("||") +
506         ") return this; throw Components.results.NS_ERROR_NO_INTERFACE;";
507     return new Function("iid", fstr);
510 function set_branch_pref(branch, name, value) {
511     if (typeof(value) == "string") {
512         branch.setCharPref(name, value);
513     } else if (typeof(value) == "number") {
514         branch.setIntPref(name, value);
515     } else if (typeof(value) == "boolean") {
516         branch.setBoolPref(name, value);
517     }
520 function default_pref(name, value) {
521     var branch = preferences.getDefaultBranch(null);
522     set_branch_pref(branch, name, value);
525 function user_pref(name, value) {
526     var branch = preferences.getBranch(null);
527     set_branch_pref(branch, name, value);
530 function get_branch_pref(branch, name) {
531     switch (branch.getPrefType(name)) {
532     case branch.PREF_STRING:
533         return branch.getCharPref(name);
534     case branch.PREF_INT:
535         return branch.getIntPref(name);
536     case branch.PREF_BOOL:
537         return branch.getBoolPref(name);
538     default:
539         return null;
540     }
543 function get_pref(name) {
544     var branch = preferences.getBranch(null);
545     return get_branch_pref(branch, name);
548 function get_default_pref(name) {
549     var branch = preferences.getDefaultBranch(null);
550     return get_branch_pref(branch, name);
553 function clear_pref(name) {
554     var branch = preferences.getBranch(null);
555     return branch.clearUserPref(name);
558 function clear_default_pref(name) {
559     var branch = preferences.getDefaultBranch(null);
560     return branch.clearUserPref(name);
563 function pref_has_user_value(name) {
564     var branch = preferences.getBranch(null);
565     return branch.prefHasUserValue(name);
568 function pref_has_default_value(name) {
569     var branch = preferences.getDefaultBranch(null);
570     return branch.prefHasUserValue(name);
573 function session_pref (name, value) {
574     try { clear_pref (name); }
575     catch (e) {}
576     return default_pref (name, value);
579 const USER_AGENT_OVERRIDE_PREF = "general.useragent.override";
581 function set_user_agent(str) {
582     session_pref(USER_AGENT_OVERRIDE_PREF, str);
585 function define_builtin_commands(prefix, do_command_function, toggle_mark, mark_active_predicate) {
587     // Specify a docstring
588     function D(cmd, docstring) {
589         var o = new String(cmd);
590         o.doc = docstring;
591         return o;
592     }
594     // Specify a forward/reverse pair
595     function R(a, b) {
596         var o = [a,b];
597         o.is_reverse_pair = true;
598         return o;
599     }
601     // Specify a movement/select command pair.
602     function S(command, movement, select) {
603         var o = [movement, select];
604         o.command = command;
605         o.is_move_select_pair = true;
606         return o;
607     }
609     var builtin_commands = [
610         S(D("beginning-of-line", "Move or extend the selection to the beginning of the current line."),
611           D("cmd_beginLine", "Move point to the beginning of the current line."),
612           D("cmd_selectBeginLine", "Extend selection to the beginning of the current line.")),
613         S(D("end-of-line", "Move or extend the selection to the end of the current line."),
614           D("cmd_endLine", "Move point to the end of the current line."),
615           D("cmd_selectEndLine", "Extend selection to the end of the current line.")),
616         D("cmd_copy", "Copy the selection into the clipboard."),
617         "cmd_copyOrDelete",
618         D("cmd_cut", "Cut the selection into the clipboard."),
619         "cmd_cutOrDelete",
620         D("cmd_deleteToBeginningOfLine", "Delete to the beginning of the current line."),
621         D("cmd_deleteToEndOfLine", "Delete to the end of the current line."),
622         S(D("beginning-of-first-line", "Move or extend the selection to the beginning of the first line."),
623           D("cmd_moveTop", "Move point to the beginning of the first line."),
624           D("cmd_selectTop", "Extend selection to the beginning of the first line.")),
625         S(D("end-of-last-line", "Move or extend the selection to the end of the last line."),
626           D("cmd_moveBottom", "Move point to the end of the last line."),
627           D("cmd_selectBottom", "Extend selection to the end of the last line.")),
628         D("cmd_selectAll", "Select all."),
629         "cmd_scrollBeginLine",
630         "cmd_scrollEndLine",
631         D("cmd_scrollTop", "Scroll to the top of the buffer."),
632         D("cmd_scrollBottom", "Scroll to the bottom of the buffer.")];
634     var builtin_commands_with_count = [
635         R(S(D("forward-char", "Move or extend the selection forward one character."),
636             D("cmd_charNext", "Move point forward one character."),
637             D("cmd_selectCharNext", "Extend selection forward one character.")),
638           S(D("backward-char", "Move or extend the selection backward one character."),
639             D("cmd_charPrevious", "Move point backward one character."),
640             D("cmd_selectCharPrevious", "Extend selection backward one character."))),
641         R(D("cmd_deleteCharForward", "Delete the following character."),
642           D("cmd_deleteCharBackward", "Delete the previous character.")),
643         R(D("cmd_deleteWordForward", "Delete the following word."),
644           D("cmd_deleteWordBackward", "Delete the previous word.")),
645         R(S(D("forward-line", "Move or extend the selection forward one line."),
646             D("cmd_lineNext", "Move point forward one line."),
647             "cmd_selectLineNext", "Extend selection forward one line."),
648           S(D("backward-line", "Move or extend the selection backward one line."),
649             D("cmd_linePrevious", "Move point backward one line."),
650             D("cmd_selectLinePrevious", "Extend selection backward one line."))),
651         R(S(D("forward-page", "Move or extend the selection forward one page."),
652             D("cmd_movePageDown", "Move point forward one page."),
653             D("cmd_selectPageDown", "Extend selection forward one page.")),
654           S(D("backward-page", "Move or extend the selection backward one page."),
655             D("cmd_movePageUp", "Move point backward one page."),
656             D("cmd_selectPageUp", "Extend selection backward one page."))),
657         R(D("cmd_undo", "Undo last editing action."),
658           D("cmd_redo", "Redo last editing action.")),
659         R(S(D("forward-word", "Move or extend the selection forward one word."),
660             D("cmd_wordNext", "Move point forward one word."),
661             D("cmd_selectWordNext", "Extend selection forward one word.")),
662           S(D("backward-word", "Move or extend the selection backward one word."),
663             D("cmd_wordPrevious", "Move point backward one word."),
664             D("cmd_selectWordPrevious", "Extend selection backward one word."))),
665         R(D("cmd_scrollPageUp", "Scroll up one page."),
666           D("cmd_scrollPageDown", "Scroll down one page.")),
667         R(D("cmd_scrollLineUp", "Scroll up one line."),
668           D("cmd_scrollLineDown", "Scroll down one line.")),
669         R(D("cmd_scrollLeft", "Scroll left."),
670           D("cmd_scrollRight", "Scroll right.")),
671         D("cmd_paste", "Insert the contents of the clipboard.")];
673     interactive(prefix + "set-mark",
674                 "Toggle whether the mark is active.\n" +
675                 "When the mark is active, movement commands affect the selection.",
676                 toggle_mark);
678     function doc_for_builtin(c) {
679         var s = "";
680         if (c.doc != null)
681             s += c.doc + "\n";
682         return s + "Run the built-in command " + c + ".";
683     }
685     function define_simple_command(c) {
686         interactive(prefix + c, doc_for_builtin(c), function (I) { do_command_function(I, c); });
687     }
689     function get_move_select_doc_string(c) {
690         return c.command.doc +
691             "\nSpecifically, if the mark is inactive, runs `" + prefix + c[0] + "'.  " +
692             "Otherwise, runs `" + prefix + c[1] + "'.\n" +
693             "To toggle whether the mark is active, use `" + prefix + "set-mark'.";
694     }
696     for each (let c_temp in builtin_commands)  {
697         let c = c_temp;
698         if (c.is_move_select_pair) {
699             interactive(prefix + c.command, get_move_select_doc_string(c), function (I) {
700                 do_command_function(I, mark_active_predicate(I) ? c[1] : c[0]);
701             });
702             define_simple_command(c[0]);
703             define_simple_command(c[1]);
704         }
705         else
706             define_simple_command(c);
707     }
709     function get_reverse_pair_doc_string(main_doc, alt_command) {
710         return main_doc + "\n" +
711             "The prefix argument specifies a repeat count for this command.  " +
712             "If the count is negative, `" + prefix + alt_command + "' is performed instead with " +
713             "a corresponding positive repeat count.";
714     }
716     function define_simple_reverse_pair(a, b) {
717         interactive(prefix + a, get_reverse_pair_doc_string(doc_for_builtin(a), b),
718                     function (I) {
719                         do_repeatedly(do_command_function, I.p, [I, a], [I, b]);
720                     });
721         interactive(prefix + b, get_reverse_pair_doc_string(doc_for_builtin(b), a),
722                     function (I) {
723                         do_repeatedly(do_command_function, I.p, [I, b], [I, a]);
724                     });
725     }
727     for each (let c_temp in builtin_commands_with_count)
728     {
729         let c = c_temp;
730         if (c.is_reverse_pair) {
731             if (c[0].is_move_select_pair) {
732                 interactive(prefix + c[0].command, get_reverse_pair_doc_string(get_move_select_doc_string(c[0]),
733                                                                                c[1].command),
734                             function (I) {
735                                 var idx = mark_active_predicate(I) ? 1 : 0;
736                                 do_repeatedly(do_command_function, I.p, [I, c[0][idx]], [I, c[1][idx]]);
737                             });
738                 interactive(prefix + c[1].command, get_reverse_pair_doc_string(get_move_select_doc_string(c[1]),
739                                                                                c[0].command),
740                             function (I) {
741                                 var idx = mark_active_predicate(I) ? 1 : 0;
742                                 do_repeatedly(do_command_function, I.p, [I, c[1][idx]], [I, c[0][idx]]);
743                             });
744                 define_simple_reverse_pair(c[0][0], c[1][0]);
745                 define_simple_reverse_pair(c[0][1], c[1][1]);
746             } else
747                 define_simple_reverse_pair(c[0], c[1]);
748         } else {
749             let doc = doc_for_builtin(c) +
750                 "\nThe prefix argument specifies a positive repeat count for this command.";
751             interactive(prefix + c, doc, function (I) {
752                 do_repeatedly_positive(do_command_function, I.p, I, c);
753             });
754         }
755     }
758 var observer_service = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
760 function abort(str) {
761     var e = new Error(str);
762     e.__proto__ = abort.prototype;
763     return e;
765 abort.prototype.__proto__ = Error.prototype;
768 function get_temporary_file(name) {
769     if (name == null)
770         name = "temp.txt";
771     var file = file_locator.get("TmpD", Ci.nsIFile);
772     file.append(name);
773     // Create the file now to ensure that no exploits are possible
774     file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
775     return file;
779 /* FIXME: This should be moved somewhere else, perhaps. */
780 function create_info_panel(window, panel_class, row_arr) {
781     /* Show information panel above minibuffer */
783     var g = new dom_generator(window.document, XUL_NS);
785     var p = g.element("vbox", "class", "panel " + panel_class, "flex", "0");
786     var grid = g.element("grid", p);
787     var cols = g.element("columns", grid);
788     g.element("column", cols, "flex", "0");
789     g.element("column", cols, "flex", "1");
791     var rows = g.element("rows", grid);
792     var row;
794     for each (let [row_class, row_label, row_value] in row_arr) {
795         row = g.element("row", rows, "class", row_class);
796         g.element("label", row,
797                   "value", row_label,
798                   "class", "panel-row-label");
799         g.element("label", row,
800                   "value", row_value,
801                   "class", "panel-row-value");
802     }
803     window.minibuffer.insert_before(p);
805     p.destroy = function () {
806         this.parentNode.removeChild(this);
807     };
809     return p;
813 // read_from_x_primary_selection favors the X PRIMARY SELECTION, when
814 // it exists.  The builtin cmd_paste always uses X CLIPBOARD.  So this
815 // is an auxiliary utility, in case you need to work with the primary
816 // selection.
818 function read_from_x_primary_selection ()
820     // Get clipboard.
821     var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
822         .getService(Components.interfaces.nsIClipboard);
824     // Create tranferable that will transfer the text.
825     var trans = Components.classes["@mozilla.org/widget/transferable;1"]
826         .createInstance(Components.interfaces.nsITransferable);
828     trans.addDataFlavor("text/unicode");
829     // If available, use selection clipboard, otherwise global one
830     if (clipboard.supportsSelectionClipboard())
831         clipboard.getData(trans, clipboard.kSelectionClipboard);
832     else
833         clipboard.getData(trans, clipboard.kGlobalClipboard);
835     var data = {};
836     var dataLen = {};
837     trans.getTransferData("text/unicode", data, dataLen);
839     if (data) {
840         data = data.value.QueryInterface(Components.interfaces.nsISupportsString);
841         return data.data.substring(0, dataLen.value / 2);
842     } else {
843         return "";
844     }
847 var user_variables = new string_hashmap();
849 function define_variable(name, default_value, doc) {
850     conkeror[name] = default_value;
851     user_variables.put(name, {
852         default_value: default_value,
853         doc: doc,
854         shortdoc: get_shortdoc_string(doc),
855         source_code_reference: get_caller_source_code_reference() });
859 function register_user_stylesheet(url)
861     var uri = makeURL(url);
862     var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
863     sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
866 function unregister_user_stylesheet(url)
868     var uri = makeURL(url);
869     var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
870     if (sss.sheetRegistered(uri, sss.USER_SHEET))
871         ss.unregisterSheet(uri, sss.USER_SHEET);
874 function predicate_alist_match(alist, key) {
875     for each (let i in alist) {
876         if (i[0](key))
877             return i[1];
878     }
879     return undefined;