1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * New Dimensions Consulting, Inc.
20 * Portions created by the Initial Developer are Copyright (C) 1999
21 * the Initial Developer. All Rights Reserved.
24 * Robert Ginda, rginda@ndcico.com, original author
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
43 const nsIBaseWindow = Components.interfaces.nsIBaseWindow;
44 const nsIXULWindow = Components.interfaces.nsIXULWindow;
45 const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor;
46 const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
47 const nsIDocShellTreeItem = Components.interfaces.nsIDocShellTreeItem;
49 var utils = new Object();
51 if (typeof document == "undefined") /* in xpcshell */
57 if (typeof dump == "function")
58 dumpln = function (str) {dump (str + "\n");}
59 else if (jsenv.HAS_RHINO)
61 dumpln = function (str) {
62 var out = java.lang.System.out;
63 out.println(str); out.flush();
67 dumpln = function () {} /* no suitable function */
72 var _dd_singleIndent = " ";
73 var _dd_indentLength = _dd_singleIndent.length;
74 var _dd_currentIndent = "";
75 var _dd_lastDumpWasOpen = false;
76 var _dd_timeStack = new Array();
77 var _dd_disableDepth = Number.MAX_VALUE;
78 var _dd_currentDepth = 0;
79 dd = function _dd (str) {
80 if (typeof str != "string") {
82 } else if (str[str.length - 1] == "{") {
84 if (_dd_currentDepth >= _dd_disableDepth)
86 if (str.indexOf("OFF") == 0)
87 _dd_disableDepth = _dd_currentDepth;
88 _dd_timeStack.push (new Date());
89 if (_dd_lastDumpWasOpen)
91 dump (_dd_pfx + _dd_currentIndent + str);
92 _dd_currentIndent += _dd_singleIndent;
93 _dd_lastDumpWasOpen = true;
94 } else if (str[0] == "}") {
95 if (--_dd_currentDepth >= _dd_disableDepth)
97 _dd_disableDepth = Number.MAX_VALUE;
98 var sufx = (new Date() - _dd_timeStack.pop()) / 1000 + " sec";
100 _dd_currentIndent.substr (0, _dd_currentIndent.length -
102 if (_dd_lastDumpWasOpen)
103 dumpln (str + " " + sufx);
105 dumpln (_dd_pfx + _dd_currentIndent + str + " " + sufx);
106 _dd_lastDumpWasOpen = false;
108 if (_dd_currentDepth >= _dd_disableDepth)
110 if (_dd_lastDumpWasOpen)
112 dumpln (_dd_pfx + _dd_currentIndent + str);
113 _dd_lastDumpWasOpen = false;
120 var jsenv = new Object();
121 jsenv.HAS_SECURITYMANAGER = ((typeof netscape == "object") &&
122 (typeof netscape.security == "object"));
123 jsenv.HAS_XPCOM = ((typeof Components == "object") &&
124 (typeof Components.classes == "object"));
125 jsenv.HAS_JAVA = (typeof java == "object");
126 jsenv.HAS_RHINO = (typeof defineClass == "function");
127 jsenv.HAS_DOCUMENT = (typeof document == "object");
129 /* Dumps an object in tree format, recurse specifiec the the number of objects
130 * to recurse, compress is a boolean that can uncompress (true) the output
131 * format, and level is the number of levels to intitialy indent (only useful
132 * internally.) A sample dumpObjectTree (o, 1) is shown below.
138 * | + nakkezzzz (object)
142 * + topic (string) 'ircclient.js:59: nothing is not defined'
143 * + getUsersLength (function) 9 lines
146 function dumpObjectTree (o, recurse, compress, level)
151 if (typeof recurse == "undefined")
153 if (typeof level == "undefined")
155 if (typeof compress == "undefined")
158 for (var i = 0; i < level; i++)
159 pfx += (compress) ? "| " : "| ";
161 var tee = (compress) ? "+ " : "+- ";
173 var sfunc = String(o[i]).split("\n");
174 if (sfunc[2] == " [native code]")
175 sfunc = "[native code]";
177 sfunc = sfunc.length + " lines";
178 s += pfx + tee + i + " (function) " + sfunc + "\n";
182 s += pfx + tee + i + " (object) " + o[i] + "\n";
185 if ((i != "parent") && (recurse))
186 s += dumpObjectTree (o[i], recurse - 1,
187 compress, level + 1);
191 if (o[i].length > 200)
192 s += pfx + tee + i + " (" + t + ") " +
193 o[i].length + " chars\n";
195 s += pfx + tee + i + " (" + t + ") '" + o[i] + "'\n";
199 s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";
204 s += pfx + tee + i + " (exception) " + ex + "\n";
218 function getService(contractID, iface)
221 var cls = Components.classes[contractID];
226 switch (typeof iface)
229 rv = cls.getService();
233 rv = cls.getService(Components.interfaces[iface]);
237 rv = cls.getService(iface);
249 function safeHTML(str)
251 function replaceChars(ch)
274 return String(str).replace(/[<>&"']/g, replaceChars);
277 function safeCSV(str)
279 function replaceChars(ch)
290 return '"' + String(str).replace(/"/g, replaceChars) + '"';
293 function alert(msg, parent, title)
295 var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
296 var nsIPromptService = Components.interfaces.nsIPromptService;
297 var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
302 ps.alert (parent, title, msg);
305 function confirm(msg, parent, title)
307 var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
308 var nsIPromptService = Components.interfaces.nsIPromptService;
309 var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
314 return ps.confirm (parent, title, msg);
317 function prompt(msg, initial, parent, title)
319 var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
320 var nsIPromptService = Components.interfaces.nsIPromptService;
321 var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
326 var rv = { value: initial };
328 if (!ps.prompt (parent, title, msg, rv, null, {value: null}))
334 function alertCheck(msg, checkMsg, checkVal, parent, title)
336 const PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
337 const nsIPromptService = Components.interfaces.nsIPromptService;
338 var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
344 var checkBoxWrapper = {value: !!checkVal};
345 ps.alertCheck(parent, title, msg, checkMsg, checkBoxWrapper);
346 return checkBoxWrapper.value;
350 function getChildById (element, id)
352 var nl = element.getElementsByAttribute("id", id);
356 function openTopWin (url)
358 var window = getWindowByType ("navigator:browser");
361 var base = getBaseWindowFromWindow (window);
365 window._content.location.href = url;
370 return openDialog (getBrowserURL(), "_blank", "chrome,all,dialog=no", url);
373 function getWindowByType (windowType)
375 const MEDIATOR_CONTRACTID =
376 "@mozilla.org/appshell/window-mediator;1";
377 const nsIWindowMediator = Components.interfaces.nsIWindowMediator;
380 Components.classes[MEDIATOR_CONTRACTID].getService(nsIWindowMediator);
382 return windowManager.getMostRecentWindow(windowType);
385 function htmlVA (attribs, href, contents)
388 attribs = {"class": "venkman-link", target: "_content"};
389 else if (attribs["class"])
390 attribs["class"] += " venkman-link";
392 attribs["class"] = "venkman-link";
394 if (typeof contents == "undefined")
396 contents = htmlSpan();
397 insertHyphenatedWord (href, contents);
400 return htmlA (attribs, href, contents);
403 function insertHyphenatedWord (longWord, containerTag)
405 var wordParts = splitLongWord (longWord, MAX_WORD_LEN);
406 containerTag.appendChild (htmlWBR());
407 for (var i = 0; i < wordParts.length; ++i)
409 containerTag.appendChild (document.createTextNode (wordParts[i]));
410 if (i != wordParts.length)
411 containerTag.appendChild (htmlWBR());
415 function insertLink (matchText, containerTag)
421 ary = matchText.match(/([.,]+)$/);
424 linkText = RegExp.leftContext;
429 linkText = matchText;
432 var ary = linkText.match (/^(\w[\w-]+):/);
435 if (!("schemes" in utils))
437 var pfx = "@mozilla.org/network/protocol;1?name=";
440 utils.schemes = new Object();
441 for (var c in Components.classes)
443 if (c.indexOf(pfx) == 0)
444 utils.schemes[c.substr(len)] = true;
448 if (!(ary[1] in utils.schemes))
450 insertHyphenatedWord(matchText, containerTag);
458 href = "http://" + linkText;
461 var anchor = htmlVA (null, href, "");
462 insertHyphenatedWord (linkText, anchor);
463 containerTag.appendChild (anchor);
465 insertHyphenatedWord (trailing, containerTag);
469 function insertQuote (matchText, containerTag, msgtype)
471 if (msgtype[0] == "#")
473 containerTag.appendChild(document.createTextNode(matchText));
477 if (matchText == "``")
478 containerTag.appendChild(document.createTextNode("\u201c"));
480 containerTag.appendChild(document.createTextNode("\u201d"));
483 /* length should be an even number >= 6 */
484 function abbreviateWord (str, length)
486 if (str.length <= length || length < 6)
489 var left = str.substr (0, (length / 2) - 1);
490 var right = str.substr (str.length - (length / 2) + 1);
492 return left + "..." + right;
495 function toBool (val)
510 return (val.search(/true|on|yes|1/i) != -1);
516 /* some of the drag and drop code has an annoying appetite for exceptions. any
517 * exception raised during a dnd operation causes the operation to fail silently.
518 * passing the function through one of these adapters lets you use "return
519 * false on planned failure" symantics, and dumps any exceptions caught
521 function Prophylactic (parentObj, fun)
530 rv = fun.apply (parentObj, arguments);
534 dd ("Prophylactic caught an exception:\n" +
547 function argumentsAsArray (args, start)
549 if (typeof start == "undefined")
552 if (start >= args.length)
555 var rv = new Array();
557 for (var i = start; i < args.length; ++i)
563 function splitLongWord (str, pos)
565 if (str.length <= pos)
568 var ary = new Array();
571 while (right.length > pos)
573 /* search for a nice place to break the word, fuzzfactor of +/-5,
574 * centered around |pos| */
576 right.substring(pos - 5, pos + 5).search(/[^A-Za-z0-9]/);
578 splitPos = (splitPos != -1) ? pos - 4 + splitPos : pos;
579 ary.push(right.substr (0, splitPos));
580 right = right.substr (splitPos);
588 function wrapText (str, width)
591 while (str.length > width)
593 rv += str.substr(0, width) + "\n";
594 str = str.substr(width);
599 function wordCap (str)
604 return str[0].toUpperCase() + str.substr(1);
608 * Clones an existing object (Only the enumerable properties
609 * of course.) use as a function..
610 * var c = Clone (obj);
611 * or a constructor...
612 * var c = new Clone (obj);
616 var robj = new Object();
625 function getXULWindowFromWindow (win)
628 //dd ("getXULWindowFromWindow: before: getInterface is " + win.getInterface);
631 var requestor = win.QueryInterface(nsIInterfaceRequestor);
632 var nav = requestor.getInterface(nsIWebNavigation);
633 var dsti = nav.QueryInterface(nsIDocShellTreeItem);
634 var owner = dsti.treeOwner;
635 requestor = owner.QueryInterface(nsIInterfaceRequestor);
636 rv = requestor.getInterface(nsIXULWindow);
641 //dd ("not a nsIXULWindow: " + formatException(ex));
642 /* ignore no-interface exception */
645 //dd ("getXULWindowFromWindow: after: getInterface is " + win.getInterface);
649 function getBaseWindowFromWindow (win)
652 //dd ("getBaseWindowFromWindow: before: getInterface is " + win.getInterface);
655 var requestor = win.QueryInterface(nsIInterfaceRequestor);
656 var nav = requestor.getInterface(nsIWebNavigation);
657 var dsti = nav.QueryInterface(nsIDocShellTreeItem);
658 var owner = dsti.treeOwner;
659 requestor = owner.QueryInterface(nsIInterfaceRequestor);
660 rv = requestor.getInterface(nsIBaseWindow);
665 //dd ("not a nsIXULWindow: " + formatException(ex));
666 /* ignore no-interface exception */
669 //dd ("getBaseWindowFromWindow: after: getInterface is " + win.getInterface);
673 function getSpecialDirectory(name)
675 if (!("directoryService" in utils))
677 const DS_CTR = "@mozilla.org/file/directory_service;1";
678 const nsIProperties = Components.interfaces.nsIProperties;
680 utils.directoryService =
681 Components.classes[DS_CTR].getService(nsIProperties);
684 return utils.directoryService.get(name, Components.interfaces.nsIFile);
687 function getPathFromURL (url)
689 var ary = url.match(/^(.*\/)([^\/?#]*)(\?|#|$)/);
696 function getFileFromPath (path)
698 var ary = path.match(/\/([^\/?#;]+)(\?|#|$|;)/);
705 function getURLSpecFromFile (file)
710 const IOS_CTRID = "@mozilla.org/network/io-service;1";
711 const LOCALFILE_CTRID = "@mozilla.org/file/local;1";
713 const nsIIOService = Components.interfaces.nsIIOService;
714 const nsILocalFile = Components.interfaces.nsILocalFile;
716 if (typeof file == "string")
719 Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
720 fileObj.initWithPath(file);
724 var service = Components.classes[IOS_CTRID].getService(nsIIOService);
725 /* In sept 2002, bug 166792 moved this method to the nsIFileProtocolHandler
726 * interface, but we need to support older versions too. */
727 if ("getURLSpecFromFile" in service)
728 return service.getURLSpecFromFile(file);
730 var nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
731 var fileHandler = service.getProtocolHandler("file");
732 fileHandler = fileHandler.QueryInterface(nsIFileProtocolHandler);
733 return fileHandler.getURLSpecFromFile(file);
736 function getCommonPfx (list)
741 for (var i = 1; i < l; i++)
743 for (var c = 0; c < pfx.length; c++)
744 if (pfx[c] != list[i][c])
745 pfx = pfx.substr (0, c);
752 function renameProperty (obj, oldname, newname)
755 if (oldname == newname)
758 obj[newname] = obj[oldname];
763 function newObject(contractID, iface)
765 if (!jsenv.HAS_XPCOM)
768 var obj = Components.classes[contractID].createInstance();
771 switch (typeof iface)
774 rv = obj.QueryInterface(Components.interfaces[iface]);
778 rv = obj.QueryInterface[iface];
792 var rv = new Array();
801 function parseSections (str, sections)
803 var rv = new Object();
806 for (var s in sections)
813 var i = str.search(sections[s]);
816 rv[currentSection] = str.substr(0, i);
818 str = RegExp.rightContext;
819 str = str.replace(/^(\n|\r|\r\n)/, "");
824 rv[currentSection] = str;
833 function replaceStrings (str, obj)
838 str = str.replace(RegExp(p, "g"), obj[p]);
842 function stringTrim (s)
846 s = s.replace (/^\s+/, "");
847 return s.replace (/\s+$/, "");
850 function formatDateOffset (seconds, format)
852 seconds = Math.floor(seconds);
853 var minutes = Math.floor(seconds / 60);
854 seconds = seconds % 60;
855 var hours = Math.floor(minutes / 60);
856 minutes = minutes % 60;
857 var days = Math.floor(hours / 24);
862 var ary = new Array();
864 ary.push (days + " days");
866 ary.push (hours + " hours");
868 ary.push (minutes + " minutes");
870 ary.push (seconds + " seconds");
872 format = ary.join(", ");
876 format = format.replace ("%d", days);
877 format = format.replace ("%h", hours);
878 format = format.replace ("%m", minutes);
879 format = format.replace ("%s", seconds);
885 function arrayHasElementAt(ary, i)
887 return typeof ary[i] != "undefined";
890 function arraySpeak (ary, single, plural)
906 rv = ary[0] + " and " + ary[1];
912 for (var i = 0; i < ary.length - 1; ++i)
914 rv += "and " + ary[ary.length - 1];
924 function arrayOrFlag (ary, i, flag)
932 function arrayAndFlag (ary, i, flag)
940 function arrayContains (ary, elem)
942 return (arrayIndexOf (ary, elem) != -1);
945 function arrayIndexOf (ary, elem, start)
950 var len = ary.length;
952 if (typeof start == "undefined")
955 for (var i = start; i < len; ++i)
964 function arrayInsertAt (ary, i, o)
967 ary.splice (i, 0, o);
971 function arrayRemoveAt (ary, i)
978 function getRandomElement (ary)
980 var i = Math.floor (Math.random() * ary.length)
981 if (i == ary.length) i = 0;
987 function zeroPad (num, decimals)
989 var rv = String(num);
991 for (var i = 0; i < decimals - len; ++i)
997 function leftPadString (str, num, ch)
1000 var len = rv.length;
1001 for (var i = len; i < num; ++i)
1007 function roundTo (num, prec)
1009 return Math.round(num * Math.pow (10, prec)) / Math.pow (10, prec);
1012 function randomRange (min, max)
1015 if (typeof min == "undefined")
1018 if (typeof max == "undefined")
1021 var rv = (Math.floor(Math.round((Math.random() * (max - min)) + min )));
1027 function getStackTrace ()
1030 if (!jsenv.HAS_XPCOM)
1031 return "No stack trace available.";
1033 var frame = Components.stack.caller;
1038 var name = frame.name ? frame.name : "[anonymous]";
1039 str += "\n" + name + "@" + frame.lineNumber;
1040 frame = frame.caller;
1047 function getInterfaces (cls)
1049 if (!jsenv.HAS_XPCOM)
1052 var rv = new Object();
1055 for (var i in Components.interfaces)
1059 var ifc = Components.interfaces[i];
1060 cls.QueryInterface(ifc);
1073 function makeExpression (items)
1075 function escapeItem (item, first)
1078 if (item.match(/^[0-9]+$/i))
1079 return "[" + item + "]";
1080 // Words/other items that don't need quoting.
1081 if (item.match(/^[a-z_][a-z0-9_]*$/i))
1082 return (!first ? "." : "") + item;
1083 // Quote everything else.
1084 return "[" + item.quote() + "]";
1087 var expression = escapeItem(items[0], true);
1089 for (var i = 1; i < items.length; i++)
1090 expression += escapeItem(items[i], false);
1095 function isinstance(inst, base)
1097 /* Returns |true| if |inst| was constructed by |base|. Not 100% accurate,
1098 * but plenty good enough for us. This is to work around the fix for bug
1099 * 254067 which makes instanceof fail if the two sides are 'from'
1100 * different windows (something we don't care about).
1102 return (inst && base &&
1103 ((inst instanceof base) ||
1104 (inst.constructor && (inst.constructor.name == base.name))));