Add embedded youtube video scraper (finds embedded youtube videos on other sites)
[conkeror.git] / modules / utils.js
blob66183c6b9bcafa42891521ea14574fb1925838a8
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     },
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     },
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 var io_service = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
185 function make_uri(uri, charset, base_uri) {
186     if (uri instanceof Ci.nsIURI)
187         return uri;
188     return io_service.newURI(uri, charset, base_uri);
191 var makeURL = make_uri; // until all callers are fixed
193 function makeFileURL(aFile)
195     return io_service.newFileURI(aFile).QueryInterface(Ci.nsIURL);
199 function get_document_content_disposition (document_o)
201     var content_disposition = null;
202     try {
203         content_disposition =
204             document_o.defaultView
205             .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
206             .getInterface(Components.interfaces.nsIDOMWindowUtils)
207             .getDocumentMetadata("content-disposition");
208     } catch (e) { }
209     return content_disposition;
213 function set_focus_no_scroll(window, element)
215     window.document.commandDispatcher.suppressFocusScroll = true;
216     element.focus();
217     window.document.commandDispatcher.suppressFocusScroll = false;
220 function do_repeatedly_positive(func, n) {
221     var args = Array.prototype.slice.call(arguments, 2);
222     while (n-- > 0)
223         func.apply(null, args);
226 function do_repeatedly(func, n, positive_args, negative_args) {
227     if (n < 0)
228         do func.apply(null, negative_args); while (++n < 0);
229     else
230         while (n-- > 0) func.apply(null, positive_args);
233 // remove whitespace from the beginning and end
234 function trim_whitespace (str)
236     var tmp = new String (str);
237     return tmp.replace (/^\s+/, "").replace (/\s+$/, "");
240 function abs_point (node)
242     var orig = node;
243     var pt = {};
244     try {
245         pt.x = node.offsetLeft;
246         pt.y = node.offsetTop;
247         // find imagemap's coordinates
248         if (node.tagName == "AREA") {
249             var coords = node.getAttribute("coords").split(",");
250             pt.x += Number(coords[0]);
251             pt.y += Number(coords[1]);
252         }
254         node = node.offsetParent;
255         // Sometimes this fails, so just return what we got.
257         while (node.tagName != "BODY") {
258             pt.x += node.offsetLeft;
259             pt.y += node.offsetTop;
260             node = node.offsetParent;
261         }
262     } catch(e) {
263 //      node = orig;
264 //      while (node.tagName != "BODY") {
265 //          alert("okay: " + node + " " + node.tagName + " " + pt.x + " " + pt.y);
266 //          node = node.offsetParent;
267 //      }
268     }
269     return pt;
272 var xul_app_info = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
273 var xul_runtime = Cc['@mozilla.org/xre/app-info;1'].getService(Ci.nsIXULRuntime);
276 function get_os ()
278     // possible return values: 'Darwin', 'Linux', 'WINNT', ...
279     return xul_runtime.OS;
282 var default_directory = null;
284 var env = Cc['@mozilla.org/process/environment;1'].getService(Ci.nsIEnvironment);
285 function getenv (variable) {
286     if (env.exists (variable))
287         return env.get(variable);
288     return null;
291 function set_default_directory(directory_s) {
292     if (! directory_s)
293     {
294         if ( get_os() == "WINNT")
295         {
296             directory_s = getenv ('USERPROFILE') ||
297                 getenv ('HOMEDRIVE') + getenv ('HOMEPATH');
298         }
299         else {
300             directory_s = getenv ('HOME');
301         }
302     }
304     default_directory = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
305     default_directory.initWithPath (directory_s);
308 set_default_directory();
310 const XHTML_NS = "http://www.w3.org/1999/xhtml";
311 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
312 const MATHML_NS = "http://www.w3.org/1998/Math/MathML";
313 const XLINK_NS = "http://www.w3.org/1999/xlink";
315 function create_XUL(window, tag_name)
317     return window.document.createElementNS(XUL_NS, tag_name);
321 /* Used in calls to XPath evaluate */
322 function xpath_lookup_namespace(prefix) {
323     if (prefix == "xhtml")
324         return XHTML_NS;
325     if (prefix == "m")
326         return MATHML_NS;
327     if (prefix == "xul")
328         return XUL_NS;
329     return null;
332 function method_caller(obj, func) {
333     return function () {
334         func.apply(obj, arguments);
335     }
338 function shell_quote(str) {
339     var s = str.replace("\"", "\\\"", "g");
340     s = s.replace("$", "\$", "g");
341     return s;
344 function get_window_from_frame(frame) {
345     try {
346         var window = frame.QueryInterface(Ci.nsIInterfaceRequestor)
347             .getInterface(Ci.nsIWebNavigation)
348             .QueryInterface(Ci.nsIDocShellTreeItem)
349             .rootTreeItem
350             .QueryInterface(Ci.nsIInterfaceRequestor)
351             .getInterface(Ci.nsIDOMWindow).wrappedJSObject;
352         /* window is now an XPCSafeJSObjectWrapper */
353         window.escape_wrapper(function (w) { window = w; });
354         /* window is now completely unwrapped */
355         return window;
356     } catch (e) {
357         return null;
358     }
361 function get_buffer_from_frame(window, frame) {
362     var count = window.buffers.count;
363     for (var i = 0; i < count; ++i) {
364         var b = window.buffers.get_buffer(i);
365         if (b.top_frame == frame)
366             return b;
367     }
368     return null;
371 var file_locator = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
373 function get_shortdoc_string(doc) {
374     var shortdoc = null;
375     if (doc != null) {
376         var idx = doc.indexOf("\n");
377         if (idx >= 0)
378             shortdoc = doc.substring(0,idx);
379         else
380             shortdoc = doc;
381     }
382     return shortdoc;
385 var conkeror_source_code_path = null;
387 function source_code_reference(uri, line_number) {
388     this.uri = uri;
389     this.line_number = line_number;
391 source_code_reference.prototype = {
392     get module_name () {
393         if (this.uri.indexOf(module_uri_prefix) == 0)
394             return this.uri.substring(module_uri_prefix.length);
395         return null;
396     },
398     get file_name () {
399         var file_uri_prefix = "file://";
400         if (this.uri.indexOf(file_uri_prefix) == 0)
401             return this.uri.substring(file_uri_prefix.length);
402         return null;
403     },
405     get best_uri () {
406         if (conkeror_source_code_path != null) {
407             var module_name = this.module_name;
408             if (module_name != null)
409                 return "file://" + conkeror_source_code_path + "/modules/" + module_name;
410         }
411         return this.uri;
412     },
414     open_in_editor : function() {
415         yield open_with_external_editor(this.best_uri, $line = this.line_number);
416     }
419 var get_caller_source_code_reference_ignored_functions = {};
421 function get_caller_source_code_reference(extra_frames_back) {
422     /* Skip at least this function itself and whoever called it (and
423      * more if the caller wants to be skipped). */
424     var frames_to_skip = 2;
425     if (extra_frames_back != null)
426         frames_to_skip += extra_frames_back;
428     for (let f = Components.stack; f != null; f = f.caller) {
429         if (frames_to_skip > 0) {
430             --frames_to_skip;
431             continue;
432         }
433         if (get_caller_source_code_reference_ignored_functions[f.name])
434             continue;
435         return new source_code_reference(f.filename, f.lineNumber);
436     }
438     return null;
441 function ignore_function_for_get_caller_source_code_reference(func_name) {
442     get_caller_source_code_reference_ignored_functions[func_name] = 1;
445 require_later("external-editor.js");
447 function dom_generator(document, ns) {
448     this.document = document;
449     this.ns = ns;
451 dom_generator.prototype = {
452     element : function(tag, parent) {
453         var node = this.document.createElementNS(this.ns, tag);
454         var i = 1;
455         if (parent != null && (parent instanceof Ci.nsIDOMNode)) {
456             parent.appendChild(node);
457             i = 2;
458         }
459         for (; i < arguments.length; i += 2)
460             node.setAttribute(arguments[i], arguments[i+1]);
461         return node;
462     },
464     text : function(str, parent) {
465         var node = this.document.createTextNode(str);
466         if (parent)
467             parent.appendChild(node);
468         return node;
469     },
472     stylesheet_link : function(href, parent) {
473         var node = this.element("link");
474         node.setAttribute("rel", "stylesheet");
475         node.setAttribute("type", "text/css");
476         node.setAttribute("href", href);
477         if (parent)
478             parent.appendChild(node);
479         return node;
480     },
483     add_stylesheet : function (url) {
484         var head = this.document.documentElement.firstChild;
485         this.stylesheet_link(url, head);
486     }
490  * Generates a QueryInterface function suitable for an implemenation
491  * of an XPCOM interface.  Unlike XPCOMUtils, this uses the Function
492  * constructor to generate a slightly more efficient version.  The
493  * arguments can be either Strings or elements of
494  * Components.interfaces.
495  */
496 function generate_QI() {
497     var args = Array.prototype.slice.call(arguments).map(String).concat(["nsISupports"]);
498     var fstr = "if(" +
499         Array.prototype.map.call(args,
500                                  function (x)
501                                      "iid.equals(Components.interfaces." + x + ")")
502         .join("||") +
503         ") return this; throw Components.results.NS_ERROR_NO_INTERFACE;";
504     return new Function("iid", fstr);
507 function set_branch_pref(branch, name, value) {
508     if (typeof(value) == "string") {
509         branch.setCharPref(name, value);
510     } else if (typeof(value) == "number") {
511         branch.setIntPref(name, value);
512     } else if (typeof(value) == "boolean") {
513         branch.setBoolPref(name, value);
514     }
517 function default_pref(name, value) {
518     var branch = preferences.getDefaultBranch(null);
519     set_branch_pref(branch, name, value);
522 function user_pref(name, value) {
523     var branch = preferences.getBranch(null);
524     set_branch_pref(branch, name, value);
527 function get_branch_pref(branch, name) {
528     switch (branch.getPrefType(name)) {
529     case branch.PREF_STRING:
530         return branch.getCharPref(name);
531     case branch.PREF_INT:
532         return branch.getIntPref(name);
533     case branch.PREF_BOOL:
534         return branch.getBoolPref(name);
535     default:
536         return null;
537     }
540 function get_localized_pref(name) {
541     try {
542         return preferences.getBranch(null).getComplexValue(name, Ci.nsIPrefLocalizedString).data;
543     } catch (e) {
544         return null;
545     }
548 function get_pref(name) {
549     var branch = preferences.getBranch(null);
550     return get_branch_pref(branch, name);
553 function get_default_pref(name) {
554     var branch = preferences.getDefaultBranch(null);
555     return get_branch_pref(branch, name);
558 function clear_pref(name) {
559     var branch = preferences.getBranch(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 LOCALE_PREF = "general.useragent.locale";
581 function get_locale() {
582     return get_localized_pref(LOCALE_PREF) || get_pref(LOCALE_PREF);
585 const USER_AGENT_OVERRIDE_PREF = "general.useragent.override";
587 function set_user_agent(str) {
588     session_pref(USER_AGENT_OVERRIDE_PREF, str);
591 function define_builtin_commands(prefix, do_command_function, toggle_mark, mark_active_predicate) {
593     // Specify a docstring
594     function D(cmd, docstring) {
595         var o = new String(cmd);
596         o.doc = docstring;
597         return o;
598     }
600     // Specify a forward/reverse pair
601     function R(a, b) {
602         var o = [a,b];
603         o.is_reverse_pair = true;
604         return o;
605     }
607     // Specify a movement/select command pair.
608     function S(command, movement, select) {
609         var o = [movement, select];
610         o.command = command;
611         o.is_move_select_pair = true;
612         return o;
613     }
615     var builtin_commands = [
616         S(D("beginning-of-line", "Move or extend the selection to the beginning of the current line."),
617           D("cmd_beginLine", "Move point to the beginning of the current line."),
618           D("cmd_selectBeginLine", "Extend selection to the beginning of the current line.")),
619         S(D("end-of-line", "Move or extend the selection to the end of the current line."),
620           D("cmd_endLine", "Move point to the end of the current line."),
621           D("cmd_selectEndLine", "Extend selection to the end of the current line.")),
622         D("cmd_copy", "Copy the selection into the clipboard."),
623         "cmd_copyOrDelete",
624         D("cmd_cut", "Cut the selection into the clipboard."),
625         "cmd_cutOrDelete",
626         D("cmd_deleteToBeginningOfLine", "Delete to the beginning of the current line."),
627         D("cmd_deleteToEndOfLine", "Delete to the end of the current line."),
628         S(D("beginning-of-first-line", "Move or extend the selection to the beginning of the first line."),
629           D("cmd_moveTop", "Move point to the beginning of the first line."),
630           D("cmd_selectTop", "Extend selection to the beginning of the first line.")),
631         S(D("end-of-last-line", "Move or extend the selection to the end of the last line."),
632           D("cmd_moveBottom", "Move point to the end of the last line."),
633           D("cmd_selectBottom", "Extend selection to the end of the last line.")),
634         D("cmd_selectAll", "Select all."),
635         "cmd_scrollBeginLine",
636         "cmd_scrollEndLine",
637         D("cmd_scrollTop", "Scroll to the top of the buffer."),
638         D("cmd_scrollBottom", "Scroll to the bottom of the buffer.")];
640     var builtin_commands_with_count = [
641         R(S(D("forward-char", "Move or extend the selection forward one character."),
642             D("cmd_charNext", "Move point forward one character."),
643             D("cmd_selectCharNext", "Extend selection forward one character.")),
644           S(D("backward-char", "Move or extend the selection backward one character."),
645             D("cmd_charPrevious", "Move point backward one character."),
646             D("cmd_selectCharPrevious", "Extend selection backward one character."))),
647         R(D("cmd_deleteCharForward", "Delete the following character."),
648           D("cmd_deleteCharBackward", "Delete the previous character.")),
649         R(D("cmd_deleteWordForward", "Delete the following word."),
650           D("cmd_deleteWordBackward", "Delete the previous word.")),
651         R(S(D("forward-line", "Move or extend the selection forward one line."),
652             D("cmd_lineNext", "Move point forward one line."),
653             "cmd_selectLineNext", "Extend selection forward one line."),
654           S(D("backward-line", "Move or extend the selection backward one line."),
655             D("cmd_linePrevious", "Move point backward one line."),
656             D("cmd_selectLinePrevious", "Extend selection backward one line."))),
657         R(S(D("forward-page", "Move or extend the selection forward one page."),
658             D("cmd_movePageDown", "Move point forward one page."),
659             D("cmd_selectPageDown", "Extend selection forward one page.")),
660           S(D("backward-page", "Move or extend the selection backward one page."),
661             D("cmd_movePageUp", "Move point backward one page."),
662             D("cmd_selectPageUp", "Extend selection backward one page."))),
663         R(D("cmd_undo", "Undo last editing action."),
664           D("cmd_redo", "Redo last editing action.")),
665         R(S(D("forward-word", "Move or extend the selection forward one word."),
666             D("cmd_wordNext", "Move point forward one word."),
667             D("cmd_selectWordNext", "Extend selection forward one word.")),
668           S(D("backward-word", "Move or extend the selection backward one word."),
669             D("cmd_wordPrevious", "Move point backward one word."),
670             D("cmd_selectWordPrevious", "Extend selection backward one word."))),
671         R(D("cmd_scrollPageUp", "Scroll up one page."),
672           D("cmd_scrollPageDown", "Scroll down one page.")),
673         R(D("cmd_scrollLineUp", "Scroll up one line."),
674           D("cmd_scrollLineDown", "Scroll down one line.")),
675         R(D("cmd_scrollLeft", "Scroll left."),
676           D("cmd_scrollRight", "Scroll right.")),
677         D("cmd_paste", "Insert the contents of the clipboard.")];
679     interactive(prefix + "set-mark",
680                 "Toggle whether the mark is active.\n" +
681                 "When the mark is active, movement commands affect the selection.",
682                 toggle_mark);
684     function doc_for_builtin(c) {
685         var s = "";
686         if (c.doc != null)
687             s += c.doc + "\n";
688         return s + "Run the built-in command " + c + ".";
689     }
691     function define_simple_command(c) {
692         interactive(prefix + c, doc_for_builtin(c), function (I) { do_command_function(I, c); });
693     }
695     function get_move_select_doc_string(c) {
696         return c.command.doc +
697             "\nSpecifically, if the mark is inactive, runs `" + prefix + c[0] + "'.  " +
698             "Otherwise, runs `" + prefix + c[1] + "'.\n" +
699             "To toggle whether the mark is active, use `" + prefix + "set-mark'.";
700     }
702     for each (let c_temp in builtin_commands)  {
703         let c = c_temp;
704         if (c.is_move_select_pair) {
705             interactive(prefix + c.command, get_move_select_doc_string(c), function (I) {
706                 do_command_function(I, mark_active_predicate(I) ? c[1] : c[0]);
707             });
708             define_simple_command(c[0]);
709             define_simple_command(c[1]);
710         }
711         else
712             define_simple_command(c);
713     }
715     function get_reverse_pair_doc_string(main_doc, alt_command) {
716         return main_doc + "\n" +
717             "The prefix argument specifies a repeat count for this command.  " +
718             "If the count is negative, `" + prefix + alt_command + "' is performed instead with " +
719             "a corresponding positive repeat count.";
720     }
722     function define_simple_reverse_pair(a, b) {
723         interactive(prefix + a, get_reverse_pair_doc_string(doc_for_builtin(a), b),
724                     function (I) {
725                         do_repeatedly(do_command_function, I.p, [I, a], [I, b]);
726                     });
727         interactive(prefix + b, get_reverse_pair_doc_string(doc_for_builtin(b), a),
728                     function (I) {
729                         do_repeatedly(do_command_function, I.p, [I, b], [I, a]);
730                     });
731     }
733     for each (let c_temp in builtin_commands_with_count)
734     {
735         let c = c_temp;
736         if (c.is_reverse_pair) {
737             if (c[0].is_move_select_pair) {
738                 interactive(prefix + c[0].command, get_reverse_pair_doc_string(get_move_select_doc_string(c[0]),
739                                                                                c[1].command),
740                             function (I) {
741                                 var idx = mark_active_predicate(I) ? 1 : 0;
742                                 do_repeatedly(do_command_function, I.p, [I, c[0][idx]], [I, c[1][idx]]);
743                             });
744                 interactive(prefix + c[1].command, get_reverse_pair_doc_string(get_move_select_doc_string(c[1]),
745                                                                                c[0].command),
746                             function (I) {
747                                 var idx = mark_active_predicate(I) ? 1 : 0;
748                                 do_repeatedly(do_command_function, I.p, [I, c[1][idx]], [I, c[0][idx]]);
749                             });
750                 define_simple_reverse_pair(c[0][0], c[1][0]);
751                 define_simple_reverse_pair(c[0][1], c[1][1]);
752             } else
753                 define_simple_reverse_pair(c[0], c[1]);
754         } else {
755             let doc = doc_for_builtin(c) +
756                 "\nThe prefix argument specifies a positive repeat count for this command.";
757             interactive(prefix + c, doc, function (I) {
758                 do_repeatedly_positive(do_command_function, I.p, I, c);
759             });
760         }
761     }
764 var observer_service = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
766 function abort(str) {
767     var e = new Error(str);
768     e.__proto__ = abort.prototype;
769     return e;
771 abort.prototype.__proto__ = Error.prototype;
774 function get_temporary_file(name) {
775     if (name == null)
776         name = "temp.txt";
777     var file = file_locator.get("TmpD", Ci.nsIFile);
778     file.append(name);
779     // Create the file now to ensure that no exploits are possible
780     file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
781     return file;
785 /* FIXME: This should be moved somewhere else, perhaps. */
786 function create_info_panel(window, panel_class, row_arr) {
787     /* Show information panel above minibuffer */
789     var g = new dom_generator(window.document, XUL_NS);
791     var p = g.element("vbox", "class", "panel " + panel_class, "flex", "0");
792     var grid = g.element("grid", p);
793     var cols = g.element("columns", grid);
794     g.element("column", cols, "flex", "0");
795     g.element("column", cols, "flex", "1");
797     var rows = g.element("rows", grid);
798     var row;
800     for each (let [row_class, row_label, row_value] in row_arr) {
801         row = g.element("row", rows, "class", row_class);
802         g.element("label", row,
803                   "value", row_label,
804                   "class", "panel-row-label");
805         g.element("label", row,
806                   "value", row_value,
807                   "class", "panel-row-value");
808     }
809     window.minibuffer.insert_before(p);
811     p.destroy = function () {
812         this.parentNode.removeChild(this);
813     };
815     return p;
819 // read_from_x_primary_selection favors the X PRIMARY SELECTION, when
820 // it exists.  The builtin cmd_paste always uses X CLIPBOARD.  So this
821 // is an auxiliary utility, in case you need to work with the primary
822 // selection.
824 function read_from_x_primary_selection ()
826     // Get clipboard.
827     var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
828         .getService(Components.interfaces.nsIClipboard);
830     // Create tranferable that will transfer the text.
831     var trans = Components.classes["@mozilla.org/widget/transferable;1"]
832         .createInstance(Components.interfaces.nsITransferable);
834     trans.addDataFlavor("text/unicode");
835     // If available, use selection clipboard, otherwise global one
836     if (clipboard.supportsSelectionClipboard())
837         clipboard.getData(trans, clipboard.kSelectionClipboard);
838     else
839         clipboard.getData(trans, clipboard.kGlobalClipboard);
841     var data = {};
842     var dataLen = {};
843     trans.getTransferData("text/unicode", data, dataLen);
845     if (data) {
846         data = data.value.QueryInterface(Components.interfaces.nsISupportsString);
847         return data.data.substring(0, dataLen.value / 2);
848     } else {
849         return "";
850     }
853 var user_variables = new string_hashmap();
855 function define_variable(name, default_value, doc) {
856     conkeror[name] = default_value;
857     user_variables.put(name, {
858         default_value: default_value,
859         doc: doc,
860         shortdoc: get_shortdoc_string(doc),
861         source_code_reference: get_caller_source_code_reference() });
865 function register_user_stylesheet(url)
867     var uri = makeURL(url);
868     var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
869     sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
872 function unregister_user_stylesheet(url)
874     var uri = makeURL(url);
875     var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
876     if (sss.sheetRegistered(uri, sss.USER_SHEET))
877         ss.unregisterSheet(uri, sss.USER_SHEET);
880 function predicate_alist_match(alist, key) {
881     for each (let i in alist) {
882         if (i[0](key))
883             return i[1];
884     }
885     return undefined;
889 function get_meta_title(doc) {
890     var title = doc.evaluate("//meta[@name='title']/@content", doc, xpath_lookup_namespace,
891                              Ci.nsIDOMXPathResult.STRING_TYPE , null);
892     if (title && title.stringValue)
893         return title.stringValue;
894     return null;
897 var rdf_service = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
899 const PREFIX_ITEM_URI     = "urn:mozilla:item:";
900 const PREFIX_NS_EM        = "http://www.mozilla.org/2004/em-rdf#";
902 var extension_manager = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
904 function get_extension_rdf_property(id, name, type) {
905     var value = extension_manager.datasource.GetTarget(
906         rdf_service.GetResource(PREFIX_ITEM_URI + id),
907         rdf_service.GetResource(PREFIX_NS_EM + name),
908         true);
909     if (value == null)
910         return null;
911     return value.QueryInterface(type || Ci.nsIRDFLiteral).Value;
914 function get_extension_update_item(id) {
915     return extension_manager.getItemForID(id);
918 function extension_info(id) {
919     this.id = id;
921 extension_info.prototype = {
922     // Returns the nsIUpdateItem object associated with this extension
923     get update_item () { return get_extension_update_item(this.id); },
925     get_rdf_property : function (name, type) {
926         return get_extension_rdf_property(this.id, name, type);
927     },
929     // RDF properties
930     get isDisabled () { return this.get_rdf_property("isDisabled"); },
931     get aboutURL () { return this.get_rdf_property("aboutURL"); },
932     get addonID () { return this.get_rdf_property("addonID"); },
933     get availableUpdateURL () { return this.get_rdf_property("availableUpdateURL"); },
934     get availableUpdateVersion () { return this.get_rdf_property("availableUpdateVersion"); },
935     get blocklisted () { return this.get_rdf_property("blocklisted"); },
936     get compatible () { return this.get_rdf_property("compatible"); },
937     get description () { return this.get_rdf_property("description"); },
938     get downloadURL () { return this.get_rdf_property("downloadURL"); },
939     get isDisabled () { return this.get_rdf_property("isDisabled"); },
940     get hidden () { return this.get_rdf_property("hidden"); },
941     get homepageURL () { return this.get_rdf_property("homepageURL"); },
942     get iconURL () { return this.get_rdf_property("iconURL"); },
943     get internalName () { return this.get_rdf_property("internalName"); },
944     get locked () { return this.get_rdf_property("locked"); },
945     get name () { return this.get_rdf_property("name"); },
946     get optionsURL () { return this.get_rdf_property("optionsURL"); },
947     get opType () { return this.get_rdf_property("opType"); },
948     get plugin () { return this.get_rdf_property("plugin"); },
949     get previewImage () { return this.get_rdf_property("previewImage"); },
950     get satisfiesDependencies () { return this.get_rdf_property("satisfiesDependencies"); },
951     get providesUpdatesSecurely () { return this.get_rdf_property("providesUpdatesSecurely"); },
952     get type () { return this.get_rdf_property("type", Ci.nsIRDFInt); },
953     get updateable () { return this.get_rdf_property("updateable"); },
954     get updateURL () { return this.get_rdf_property("updateURL"); },
955     get version () { return this.get_rdf_property("version"); }
958 function extension_is_enabled(id) {
959     var info = new extension_info(id);
960     return info.update_item && (info.isDisabled == "false");
963 function for_each_frame(root_frame, callback, start_with) {
964     if (start_with)
965         callback(start_with);
966     function helper(f) {
967         if (f == start_with)
968             return;
969         callback(f);
970         for (let i = 0; i < f.frames.length; ++i) {
971             helper(f.frames[i]);
972         }
973     }
974     helper(root_frame);
977 // Co-routine version of for_each_frame
978 function co_for_each_frame(root_frame, callback, start_with) {
979     if (start_with)
980         yield callback(start_with);
981     function helper(f) {
982         if (f == start_with)
983             return;
984         yield callback(f);
985         for (let i = 0; i < f.frames.length; ++i) {
986             yield helper(f.frames[i]);
987         }
988     }
989     yield helper(root_frame);
992 function xml_http_request() {
993     return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest).QueryInterface(Ci.nsIJSXMLHttpRequest).QueryInterface(Ci.nsIDOMEventTarget);
996 var xml_http_request_load_listener = {
997   // nsIBadCertListener2
998   notifyCertProblem: function SSLL_certProblem(socketInfo, status, targetSite) {
999     return true;
1000   },
1002   // nsISSLErrorListener
1003   notifySSLError: function SSLL_SSLError(socketInfo, error, targetSite) {
1004     return true;
1005   },
1007   // nsIInterfaceRequestor
1008   getInterface: function SSLL_getInterface(iid) {
1009     return this.QueryInterface(iid);
1010   },
1012   // nsISupports
1013   QueryInterface: XPCOMUtils.generateQI([Ci.nsIBadCertListener2,
1014                                          Ci.nsISSLErrorListener,
1015                                          Ci.nsIInterfaceRequestor])
1019 define_keywords("$user", "$password", "$override_mime_type", "$headers");
1020 function send_http_request(lspec) {
1021     keywords(arguments);
1022     var req = xml_http_request();
1023     var cc = yield CONTINUATION;
1024     req.onreadystatechange = function () {
1025         if (req.readyState != 4)
1026             return;
1027         cc();
1028     };
1030     if (arguments.$override_mime_type)
1031         req.overrideMimeType(arguments.$override_mime_type);
1033     var post_data = load_spec_raw_post_data(lspec);
1035     var method = post_data ? "POST" : "GET";
1037     req.open(method, load_spec_uri_string(lspec), true, arguments.$user, arguments.$password);
1038     req.channel.notificationCallbacks = xml_http_request_load_listener;
1040     for each (let [name,value] in arguments.$headers) {
1041         req.setRequestHeader(name, value);
1042     }
1044     if (post_data) {
1045         req.setRequestHeader("Content-Type", load_spec_request_mime_type(lspec));
1046         req.send(post_data);
1047     } else
1048         req.send(null);
1050     try {
1051         yield SUSPEND;
1052     } catch (e) {
1053         req.abort();
1054         throw e;
1055     }
1057     // Let the caller access the status and reponse data
1058     yield co_return(req);