~ubuntu-branches/ubuntu/jaunty/venkman/jaunty

« back to all changes in this revision

Viewing changes to chrome/content/venkman/venkman-utils.js

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2006-11-25 13:09:12 UTC
  • mfrom: (2.1.5 feisty)
  • Revision ID: james.westby@ubuntu.com-20061125130912-lf5wuz22ijh0k8ed
Tags: 0.9.87-6
debian/postinst: Don't invoque chrome updaters (except iceape one) on
first installs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 
 *
3
 
 * The contents of this file are subject to the Mozilla Public
4
 
 * License Version 1.1 (the "License"); you may not use this file
5
 
 * except in compliance with the License. You may obtain a copy of
6
 
 * the License at http://www.mozilla.org/MPL/
7
 
 *
8
 
 * Software distributed under the License is distributed on an "AS
9
 
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
 
 * implied. See the License for the specific language governing
11
 
 * rights and limitations under the License.
12
 
 *
13
 
 * The Original Code is mozilla.org code
14
 
 *
15
 
 * The Initial Developer of the Original Code is New Dimensions Consulting,
16
 
 * Inc. Portions created by New Dimensions Consulting, Inc. are
17
 
 * Copyright (C) 1999 New Dimensions Consulting, Inc. All Rights Reserved.
18
 
 *
19
 
 * Contributor(s):
20
 
 *  Robert Ginda, rginda@ndcico.com, original author
21
 
 *
22
 
 *
23
 
 * JavaScript utility functions.
24
 
 */
25
 
 
26
 
var dumpln;
27
 
var dd;
28
 
 
29
 
const nsIBaseWindow         = Components.interfaces.nsIBaseWindow;
30
 
const nsIXULWindow          = Components.interfaces.nsIXULWindow;
31
 
const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor;
32
 
const nsIWebNavigation      = Components.interfaces.nsIWebNavigation;
33
 
const nsIDocShellTreeItem   = Components.interfaces.nsIDocShellTreeItem;
34
 
 
35
 
var utils = new Object();
36
 
 
37
 
if (typeof document == "undefined") /* in xpcshell */
38
 
{
39
 
    dumpln = print;
40
 
}
41
 
else
42
 
{
43
 
    if (typeof dump == "function")
44
 
        dumpln = function (str) {dump (str + "\n");}
45
 
    else if (jsenv.HAS_RHINO)
46
 
    {
47
 
        dumpln = function (str) {
48
 
                     var out = java.lang.System.out;
49
 
                     out.println(str); out.flush();
50
 
                 }
51
 
    }
52
 
    else
53
 
        dumpln = function () {} /* no suitable function */
54
 
}
55
 
 
56
 
if (DEBUG) {
57
 
    var _dd_pfx = "";
58
 
    var _dd_singleIndent = "  ";
59
 
    var _dd_indentLength = _dd_singleIndent.length;
60
 
    var _dd_currentIndent = "";
61
 
    var _dd_lastDumpWasOpen = false;
62
 
    var _dd_timeStack = new Array();
63
 
    var _dd_disableDepth = Number.MAX_VALUE;
64
 
    var _dd_currentDepth = 0;
65
 
    dd = function _dd (str) {
66
 
             if (typeof str != "string") {
67
 
                 dumpln (str);
68
 
             } else if (str[str.length - 1] == "{") {
69
 
                 ++_dd_currentDepth;
70
 
                 if (_dd_currentDepth >= _dd_disableDepth)
71
 
                     return;
72
 
                 if (str.indexOf("OFF") == 0)
73
 
                     _dd_disableDepth = _dd_currentDepth;
74
 
                 _dd_timeStack.push (new Date());
75
 
                 if (_dd_lastDumpWasOpen)
76
 
                     dump("\n");
77
 
                 dump (_dd_pfx + _dd_currentIndent + str);
78
 
                 _dd_currentIndent += _dd_singleIndent;
79
 
                 _dd_lastDumpWasOpen = true;
80
 
             } else if (str[0] == "}") {
81
 
                 if (--_dd_currentDepth >= _dd_disableDepth)
82
 
                     return;
83
 
                 _dd_disableDepth = Number.MAX_VALUE;
84
 
                 var sufx = (new Date() - _dd_timeStack.pop()) / 1000 + " sec";
85
 
                 _dd_currentIndent = 
86
 
                     _dd_currentIndent.substr (0, _dd_currentIndent.length -
87
 
                                               _dd_indentLength);
88
 
                 if (_dd_lastDumpWasOpen)
89
 
                     dumpln (str + " " + sufx);
90
 
                 else
91
 
                     dumpln (_dd_pfx + _dd_currentIndent + str + " " + sufx);
92
 
                 _dd_lastDumpWasOpen = false;
93
 
             } else {
94
 
                 if (_dd_currentDepth >= _dd_disableDepth)
95
 
                     return;
96
 
                 if (_dd_lastDumpWasOpen)
97
 
                     dump ("\n");
98
 
                 dumpln (_dd_pfx + _dd_currentIndent + str);
99
 
                 _dd_lastDumpWasOpen = false;
100
 
             }    
101
 
         }
102
 
} else {
103
 
    dd = function (){};
104
 
}
105
 
 
106
 
var jsenv = new Object();
107
 
jsenv.HAS_SECURITYMANAGER = ((typeof netscape == "object") &&
108
 
                             (typeof netscape.security == "object"));
109
 
jsenv.HAS_XPCOM = ((typeof Components == "object") &&
110
 
                   (typeof Components.classes == "object"));
111
 
jsenv.HAS_JAVA = (typeof java == "object");
112
 
jsenv.HAS_RHINO = (typeof defineClass == "function");
113
 
jsenv.HAS_DOCUMENT = (typeof document == "object");
114
 
 
115
 
/* Dumps an object in tree format, recurse specifiec the the number of objects
116
 
 * to recurse, compress is a boolean that can uncompress (true) the output
117
 
 * format, and level is the number of levels to intitialy indent (only useful
118
 
 * internally.)  A sample dumpObjectTree (o, 1) is shown below.
119
 
 *
120
 
 * + parent (object)
121
 
 * + users (object)
122
 
 * | + jsbot (object)
123
 
 * | + mrjs (object)
124
 
 * | + nakkezzzz (object)
125
 
 * | *
126
 
 * + bans (object)
127
 
 * | *
128
 
 * + topic (string) 'ircclient.js:59: nothing is not defined'
129
 
 * + getUsersLength (function) 9 lines
130
 
 * *
131
 
 */
132
 
function dumpObjectTree (o, recurse, compress, level)
133
 
{
134
 
    var s = "";
135
 
    var pfx = "";
136
 
 
137
 
    if (typeof recurse == "undefined")
138
 
        recurse = 0;
139
 
    if (typeof level == "undefined")
140
 
        level = 0;
141
 
    if (typeof compress == "undefined")
142
 
        compress = true;
143
 
    
144
 
    for (var i = 0; i < level; i++)
145
 
        pfx += (compress) ? "| " : "|  ";
146
 
 
147
 
    var tee = (compress) ? "+ " : "+- ";
148
 
 
149
 
    for (i in o)
150
 
    {
151
 
        var t;
152
 
        try
153
 
        {
154
 
            t = typeof o[i];
155
 
        
156
 
            switch (t)
157
 
            {
158
 
                case "function":
159
 
                    var sfunc = String(o[i]).split("\n");
160
 
                    if (sfunc[2] == "    [native code]")
161
 
                        sfunc = "[native code]";
162
 
                    else
163
 
                        sfunc = sfunc.length + " lines";
164
 
                    s += pfx + tee + i + " (function) " + sfunc + "\n";
165
 
                    break;
166
 
                    
167
 
                case "object":
168
 
                    s += pfx + tee + i + " (object) " + o[i] + "\n";
169
 
                    if (!compress)
170
 
                        s += pfx + "|\n";
171
 
                    if ((i != "parent") && (recurse))
172
 
                        s += dumpObjectTree (o[i], recurse - 1,
173
 
                                             compress, level + 1);
174
 
                    break;
175
 
                    
176
 
                case "string":
177
 
                    if (o[i].length > 200)
178
 
                        s += pfx + tee + i + " (" + t + ") " + 
179
 
                            o[i].length + " chars\n";
180
 
                    else
181
 
                        s += pfx + tee + i + " (" + t + ") '" + o[i] + "'\n";
182
 
                    break;
183
 
                    
184
 
                default:
185
 
                    s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";
186
 
            }
187
 
        }
188
 
        catch (ex)
189
 
        {
190
 
            s += pfx + tee + i + " (exception) " + ex + "\n";
191
 
        }
192
 
 
193
 
        if (!compress)
194
 
            s += pfx + "|\n";
195
 
 
196
 
    }
197
 
 
198
 
    s += pfx + "*\n";
199
 
    
200
 
    return s;
201
 
    
202
 
}
203
 
 
204
 
function safeHTML(str)
205
 
{
206
 
    function replaceChars(ch)
207
 
    {
208
 
        switch (ch)
209
 
        {
210
 
            case "<":
211
 
                return "&lt;";
212
 
            
213
 
            case ">":
214
 
                return "&gt;";
215
 
                    
216
 
            case "&":
217
 
                return "&amp;";
218
 
        }
219
 
 
220
 
        return "?";
221
 
    };
222
 
        
223
 
    return String(str).replace(/[<>&]/g, replaceChars);
224
 
}
225
 
 
226
 
function alert(msg, parent, title)
227
 
{
228
 
    var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
229
 
    var nsIPromptService = Components.interfaces.nsIPromptService;
230
 
    var ps = Components.classes[PROMPT_CTRID].createInstance(nsIPromptService);
231
 
    if (!parent)
232
 
        parent = window;
233
 
    if (!title)
234
 
        title = MSG_ALERT;
235
 
    ps.alert (parent, title, msg);
236
 
}
237
 
 
238
 
function confirm(msg, parent, title)
239
 
{
240
 
    var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
241
 
    var nsIPromptService = Components.interfaces.nsIPromptService;
242
 
    var ps = Components.classes[PROMPT_CTRID].createInstance(nsIPromptService);
243
 
    if (!parent)
244
 
        parent = window;
245
 
    if (!title)
246
 
        title = MSG_CONFIRM;
247
 
    return ps.confirm (parent, title, msg);
248
 
}
249
 
 
250
 
function prompt(msg, initial, parent, title)
251
 
{
252
 
    var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
253
 
    var nsIPromptService = Components.interfaces.nsIPromptService;
254
 
    var ps = Components.classes[PROMPT_CTRID].createInstance(nsIPromptService);
255
 
    if (!parent)
256
 
        parent = window;
257
 
    if (!title)
258
 
        title = MSG_PROMPT;
259
 
    rv = { value: initial };
260
 
 
261
 
    if (!ps.prompt (parent, title, msg, rv, null, {value: null}))
262
 
        return null;
263
 
 
264
 
    return rv.value
265
 
}
266
 
 
267
 
function getChildById (element, id)
268
 
{
269
 
    var nl = element.getElementsByAttribute("id", id);
270
 
    return nl.item(0);
271
 
}
272
 
 
273
 
function openTopWin (url)
274
 
{
275
 
    var window = getWindowByType ("navigator:browser");
276
 
    if (window)
277
 
    {
278
 
        var base = getBaseWindowFromWindow (window);
279
 
        if (base.enabled)
280
 
        {
281
 
            window.focus();
282
 
            window._content.location.href = url;
283
 
            return window;
284
 
        }
285
 
    }
286
 
 
287
 
    return openDialog (getBrowserURL(), "_blank", "chrome,all,dialog=no", url);
288
 
}
289
 
    
290
 
function getWindowByType (windowType)
291
 
{
292
 
    const MEDIATOR_CONTRACTID =
293
 
        "@mozilla.org/appshell/window-mediator;1";
294
 
    const nsIWindowMediator  = Components.interfaces.nsIWindowMediator;
295
 
 
296
 
    var windowManager =
297
 
        Components.classes[MEDIATOR_CONTRACTID].getService(nsIWindowMediator);
298
 
 
299
 
    return windowManager.getMostRecentWindow(windowType);
300
 
}
301
 
 
302
 
function htmlVA (attribs, href, contents)
303
 
{
304
 
    if (!attribs)
305
 
        attribs = {"class": "venkman-link", target: "_content"};
306
 
    else if (attribs["class"])
307
 
        attribs["class"] += " venkman-link";
308
 
    else
309
 
        attribs["class"] = "venkman-link";
310
 
 
311
 
    if (typeof contents == "undefined")
312
 
    {
313
 
        contents = htmlSpan();
314
 
        insertHyphenatedWord (href, contents);
315
 
    }
316
 
    
317
 
    return htmlA (attribs, href, contents);
318
 
}
319
 
 
320
 
function insertHyphenatedWord (longWord, containerTag)
321
 
{
322
 
    var wordParts = splitLongWord (longWord, MAX_WORD_LEN);
323
 
    containerTag.appendChild (htmlWBR());
324
 
    for (var i = 0; i < wordParts.length; ++i)
325
 
    {
326
 
        containerTag.appendChild (document.createTextNode (wordParts[i]));
327
 
        if (i != wordParts.length)
328
 
            containerTag.appendChild (htmlWBR());
329
 
    }
330
 
}
331
 
 
332
 
function insertLink (matchText, containerTag)
333
 
{
334
 
    var href;
335
 
    var linkText;
336
 
    
337
 
    var trailing;
338
 
    ary = matchText.match(/([.,]+)$/);
339
 
    if (ary)
340
 
    {
341
 
        linkText = RegExp.leftContext;
342
 
        trailing = ary[1];
343
 
    }
344
 
    else
345
 
    {
346
 
        linkText = matchText;
347
 
    }
348
 
 
349
 
    var ary = linkText.match (/^(\w[\w-]+):/);
350
 
    if (ary)
351
 
    {
352
 
        if (!("schemes" in utils))
353
 
        {
354
 
            var pfx = "@mozilla.org/network/protocol;1?name=";
355
 
            var len = pfx.length
356
 
 
357
 
            utils.schemes = new Object();
358
 
            for (var c in Components.classes)
359
 
            {
360
 
                if (c.indexOf(pfx) == 0)
361
 
                    utils.schemes[c.substr(len)] = true;
362
 
            }
363
 
        }
364
 
        
365
 
        if (!(ary[1] in utils.schemes))
366
 
        {
367
 
            insertHyphenatedWord(matchText, containerTag);
368
 
            return;
369
 
        }
370
 
 
371
 
        href = linkText;
372
 
    }
373
 
    else
374
 
    {
375
 
        href = "http://" + linkText;
376
 
    }
377
 
 
378
 
    var anchor = htmlVA (null, href, "");
379
 
    insertHyphenatedWord (linkText, anchor);
380
 
    containerTag.appendChild (anchor);
381
 
    if (trailing)
382
 
        insertHyphenatedWord (trailing, containerTag);
383
 
    
384
 
}
385
 
 
386
 
function insertQuote (matchText, containerTag, msgtype)
387
 
{
388
 
    if (msgtype[0] == "#")
389
 
    {
390
 
        containerTag.appendChild(document.createTextNode(matchText));
391
 
        return;
392
 
    }
393
 
    
394
 
    if (matchText == "``")
395
 
        containerTag.appendChild(document.createTextNode("\u201c"));
396
 
    else
397
 
        containerTag.appendChild(document.createTextNode("\u201d"));
398
 
}
399
 
 
400
 
/* length should be an even number >= 6 */
401
 
function abbreviateWord (str, length)
402
 
{
403
 
    if (str.length <= length || length < 6)
404
 
        return str;
405
 
 
406
 
    var left = str.substr (0, (length / 2) - 1);
407
 
    var right = str.substr (str.length - (length / 2) + 1);
408
 
 
409
 
    return left + "..." + right;
410
 
}
411
 
 
412
 
function toBool (val)
413
 
{
414
 
    switch (typeof val)
415
 
    {
416
 
        case "boolean":
417
 
            return val;
418
 
    
419
 
        case "number":
420
 
            return val != 0;
421
 
            
422
 
        default:
423
 
            val = String(val);
424
 
            /* fall through */
425
 
 
426
 
        case "string":
427
 
            return (val.search(/true|on|yes|1/i) != -1);
428
 
    }
429
 
 
430
 
    return null;
431
 
}
432
 
 
433
 
/* some of the drag and drop code has an annoying appetite for exceptions.  any
434
 
 * exception raised during a dnd operation causes the operation to fail silently.
435
 
 * passing the function through one of these adapters lets you use "return
436
 
 * false on planned failure" symantics, and dumps any exceptions caught
437
 
 * to the console. */
438
 
function Prophylactic (parentObj, fun)
439
 
{
440
 
    function adapter ()
441
 
    {
442
 
        var ex;
443
 
        var rv = false;
444
 
        
445
 
        try
446
 
        {
447
 
            rv = fun.apply (parentObj, arguments);
448
 
        }
449
 
        catch (ex)
450
 
        {
451
 
            dd ("Prophylactic caught an exception:\n" +
452
 
                dumpObjectTree(ex));
453
 
        }
454
 
        
455
 
        if (!rv)
456
 
            throw "goodger";
457
 
 
458
 
        return rv;
459
 
    };
460
 
    
461
 
    return adapter;
462
 
}
463
 
 
464
 
function argumentsAsArray (args, start)
465
 
{
466
 
    if (typeof start == "undefined")
467
 
        start = 0;
468
 
 
469
 
    if (start >= args.length)
470
 
        return null;
471
 
    
472
 
    var rv = new Array();
473
 
    
474
 
    for (var i = start; i < args.length; ++i)
475
 
        rv.push(args[i]);
476
 
    
477
 
    return rv;
478
 
}
479
 
 
480
 
function splitLongWord (str, pos)
481
 
{
482
 
    if (str.length <= pos)
483
 
        return [str];
484
 
 
485
 
    var ary = new Array();
486
 
    var right = str;
487
 
    
488
 
    while (right.length > pos)
489
 
    {
490
 
        /* search for a nice place to break the word, fuzzfactor of +/-5, 
491
 
         * centered around |pos| */
492
 
        var splitPos =
493
 
            right.substring(pos - 5, pos + 5).search(/[^A-Za-z0-9]/);
494
 
 
495
 
        splitPos = (splitPos != -1) ? pos - 4 + splitPos : pos;
496
 
        ary.push(right.substr (0, splitPos));
497
 
        right = right.substr (splitPos);
498
 
    }
499
 
 
500
 
    ary.push (right);
501
 
 
502
 
    return ary;
503
 
}
504
 
 
505
 
function wrapText (str, width)
506
 
{
507
 
    var rv = "";
508
 
    while (str.length > width)
509
 
    {
510
 
        rv += str.substr(0, width) + "\n";
511
 
        str = str.substr(width);
512
 
    }
513
 
    return rv + str;
514
 
}
515
 
 
516
 
function wordCap (str)
517
 
{
518
 
    if (!str)
519
 
        return str;
520
 
    
521
 
    return str[0].toUpperCase() + str.substr(1);
522
 
}
523
 
 
524
 
/*
525
 
 * Clones an existing object (Only the enumerable properties
526
 
 * of course.) use as a function..
527
 
 * var c = Clone (obj);
528
 
 * or a constructor...
529
 
 * var c = new Clone (obj);
530
 
 */
531
 
function Clone (obj)
532
 
{
533
 
    var robj = new Object();
534
 
 
535
 
    for (var p in obj)
536
 
        robj[p] = obj[p];
537
 
 
538
 
    return robj;
539
 
    
540
 
}
541
 
 
542
 
function getXULWindowFromWindow (win)
543
 
{
544
 
    var rv;
545
 
    //dd ("getXULWindowFromWindow: before: getInterface is " + win.getInterface);
546
 
    try
547
 
    {
548
 
        var requestor = win.QueryInterface(nsIInterfaceRequestor);
549
 
        var nav = requestor.getInterface(nsIWebNavigation);
550
 
        var dsti = nav.QueryInterface(nsIDocShellTreeItem);
551
 
        var owner = dsti.treeOwner;
552
 
        requestor = owner.QueryInterface(nsIInterfaceRequestor);
553
 
        rv = requestor.getInterface(nsIXULWindow);
554
 
    }
555
 
    catch (ex)
556
 
    {
557
 
        rv = null;
558
 
        //dd ("not a nsIXULWindow: " + formatException(ex));
559
 
        /* ignore no-interface exception */
560
 
    }
561
 
 
562
 
    //dd ("getXULWindowFromWindow: after: getInterface is " + win.getInterface);
563
 
    return rv;
564
 
}
565
 
 
566
 
function getBaseWindowFromWindow (win)
567
 
{
568
 
    var rv;
569
 
    //dd ("getBaseWindowFromWindow: before: getInterface is " + win.getInterface);
570
 
    try
571
 
    {
572
 
        var requestor = win.QueryInterface(nsIInterfaceRequestor);
573
 
        var nav = requestor.getInterface(nsIWebNavigation);
574
 
        var dsti = nav.QueryInterface(nsIDocShellTreeItem);
575
 
        var owner = dsti.treeOwner;
576
 
        requestor = owner.QueryInterface(nsIInterfaceRequestor);
577
 
        rv = requestor.getInterface(nsIBaseWindow);
578
 
    }
579
 
    catch (ex)
580
 
    {
581
 
        rv = null;
582
 
        //dd ("not a nsIXULWindow: " + formatException(ex));
583
 
        /* ignore no-interface exception */
584
 
    }
585
 
 
586
 
    //dd ("getBaseWindowFromWindow: after: getInterface is " + win.getInterface);
587
 
    return rv;
588
 
}
589
 
 
590
 
function getSpecialDirectory(name)
591
 
{
592
 
    if (!("directoryService" in utils))
593
 
    {
594
 
        const DS_CTR = "@mozilla.org/file/directory_service;1";
595
 
        const nsIProperties = Components.interfaces.nsIProperties;
596
 
    
597
 
        utils.directoryService =
598
 
            Components.classes[DS_CTR].getService(nsIProperties);
599
 
    }
600
 
    
601
 
    return utils.directoryService.get(name, Components.interfaces.nsIFile);
602
 
}
603
 
 
604
 
function getPathFromURL (url)
605
 
{
606
 
    var ary = url.match(/^(.*\/)([^\/?#]+)(\?|#|$)/);
607
 
    if (ary)
608
 
        return ary[1];
609
 
 
610
 
    return url;
611
 
}
612
 
 
613
 
function getFileFromPath (path)
614
 
{
615
 
    var ary = path.match(/\/([^\/?#;]+)(\?|#|$|;)/);
616
 
    if (ary)
617
 
        return ary[1];
618
 
 
619
 
    return path;
620
 
}
621
 
 
622
 
function getURLSpecFromFile (file)
623
 
{
624
 
    if (!file)
625
 
        return null;
626
 
 
627
 
    const IOS_CTRID = "@mozilla.org/network/io-service;1";
628
 
    const LOCALFILE_CTRID = "@mozilla.org/file/local;1";
629
 
 
630
 
    const nsIIOService = Components.interfaces.nsIIOService;
631
 
    const nsILocalFile = Components.interfaces.nsILocalFile;
632
 
    
633
 
    if (typeof file == "string")
634
 
    {
635
 
        var fileObj =
636
 
            Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
637
 
        fileObj.initWithPath(file);
638
 
        file = fileObj;
639
 
    }
640
 
    
641
 
    var service = Components.classes[IOS_CTRID].getService(nsIIOService);
642
 
    /* In sept 2002, bug 166792 moved this method to the nsIFileProtocolHandler
643
 
     * interface, but we need to support older versions too. */
644
 
    if ("getURLSpecFromFile" in service)
645
 
        return service.getURLSpecFromFile(file);
646
 
 
647
 
    var nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
648
 
    var fileHandler = service.getProtocolHandler("file");
649
 
    fileHandler = fileHandler.QueryInterface(nsIFileProtocolHandler);
650
 
    return fileHandler.getURLSpecFromFile(file);
651
 
}
652
 
 
653
 
function getCommonPfx (list)
654
 
{
655
 
    var pfx = list[0];
656
 
    var l = list.length;
657
 
    
658
 
    for (var i = 1; i < l; i++)
659
 
    {
660
 
        for (var c = 0; c < pfx.length; c++)
661
 
            if (pfx[c] != list[i][c])
662
 
                pfx = pfx.substr (0, c);
663
 
    }
664
 
 
665
 
    return pfx;
666
 
 
667
 
}
668
 
 
669
 
function renameProperty (obj, oldname, newname)
670
 
{
671
 
 
672
 
    if (oldname == newname)
673
 
        return;
674
 
    
675
 
    obj[newname] = obj[oldname];
676
 
    delete obj[oldname];
677
 
    
678
 
}
679
 
 
680
 
function newObject(contractID, iface)
681
 
{
682
 
    if (!jsenv.HAS_XPCOM)
683
 
        return null;
684
 
 
685
 
    var obj = Components.classes[contractID].createInstance();
686
 
    var rv;
687
 
 
688
 
    switch (typeof iface)
689
 
    {
690
 
        case "string":
691
 
            rv = obj.QueryInterface(Components.interfaces[iface]);
692
 
            break;
693
 
 
694
 
        case "object":
695
 
            rv = obj.QueryInterface[iface];
696
 
            break;
697
 
 
698
 
        default:
699
 
            rv = null;
700
 
            break;
701
 
    }
702
 
 
703
 
    return rv;
704
 
    
705
 
}
706
 
 
707
 
function keys (o)
708
 
{
709
 
    var rv = new Array();
710
 
    
711
 
    for (var p in o)
712
 
        rv.push(p);
713
 
 
714
 
    return rv;
715
 
    
716
 
}
717
 
 
718
 
function parseSections (str, sections)
719
 
{
720
 
    var rv = new Object();
721
 
    var currentSection;
722
 
 
723
 
    for (var s in sections)
724
 
    {
725
 
        if (!currentSection)
726
 
            currentSection = s;
727
 
        
728
 
        if (sections[s])
729
 
        {
730
 
            var i = str.search(sections[s]);
731
 
            if (i != -1)
732
 
            {
733
 
                rv[currentSection] = str.substr(0, i);
734
 
                currentSection = 0;
735
 
                str = RegExp.rightContext;
736
 
                str = str.replace(/^(\n|\r|\r\n)/, "");
737
 
            }
738
 
        }
739
 
        else
740
 
        {
741
 
            rv[currentSection] = str;
742
 
            str = "";
743
 
            break;
744
 
        }
745
 
    }
746
 
 
747
 
    return rv;
748
 
}
749
 
 
750
 
function replaceStrings (str, obj)
751
 
{
752
 
    if (!str)
753
 
        return str;
754
 
    for (var p in obj)
755
 
        str = str.replace(RegExp(p, "g"), obj[p]);
756
 
    return str;
757
 
}
758
 
 
759
 
function stringTrim (s)
760
 
{
761
 
    if (!s)
762
 
        return "";
763
 
    s = s.replace (/^\s+/, "");
764
 
    return s.replace (/\s+$/, "");
765
 
}
766
 
 
767
 
function formatDateOffset (seconds, format)
768
 
{
769
 
    seconds = Math.floor(seconds);
770
 
    var minutes = Math.floor(seconds / 60);
771
 
    seconds = seconds % 60;
772
 
    var hours   = Math.floor(minutes / 60);
773
 
    minutes = minutes % 60;
774
 
    var days    = Math.floor(hours / 24);
775
 
    hours = hours % 24;
776
 
 
777
 
    if (!format)
778
 
    {
779
 
        var ary = new Array();
780
 
        if (days > 0)
781
 
            ary.push (days + " days");
782
 
        if (hours > 0)
783
 
            ary.push (hours + " hours");
784
 
        if (minutes > 0)
785
 
            ary.push (minutes + " minutes");
786
 
        if (seconds > 0)
787
 
            ary.push (seconds + " seconds");
788
 
 
789
 
        format = ary.join(", ");
790
 
    }
791
 
    else
792
 
    {
793
 
        format = format.replace ("%d", days);
794
 
        format = format.replace ("%h", hours);
795
 
        format = format.replace ("%m", minutes);
796
 
        format = format.replace ("%s", seconds);
797
 
    }
798
 
    
799
 
    return format;
800
 
}
801
 
 
802
 
function arrayHasElementAt(ary, i)
803
 
{
804
 
    return typeof ary[i] != "undefined";
805
 
}
806
 
 
807
 
function arraySpeak (ary, single, plural)
808
 
{
809
 
    var rv = "";
810
 
    
811
 
    switch (ary.length)
812
 
    {
813
 
        case 0:
814
 
            break;
815
 
            
816
 
        case 1:
817
 
            rv = ary[0];
818
 
            if (single)
819
 
                rv += " " + single;            
820
 
            break;
821
 
 
822
 
        case 2:
823
 
            rv = ary[0] + " and " + ary[1];
824
 
            if (plural)
825
 
                rv += " " + plural;
826
 
            break;
827
 
 
828
 
        default:
829
 
            for (var i = 0; i < ary.length - 1; ++i)
830
 
                rv += ary[i] + ", ";
831
 
            rv += "and " + ary[ary.length - 1];
832
 
            if (plural)
833
 
                rv += " " + plural;
834
 
            break;
835
 
    }
836
 
 
837
 
    return rv;
838
 
    
839
 
}
840
 
 
841
 
function arrayOrFlag (ary, i, flag)
842
 
{
843
 
    if (i in ary)
844
 
        ary[i] |= flag;
845
 
    else
846
 
        ary[i] = flag;
847
 
}
848
 
 
849
 
function arrayAndFlag (ary, i, flag)
850
 
{
851
 
    if (i in ary)
852
 
        ary[i] &= flag;
853
 
    else
854
 
        ary[i] = 0;
855
 
}
856
 
 
857
 
function arrayContains (ary, elem)
858
 
{
859
 
    return (arrayIndexOf (ary, elem) != -1);
860
 
}
861
 
 
862
 
function arrayIndexOf (ary, elem, start)
863
 
{
864
 
    if (!ary)
865
 
        return -1;
866
 
 
867
 
    var len = ary.length;
868
 
 
869
 
    if (typeof start == "undefined")
870
 
        start = 0;
871
 
 
872
 
    for (var i = start; i < len; ++i)
873
 
    {
874
 
        if (ary[i] == elem)
875
 
            return i;
876
 
    }
877
 
 
878
 
    return -1;
879
 
}
880
 
    
881
 
function arrayInsertAt (ary, i, o)
882
 
{
883
 
 
884
 
    ary.splice (i, 0, o);
885
 
 
886
 
}
887
 
 
888
 
function arrayRemoveAt (ary, i)
889
 
{
890
 
 
891
 
    ary.splice (i, 1);
892
 
 
893
 
}
894
 
 
895
 
function getRandomElement (ary)
896
 
{
897
 
    var i = Math.floor (Math.random() * ary.length)
898
 
        if (i == ary.length) i = 0;
899
 
 
900
 
    return ary[i];
901
 
 
902
 
}
903
 
 
904
 
function zeroPad (num, decimals)
905
 
{
906
 
    var rv = String(num);
907
 
    var len = rv.length;
908
 
    for (var i = 0; i < decimals - len; ++i)
909
 
        rv = "0" + rv;
910
 
    
911
 
    return rv;
912
 
}
913
 
 
914
 
function leftPadString (str, num, ch)
915
 
{
916
 
    var rv = "";
917
 
    var len = rv.length;
918
 
    for (var i = len; i < num; ++i)
919
 
        rv += ch;
920
 
    
921
 
    return rv + str;
922
 
}
923
 
    
924
 
function roundTo (num, prec)
925
 
{
926
 
    return Math.round(num * Math.pow (10, prec)) / Math.pow (10, prec);
927
 
}
928
 
 
929
 
function randomRange (min, max)
930
 
{
931
 
 
932
 
    if (typeof min == "undefined")
933
 
        min = 0;
934
 
 
935
 
    if (typeof max == "undefined")
936
 
        max = 1;
937
 
 
938
 
    var rv = (Math.floor(Math.round((Math.random() * (max - min)) + min )));
939
 
    
940
 
    return rv;
941
 
 
942
 
}
943
 
 
944
 
function getStackTrace ()
945
 
{
946
 
 
947
 
    if (!jsenv.HAS_XPCOM)
948
 
        return "No stack trace available.";
949
 
 
950
 
    var frame = Components.stack.caller;
951
 
    var str = "<top>";
952
 
 
953
 
    while (frame)
954
 
    {
955
 
        var name = frame.name ? frame.name : "[anonymous]";
956
 
        str += "\n" + name + "@" + frame.lineNumber;
957
 
        frame = frame.caller;
958
 
    }
959
 
 
960
 
    return str;
961
 
    
962
 
}
963
 
 
964
 
function getInterfaces (cls)
965
 
{
966
 
    if (!jsenv.HAS_XPCOM)
967
 
        return null;
968
 
 
969
 
    var rv = new Object();
970
 
    var e;
971
 
 
972
 
    for (var i in Components.interfaces)
973
 
    {
974
 
        try
975
 
        {
976
 
            var ifc = Components.interfaces[i];
977
 
            cls.QueryInterface(ifc);
978
 
            rv[i] = ifc;
979
 
        }
980
 
        catch (e)
981
 
        {
982
 
            /* nada */
983
 
        }
984
 
    }
985
 
 
986
 
    return rv;
987
 
    
988
 
}
989
 
 
990
 
function makeExpression (items)
991
 
{
992
 
    function escapeItem (item, first)
993
 
    {
994
 
        // Numbers.
995
 
        if (item.match(/^[0-9]+$/i))
996
 
            return "[" + item + "]";
997
 
        // Words/other items that don't need quoting.
998
 
        if (item.match(/^[a-z_][a-z0-9_]+$/i))
999
 
            return (!first ? "." : "") + item;
1000
 
        // Quote everything else.
1001
 
        return "[" + item.quote() + "]";
1002
 
    };
1003
 
    
1004
 
    var expression = escapeItem(items[0], true);
1005
 
    
1006
 
    for (var i = 1; i < items.length; i++)
1007
 
        expression += escapeItem(items[i], false);
1008
 
    
1009
 
    return expression;
1010
 
}
 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 * ***** BEGIN LICENSE BLOCK *****
 
4
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
5
 *
 
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/
 
10
 *
 
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
 
14
 * License.
 
15
 *
 
16
 * The Original Code is mozilla.org code.
 
17
 *
 
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.
 
22
 *
 
23
 * Contributor(s):
 
24
 *   Robert Ginda, rginda@ndcico.com, original author
 
25
 *
 
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.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
var dumpln;
 
41
var dd;
 
42
 
 
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;
 
48
 
 
49
var utils = new Object();
 
50
 
 
51
if (typeof document == "undefined") /* in xpcshell */
 
52
{
 
53
    dumpln = print;
 
54
}
 
55
else
 
56
{
 
57
    if (typeof dump == "function")
 
58
        dumpln = function (str) {dump (str + "\n");}
 
59
    else if (jsenv.HAS_RHINO)
 
60
    {
 
61
        dumpln = function (str) {
 
62
                     var out = java.lang.System.out;
 
63
                     out.println(str); out.flush();
 
64
                 }
 
65
    }
 
66
    else
 
67
        dumpln = function () {} /* no suitable function */
 
68
}
 
69
 
 
70
if (DEBUG) {
 
71
    var _dd_pfx = "";
 
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") {
 
81
                 dumpln (str);
 
82
             } else if (str[str.length - 1] == "{") {
 
83
                 ++_dd_currentDepth;
 
84
                 if (_dd_currentDepth >= _dd_disableDepth)
 
85
                     return;
 
86
                 if (str.indexOf("OFF") == 0)
 
87
                     _dd_disableDepth = _dd_currentDepth;
 
88
                 _dd_timeStack.push (new Date());
 
89
                 if (_dd_lastDumpWasOpen)
 
90
                     dump("\n");
 
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)
 
96
                     return;
 
97
                 _dd_disableDepth = Number.MAX_VALUE;
 
98
                 var sufx = (new Date() - _dd_timeStack.pop()) / 1000 + " sec";
 
99
                 _dd_currentIndent = 
 
100
                     _dd_currentIndent.substr (0, _dd_currentIndent.length -
 
101
                                               _dd_indentLength);
 
102
                 if (_dd_lastDumpWasOpen)
 
103
                     dumpln (str + " " + sufx);
 
104
                 else
 
105
                     dumpln (_dd_pfx + _dd_currentIndent + str + " " + sufx);
 
106
                 _dd_lastDumpWasOpen = false;
 
107
             } else {
 
108
                 if (_dd_currentDepth >= _dd_disableDepth)
 
109
                     return;
 
110
                 if (_dd_lastDumpWasOpen)
 
111
                     dump ("\n");
 
112
                 dumpln (_dd_pfx + _dd_currentIndent + str);
 
113
                 _dd_lastDumpWasOpen = false;
 
114
             }    
 
115
         }
 
116
} else {
 
117
    dd = function (){};
 
118
}
 
119
 
 
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");
 
128
 
 
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.
 
133
 *
 
134
 * + parent (object)
 
135
 * + users (object)
 
136
 * | + jsbot (object)
 
137
 * | + mrjs (object)
 
138
 * | + nakkezzzz (object)
 
139
 * | *
 
140
 * + bans (object)
 
141
 * | *
 
142
 * + topic (string) 'ircclient.js:59: nothing is not defined'
 
143
 * + getUsersLength (function) 9 lines
 
144
 * *
 
145
 */
 
146
function dumpObjectTree (o, recurse, compress, level)
 
147
{
 
148
    var s = "";
 
149
    var pfx = "";
 
150
 
 
151
    if (typeof recurse == "undefined")
 
152
        recurse = 0;
 
153
    if (typeof level == "undefined")
 
154
        level = 0;
 
155
    if (typeof compress == "undefined")
 
156
        compress = true;
 
157
    
 
158
    for (var i = 0; i < level; i++)
 
159
        pfx += (compress) ? "| " : "|  ";
 
160
 
 
161
    var tee = (compress) ? "+ " : "+- ";
 
162
 
 
163
    for (i in o)
 
164
    {
 
165
        var t;
 
166
        try
 
167
        {
 
168
            t = typeof o[i];
 
169
        
 
170
            switch (t)
 
171
            {
 
172
                case "function":
 
173
                    var sfunc = String(o[i]).split("\n");
 
174
                    if (sfunc[2] == "    [native code]")
 
175
                        sfunc = "[native code]";
 
176
                    else
 
177
                        sfunc = sfunc.length + " lines";
 
178
                    s += pfx + tee + i + " (function) " + sfunc + "\n";
 
179
                    break;
 
180
                    
 
181
                case "object":
 
182
                    s += pfx + tee + i + " (object) " + o[i] + "\n";
 
183
                    if (!compress)
 
184
                        s += pfx + "|\n";
 
185
                    if ((i != "parent") && (recurse))
 
186
                        s += dumpObjectTree (o[i], recurse - 1,
 
187
                                             compress, level + 1);
 
188
                    break;
 
189
                    
 
190
                case "string":
 
191
                    if (o[i].length > 200)
 
192
                        s += pfx + tee + i + " (" + t + ") " + 
 
193
                            o[i].length + " chars\n";
 
194
                    else
 
195
                        s += pfx + tee + i + " (" + t + ") '" + o[i] + "'\n";
 
196
                    break;
 
197
                    
 
198
                default:
 
199
                    s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";
 
200
            }
 
201
        }
 
202
        catch (ex)
 
203
        {
 
204
            s += pfx + tee + i + " (exception) " + ex + "\n";
 
205
        }
 
206
 
 
207
        if (!compress)
 
208
            s += pfx + "|\n";
 
209
 
 
210
    }
 
211
 
 
212
    s += pfx + "*\n";
 
213
    
 
214
    return s;
 
215
    
 
216
}
 
217
 
 
218
function safeHTML(str)
 
219
{
 
220
    function replaceChars(ch)
 
221
    {
 
222
        switch (ch)
 
223
        {
 
224
            case "<":
 
225
                return "&lt;";
 
226
            
 
227
            case ">":
 
228
                return "&gt;";
 
229
                    
 
230
            case "&":
 
231
                return "&amp;";
 
232
        }
 
233
 
 
234
        return "?";
 
235
    };
 
236
        
 
237
    return String(str).replace(/[<>&]/g, replaceChars);
 
238
}
 
239
 
 
240
function alert(msg, parent, title)
 
241
{
 
242
    var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
 
243
    var nsIPromptService = Components.interfaces.nsIPromptService;
 
244
    var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
 
245
    if (!parent)
 
246
        parent = window;
 
247
    if (!title)
 
248
        title = MSG_ALERT;
 
249
    ps.alert (parent, title, msg);
 
250
}
 
251
 
 
252
function confirm(msg, parent, title)
 
253
{
 
254
    var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
 
255
    var nsIPromptService = Components.interfaces.nsIPromptService;
 
256
    var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
 
257
    if (!parent)
 
258
        parent = window;
 
259
    if (!title)
 
260
        title = MSG_CONFIRM;
 
261
    return ps.confirm (parent, title, msg);
 
262
}
 
263
 
 
264
function prompt(msg, initial, parent, title)
 
265
{
 
266
    var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
 
267
    var nsIPromptService = Components.interfaces.nsIPromptService;
 
268
    var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
 
269
    if (!parent)
 
270
        parent = window;
 
271
    if (!title)
 
272
        title = MSG_PROMPT;
 
273
    rv = { value: initial };
 
274
 
 
275
    if (!ps.prompt (parent, title, msg, rv, null, {value: null}))
 
276
        return null;
 
277
 
 
278
    return rv.value
 
279
}
 
280
 
 
281
function getChildById (element, id)
 
282
{
 
283
    var nl = element.getElementsByAttribute("id", id);
 
284
    return nl.item(0);
 
285
}
 
286
 
 
287
function openTopWin (url)
 
288
{
 
289
    var window = getWindowByType ("navigator:browser");
 
290
    if (window)
 
291
    {
 
292
        var base = getBaseWindowFromWindow (window);
 
293
        if (base.enabled)
 
294
        {
 
295
            window.focus();
 
296
            window._content.location.href = url;
 
297
            return window;
 
298
        }
 
299
    }
 
300
 
 
301
    return openDialog (getBrowserURL(), "_blank", "chrome,all,dialog=no", url);
 
302
}
 
303
    
 
304
function getWindowByType (windowType)
 
305
{
 
306
    const MEDIATOR_CONTRACTID =
 
307
        "@mozilla.org/appshell/window-mediator;1";
 
308
    const nsIWindowMediator  = Components.interfaces.nsIWindowMediator;
 
309
 
 
310
    var windowManager =
 
311
        Components.classes[MEDIATOR_CONTRACTID].getService(nsIWindowMediator);
 
312
 
 
313
    return windowManager.getMostRecentWindow(windowType);
 
314
}
 
315
 
 
316
function htmlVA (attribs, href, contents)
 
317
{
 
318
    if (!attribs)
 
319
        attribs = {"class": "venkman-link", target: "_content"};
 
320
    else if (attribs["class"])
 
321
        attribs["class"] += " venkman-link";
 
322
    else
 
323
        attribs["class"] = "venkman-link";
 
324
 
 
325
    if (typeof contents == "undefined")
 
326
    {
 
327
        contents = htmlSpan();
 
328
        insertHyphenatedWord (href, contents);
 
329
    }
 
330
    
 
331
    return htmlA (attribs, href, contents);
 
332
}
 
333
 
 
334
function insertHyphenatedWord (longWord, containerTag)
 
335
{
 
336
    var wordParts = splitLongWord (longWord, MAX_WORD_LEN);
 
337
    containerTag.appendChild (htmlWBR());
 
338
    for (var i = 0; i < wordParts.length; ++i)
 
339
    {
 
340
        containerTag.appendChild (document.createTextNode (wordParts[i]));
 
341
        if (i != wordParts.length)
 
342
            containerTag.appendChild (htmlWBR());
 
343
    }
 
344
}
 
345
 
 
346
function insertLink (matchText, containerTag)
 
347
{
 
348
    var href;
 
349
    var linkText;
 
350
    
 
351
    var trailing;
 
352
    ary = matchText.match(/([.,]+)$/);
 
353
    if (ary)
 
354
    {
 
355
        linkText = RegExp.leftContext;
 
356
        trailing = ary[1];
 
357
    }
 
358
    else
 
359
    {
 
360
        linkText = matchText;
 
361
    }
 
362
 
 
363
    var ary = linkText.match (/^(\w[\w-]+):/);
 
364
    if (ary)
 
365
    {
 
366
        if (!("schemes" in utils))
 
367
        {
 
368
            var pfx = "@mozilla.org/network/protocol;1?name=";
 
369
            var len = pfx.length
 
370
 
 
371
            utils.schemes = new Object();
 
372
            for (var c in Components.classes)
 
373
            {
 
374
                if (c.indexOf(pfx) == 0)
 
375
                    utils.schemes[c.substr(len)] = true;
 
376
            }
 
377
        }
 
378
        
 
379
        if (!(ary[1] in utils.schemes))
 
380
        {
 
381
            insertHyphenatedWord(matchText, containerTag);
 
382
            return;
 
383
        }
 
384
 
 
385
        href = linkText;
 
386
    }
 
387
    else
 
388
    {
 
389
        href = "http://" + linkText;
 
390
    }
 
391
 
 
392
    var anchor = htmlVA (null, href, "");
 
393
    insertHyphenatedWord (linkText, anchor);
 
394
    containerTag.appendChild (anchor);
 
395
    if (trailing)
 
396
        insertHyphenatedWord (trailing, containerTag);
 
397
    
 
398
}
 
399
 
 
400
function insertQuote (matchText, containerTag, msgtype)
 
401
{
 
402
    if (msgtype[0] == "#")
 
403
    {
 
404
        containerTag.appendChild(document.createTextNode(matchText));
 
405
        return;
 
406
    }
 
407
    
 
408
    if (matchText == "``")
 
409
        containerTag.appendChild(document.createTextNode("\u201c"));
 
410
    else
 
411
        containerTag.appendChild(document.createTextNode("\u201d"));
 
412
}
 
413
 
 
414
/* length should be an even number >= 6 */
 
415
function abbreviateWord (str, length)
 
416
{
 
417
    if (str.length <= length || length < 6)
 
418
        return str;
 
419
 
 
420
    var left = str.substr (0, (length / 2) - 1);
 
421
    var right = str.substr (str.length - (length / 2) + 1);
 
422
 
 
423
    return left + "..." + right;
 
424
}
 
425
 
 
426
function toBool (val)
 
427
{
 
428
    switch (typeof val)
 
429
    {
 
430
        case "boolean":
 
431
            return val;
 
432
    
 
433
        case "number":
 
434
            return val != 0;
 
435
            
 
436
        default:
 
437
            val = String(val);
 
438
            /* fall through */
 
439
 
 
440
        case "string":
 
441
            return (val.search(/true|on|yes|1/i) != -1);
 
442
    }
 
443
 
 
444
    return null;
 
445
}
 
446
 
 
447
/* some of the drag and drop code has an annoying appetite for exceptions.  any
 
448
 * exception raised during a dnd operation causes the operation to fail silently.
 
449
 * passing the function through one of these adapters lets you use "return
 
450
 * false on planned failure" symantics, and dumps any exceptions caught
 
451
 * to the console. */
 
452
function Prophylactic (parentObj, fun)
 
453
{
 
454
    function adapter ()
 
455
    {
 
456
        var ex;
 
457
        var rv = false;
 
458
        
 
459
        try
 
460
        {
 
461
            rv = fun.apply (parentObj, arguments);
 
462
        }
 
463
        catch (ex)
 
464
        {
 
465
            dd ("Prophylactic caught an exception:\n" +
 
466
                dumpObjectTree(ex));
 
467
        }
 
468
        
 
469
        if (!rv)
 
470
            throw "goodger";
 
471
 
 
472
        return rv;
 
473
    };
 
474
    
 
475
    return adapter;
 
476
}
 
477
 
 
478
function argumentsAsArray (args, start)
 
479
{
 
480
    if (typeof start == "undefined")
 
481
        start = 0;
 
482
 
 
483
    if (start >= args.length)
 
484
        return null;
 
485
    
 
486
    var rv = new Array();
 
487
    
 
488
    for (var i = start; i < args.length; ++i)
 
489
        rv.push(args[i]);
 
490
    
 
491
    return rv;
 
492
}
 
493
 
 
494
function splitLongWord (str, pos)
 
495
{
 
496
    if (str.length <= pos)
 
497
        return [str];
 
498
 
 
499
    var ary = new Array();
 
500
    var right = str;
 
501
    
 
502
    while (right.length > pos)
 
503
    {
 
504
        /* search for a nice place to break the word, fuzzfactor of +/-5, 
 
505
         * centered around |pos| */
 
506
        var splitPos =
 
507
            right.substring(pos - 5, pos + 5).search(/[^A-Za-z0-9]/);
 
508
 
 
509
        splitPos = (splitPos != -1) ? pos - 4 + splitPos : pos;
 
510
        ary.push(right.substr (0, splitPos));
 
511
        right = right.substr (splitPos);
 
512
    }
 
513
 
 
514
    ary.push (right);
 
515
 
 
516
    return ary;
 
517
}
 
518
 
 
519
function wrapText (str, width)
 
520
{
 
521
    var rv = "";
 
522
    while (str.length > width)
 
523
    {
 
524
        rv += str.substr(0, width) + "\n";
 
525
        str = str.substr(width);
 
526
    }
 
527
    return rv + str;
 
528
}
 
529
 
 
530
function wordCap (str)
 
531
{
 
532
    if (!str)
 
533
        return str;
 
534
    
 
535
    return str[0].toUpperCase() + str.substr(1);
 
536
}
 
537
 
 
538
/*
 
539
 * Clones an existing object (Only the enumerable properties
 
540
 * of course.) use as a function..
 
541
 * var c = Clone (obj);
 
542
 * or a constructor...
 
543
 * var c = new Clone (obj);
 
544
 */
 
545
function Clone (obj)
 
546
{
 
547
    var robj = new Object();
 
548
 
 
549
    for (var p in obj)
 
550
        robj[p] = obj[p];
 
551
 
 
552
    return robj;
 
553
    
 
554
}
 
555
 
 
556
function getXULWindowFromWindow (win)
 
557
{
 
558
    var rv;
 
559
    //dd ("getXULWindowFromWindow: before: getInterface is " + win.getInterface);
 
560
    try
 
561
    {
 
562
        var requestor = win.QueryInterface(nsIInterfaceRequestor);
 
563
        var nav = requestor.getInterface(nsIWebNavigation);
 
564
        var dsti = nav.QueryInterface(nsIDocShellTreeItem);
 
565
        var owner = dsti.treeOwner;
 
566
        requestor = owner.QueryInterface(nsIInterfaceRequestor);
 
567
        rv = requestor.getInterface(nsIXULWindow);
 
568
    }
 
569
    catch (ex)
 
570
    {
 
571
        rv = null;
 
572
        //dd ("not a nsIXULWindow: " + formatException(ex));
 
573
        /* ignore no-interface exception */
 
574
    }
 
575
 
 
576
    //dd ("getXULWindowFromWindow: after: getInterface is " + win.getInterface);
 
577
    return rv;
 
578
}
 
579
 
 
580
function getBaseWindowFromWindow (win)
 
581
{
 
582
    var rv;
 
583
    //dd ("getBaseWindowFromWindow: before: getInterface is " + win.getInterface);
 
584
    try
 
585
    {
 
586
        var requestor = win.QueryInterface(nsIInterfaceRequestor);
 
587
        var nav = requestor.getInterface(nsIWebNavigation);
 
588
        var dsti = nav.QueryInterface(nsIDocShellTreeItem);
 
589
        var owner = dsti.treeOwner;
 
590
        requestor = owner.QueryInterface(nsIInterfaceRequestor);
 
591
        rv = requestor.getInterface(nsIBaseWindow);
 
592
    }
 
593
    catch (ex)
 
594
    {
 
595
        rv = null;
 
596
        //dd ("not a nsIXULWindow: " + formatException(ex));
 
597
        /* ignore no-interface exception */
 
598
    }
 
599
 
 
600
    //dd ("getBaseWindowFromWindow: after: getInterface is " + win.getInterface);
 
601
    return rv;
 
602
}
 
603
 
 
604
function getSpecialDirectory(name)
 
605
{
 
606
    if (!("directoryService" in utils))
 
607
    {
 
608
        const DS_CTR = "@mozilla.org/file/directory_service;1";
 
609
        const nsIProperties = Components.interfaces.nsIProperties;
 
610
    
 
611
        utils.directoryService =
 
612
            Components.classes[DS_CTR].getService(nsIProperties);
 
613
    }
 
614
    
 
615
    return utils.directoryService.get(name, Components.interfaces.nsIFile);
 
616
}
 
617
 
 
618
function getPathFromURL (url)
 
619
{
 
620
    var ary = url.match(/^(.*\/)([^\/?#]+)(\?|#|$)/);
 
621
    if (ary)
 
622
        return ary[1];
 
623
 
 
624
    return url;
 
625
}
 
626
 
 
627
function getFileFromPath (path)
 
628
{
 
629
    var ary = path.match(/\/([^\/?#;]+)(\?|#|$|;)/);
 
630
    if (ary)
 
631
        return ary[1];
 
632
 
 
633
    return path;
 
634
}
 
635
 
 
636
function getURLSpecFromFile (file)
 
637
{
 
638
    if (!file)
 
639
        return null;
 
640
 
 
641
    const IOS_CTRID = "@mozilla.org/network/io-service;1";
 
642
    const LOCALFILE_CTRID = "@mozilla.org/file/local;1";
 
643
 
 
644
    const nsIIOService = Components.interfaces.nsIIOService;
 
645
    const nsILocalFile = Components.interfaces.nsILocalFile;
 
646
    
 
647
    if (typeof file == "string")
 
648
    {
 
649
        var fileObj =
 
650
            Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
 
651
        fileObj.initWithPath(file);
 
652
        file = fileObj;
 
653
    }
 
654
    
 
655
    var service = Components.classes[IOS_CTRID].getService(nsIIOService);
 
656
    /* In sept 2002, bug 166792 moved this method to the nsIFileProtocolHandler
 
657
     * interface, but we need to support older versions too. */
 
658
    if ("getURLSpecFromFile" in service)
 
659
        return service.getURLSpecFromFile(file);
 
660
 
 
661
    var nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
 
662
    var fileHandler = service.getProtocolHandler("file");
 
663
    fileHandler = fileHandler.QueryInterface(nsIFileProtocolHandler);
 
664
    return fileHandler.getURLSpecFromFile(file);
 
665
}
 
666
 
 
667
function getCommonPfx (list)
 
668
{
 
669
    var pfx = list[0];
 
670
    var l = list.length;
 
671
    
 
672
    for (var i = 1; i < l; i++)
 
673
    {
 
674
        for (var c = 0; c < pfx.length; c++)
 
675
            if (pfx[c] != list[i][c])
 
676
                pfx = pfx.substr (0, c);
 
677
    }
 
678
 
 
679
    return pfx;
 
680
 
 
681
}
 
682
 
 
683
function renameProperty (obj, oldname, newname)
 
684
{
 
685
 
 
686
    if (oldname == newname)
 
687
        return;
 
688
    
 
689
    obj[newname] = obj[oldname];
 
690
    delete obj[oldname];
 
691
    
 
692
}
 
693
 
 
694
function newObject(contractID, iface)
 
695
{
 
696
    if (!jsenv.HAS_XPCOM)
 
697
        return null;
 
698
 
 
699
    var obj = Components.classes[contractID].createInstance();
 
700
    var rv;
 
701
 
 
702
    switch (typeof iface)
 
703
    {
 
704
        case "string":
 
705
            rv = obj.QueryInterface(Components.interfaces[iface]);
 
706
            break;
 
707
 
 
708
        case "object":
 
709
            rv = obj.QueryInterface[iface];
 
710
            break;
 
711
 
 
712
        default:
 
713
            rv = null;
 
714
            break;
 
715
    }
 
716
 
 
717
    return rv;
 
718
    
 
719
}
 
720
 
 
721
function keys (o)
 
722
{
 
723
    var rv = new Array();
 
724
    
 
725
    for (var p in o)
 
726
        rv.push(p);
 
727
 
 
728
    return rv;
 
729
    
 
730
}
 
731
 
 
732
function parseSections (str, sections)
 
733
{
 
734
    var rv = new Object();
 
735
    var currentSection;
 
736
 
 
737
    for (var s in sections)
 
738
    {
 
739
        if (!currentSection)
 
740
            currentSection = s;
 
741
        
 
742
        if (sections[s])
 
743
        {
 
744
            var i = str.search(sections[s]);
 
745
            if (i != -1)
 
746
            {
 
747
                rv[currentSection] = str.substr(0, i);
 
748
                currentSection = 0;
 
749
                str = RegExp.rightContext;
 
750
                str = str.replace(/^(\n|\r|\r\n)/, "");
 
751
            }
 
752
        }
 
753
        else
 
754
        {
 
755
            rv[currentSection] = str;
 
756
            str = "";
 
757
            break;
 
758
        }
 
759
    }
 
760
 
 
761
    return rv;
 
762
}
 
763
 
 
764
function replaceStrings (str, obj)
 
765
{
 
766
    if (!str)
 
767
        return str;
 
768
    for (var p in obj)
 
769
        str = str.replace(RegExp(p, "g"), obj[p]);
 
770
    return str;
 
771
}
 
772
 
 
773
function stringTrim (s)
 
774
{
 
775
    if (!s)
 
776
        return "";
 
777
    s = s.replace (/^\s+/, "");
 
778
    return s.replace (/\s+$/, "");
 
779
}
 
780
 
 
781
function formatDateOffset (seconds, format)
 
782
{
 
783
    seconds = Math.floor(seconds);
 
784
    var minutes = Math.floor(seconds / 60);
 
785
    seconds = seconds % 60;
 
786
    var hours   = Math.floor(minutes / 60);
 
787
    minutes = minutes % 60;
 
788
    var days    = Math.floor(hours / 24);
 
789
    hours = hours % 24;
 
790
 
 
791
    if (!format)
 
792
    {
 
793
        var ary = new Array();
 
794
        if (days > 0)
 
795
            ary.push (days + " days");
 
796
        if (hours > 0)
 
797
            ary.push (hours + " hours");
 
798
        if (minutes > 0)
 
799
            ary.push (minutes + " minutes");
 
800
        if (seconds > 0)
 
801
            ary.push (seconds + " seconds");
 
802
 
 
803
        format = ary.join(", ");
 
804
    }
 
805
    else
 
806
    {
 
807
        format = format.replace ("%d", days);
 
808
        format = format.replace ("%h", hours);
 
809
        format = format.replace ("%m", minutes);
 
810
        format = format.replace ("%s", seconds);
 
811
    }
 
812
    
 
813
    return format;
 
814
}
 
815
 
 
816
function arrayHasElementAt(ary, i)
 
817
{
 
818
    return typeof ary[i] != "undefined";
 
819
}
 
820
 
 
821
function arraySpeak (ary, single, plural)
 
822
{
 
823
    var rv = "";
 
824
    
 
825
    switch (ary.length)
 
826
    {
 
827
        case 0:
 
828
            break;
 
829
            
 
830
        case 1:
 
831
            rv = ary[0];
 
832
            if (single)
 
833
                rv += " " + single;            
 
834
            break;
 
835
 
 
836
        case 2:
 
837
            rv = ary[0] + " and " + ary[1];
 
838
            if (plural)
 
839
                rv += " " + plural;
 
840
            break;
 
841
 
 
842
        default:
 
843
            for (var i = 0; i < ary.length - 1; ++i)
 
844
                rv += ary[i] + ", ";
 
845
            rv += "and " + ary[ary.length - 1];
 
846
            if (plural)
 
847
                rv += " " + plural;
 
848
            break;
 
849
    }
 
850
 
 
851
    return rv;
 
852
    
 
853
}
 
854
 
 
855
function arrayOrFlag (ary, i, flag)
 
856
{
 
857
    if (i in ary)
 
858
        ary[i] |= flag;
 
859
    else
 
860
        ary[i] = flag;
 
861
}
 
862
 
 
863
function arrayAndFlag (ary, i, flag)
 
864
{
 
865
    if (i in ary)
 
866
        ary[i] &= flag;
 
867
    else
 
868
        ary[i] = 0;
 
869
}
 
870
 
 
871
function arrayContains (ary, elem)
 
872
{
 
873
    return (arrayIndexOf (ary, elem) != -1);
 
874
}
 
875
 
 
876
function arrayIndexOf (ary, elem, start)
 
877
{
 
878
    if (!ary)
 
879
        return -1;
 
880
 
 
881
    var len = ary.length;
 
882
 
 
883
    if (typeof start == "undefined")
 
884
        start = 0;
 
885
 
 
886
    for (var i = start; i < len; ++i)
 
887
    {
 
888
        if (ary[i] == elem)
 
889
            return i;
 
890
    }
 
891
 
 
892
    return -1;
 
893
}
 
894
    
 
895
function arrayInsertAt (ary, i, o)
 
896
{
 
897
 
 
898
    ary.splice (i, 0, o);
 
899
 
 
900
}
 
901
 
 
902
function arrayRemoveAt (ary, i)
 
903
{
 
904
 
 
905
    ary.splice (i, 1);
 
906
 
 
907
}
 
908
 
 
909
function getRandomElement (ary)
 
910
{
 
911
    var i = Math.floor (Math.random() * ary.length)
 
912
        if (i == ary.length) i = 0;
 
913
 
 
914
    return ary[i];
 
915
 
 
916
}
 
917
 
 
918
function zeroPad (num, decimals)
 
919
{
 
920
    var rv = String(num);
 
921
    var len = rv.length;
 
922
    for (var i = 0; i < decimals - len; ++i)
 
923
        rv = "0" + rv;
 
924
    
 
925
    return rv;
 
926
}
 
927
 
 
928
function leftPadString (str, num, ch)
 
929
{
 
930
    var rv = "";
 
931
    var len = rv.length;
 
932
    for (var i = len; i < num; ++i)
 
933
        rv += ch;
 
934
    
 
935
    return rv + str;
 
936
}
 
937
    
 
938
function roundTo (num, prec)
 
939
{
 
940
    return Math.round(num * Math.pow (10, prec)) / Math.pow (10, prec);
 
941
}
 
942
 
 
943
function randomRange (min, max)
 
944
{
 
945
 
 
946
    if (typeof min == "undefined")
 
947
        min = 0;
 
948
 
 
949
    if (typeof max == "undefined")
 
950
        max = 1;
 
951
 
 
952
    var rv = (Math.floor(Math.round((Math.random() * (max - min)) + min )));
 
953
    
 
954
    return rv;
 
955
 
 
956
}
 
957
 
 
958
function getStackTrace ()
 
959
{
 
960
 
 
961
    if (!jsenv.HAS_XPCOM)
 
962
        return "No stack trace available.";
 
963
 
 
964
    var frame = Components.stack.caller;
 
965
    var str = "<top>";
 
966
 
 
967
    while (frame)
 
968
    {
 
969
        var name = frame.name ? frame.name : "[anonymous]";
 
970
        str += "\n" + name + "@" + frame.lineNumber;
 
971
        frame = frame.caller;
 
972
    }
 
973
 
 
974
    return str;
 
975
    
 
976
}
 
977
 
 
978
function getInterfaces (cls)
 
979
{
 
980
    if (!jsenv.HAS_XPCOM)
 
981
        return null;
 
982
 
 
983
    var rv = new Object();
 
984
    var e;
 
985
 
 
986
    for (var i in Components.interfaces)
 
987
    {
 
988
        try
 
989
        {
 
990
            var ifc = Components.interfaces[i];
 
991
            cls.QueryInterface(ifc);
 
992
            rv[i] = ifc;
 
993
        }
 
994
        catch (e)
 
995
        {
 
996
            /* nada */
 
997
        }
 
998
    }
 
999
 
 
1000
    return rv;
 
1001
    
 
1002
}
 
1003
 
 
1004
function makeExpression (items)
 
1005
{
 
1006
    function escapeItem (item, first)
 
1007
    {
 
1008
        // Numbers.
 
1009
        if (item.match(/^[0-9]+$/i))
 
1010
            return "[" + item + "]";
 
1011
        // Words/other items that don't need quoting.
 
1012
        if (item.match(/^[a-z_][a-z0-9_]+$/i))
 
1013
            return (!first ? "." : "") + item;
 
1014
        // Quote everything else.
 
1015
        return "[" + item.quote() + "]";
 
1016
    };
 
1017
    
 
1018
    var expression = escapeItem(items[0], true);
 
1019
    
 
1020
    for (var i = 1; i < items.length; i++)
 
1021
        expression += escapeItem(items[i], false);
 
1022
    
 
1023
    return expression;
 
1024
}