~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/composer/base/content/editorUtilities.js

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
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/
 
8
 *
 
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.
 
13
 *
 
14
 * The Original Code is Mozilla Communicator client code.
 
15
 *
 
16
 * The Initial Developer of the Original Code is
 
17
 * Netscape Communications Corporation.
 
18
 * Portions created by the Initial Developer are Copyright (C) 1998
 
19
 * the Initial Developer. All Rights Reserved.
 
20
 *
 
21
 * Contributor(s):
 
22
 *   Pete Collins
 
23
 *   Brian King
 
24
 *   Daniel Glazman (glazman@disruptive-innovations.com), on behalf of Linspire Inc.
 
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 NPL, 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 NPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
/**** NAMESPACES ****/
 
41
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
42
const NVU_NS = "http://disruptive-innovations.com/zoo/nvu";
 
43
 
 
44
// Each editor window must include this file
 
45
// Variables  shared by all dialogs:
 
46
 
 
47
// Object to attach commonly-used widgets (all dialogs should use this)
 
48
var gDialog = {};
 
49
 
 
50
// Bummer! Can't get at enums from nsIDocumentEncoder.h
 
51
// http://lxr.mozilla.org/seamonkey/source/content/base/public/nsIDocumentEncoder.h#111
 
52
var gStringBundle;
 
53
var gIOService;
 
54
var gPrefsService;
 
55
var gPrefsBranch;
 
56
var gFilePickerDirectory;
 
57
 
 
58
var gOS = "";
 
59
const gWin = "Win";
 
60
const gUNIX = "UNIX";
 
61
const gMac = "Mac";
 
62
 
 
63
const kWebComposerWindowID = "editorWindow";
 
64
const kMailComposerWindowID = "msgcomposeWindow";
 
65
 
 
66
var gIsHTMLEditor;
 
67
/************* Message dialogs ***************/
 
68
 
 
69
function AlertWithTitle(title, message, parentWindow)
 
70
{
 
71
  if (!parentWindow)
 
72
    parentWindow = window;
 
73
 
 
74
  var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
 
75
  promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
 
76
 
 
77
  if (promptService)
 
78
  {
 
79
    if (!title)
 
80
      title = GetString("Alert");
 
81
 
 
82
    // "window" is the calling dialog window
 
83
    promptService.alert(parentWindow, title, message);
 
84
  }
 
85
}
 
86
 
 
87
// Optional: Caller may supply text to substitue for "Ok" and/or "Cancel"
 
88
function ConfirmWithTitle(title, message, okButtonText, cancelButtonText)
 
89
{
 
90
  var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
 
91
  promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
 
92
 
 
93
  if (promptService)
 
94
  {
 
95
    var okFlag = okButtonText ? promptService.BUTTON_TITLE_IS_STRING : promptService.BUTTON_TITLE_OK;
 
96
    var cancelFlag = cancelButtonText ? promptService.BUTTON_TITLE_IS_STRING : promptService.BUTTON_TITLE_CANCEL;
 
97
 
 
98
    return promptService.confirmEx(window, title, message,
 
99
                            (okFlag * promptService.BUTTON_POS_0) +
 
100
                            (cancelFlag * promptService.BUTTON_POS_1),
 
101
                            okButtonText, cancelButtonText, null, null, {value:0}) == 0;
 
102
  }
 
103
  return false;
 
104
}
 
105
 
 
106
/************* String Utilities ***************/
 
107
 
 
108
function GetString(name)
 
109
{
 
110
  if (!gStringBundle)
 
111
  {
 
112
    try {
 
113
      var strBundleService =
 
114
          Components.classes["@mozilla.org/intl/stringbundle;1"].getService(); 
 
115
      strBundleService = 
 
116
          strBundleService.QueryInterface(Components.interfaces.nsIStringBundleService);
 
117
 
 
118
      gStringBundle = strBundleService.createBundle("chrome://editor/locale/editor.properties"); 
 
119
 
 
120
    } catch (ex) {}
 
121
  }
 
122
  if (gStringBundle)
 
123
  {
 
124
    try {
 
125
      return gStringBundle.GetStringFromName(name);
 
126
    } catch (e) {}
 
127
  }
 
128
  return null;
 
129
}
 
130
 
 
131
function TrimStringLeft(string)
 
132
{
 
133
  if(!string) return "";
 
134
  return string.replace(/^\s+/, "");
 
135
}
 
136
 
 
137
function TrimStringRight(string)
 
138
{
 
139
  if (!string) return "";
 
140
  return string.replace(/\s+$/, '');
 
141
}
 
142
 
 
143
// Remove whitespace from both ends of a string
 
144
function TrimString(string)
 
145
{
 
146
  if (!string) return "";
 
147
  return string.replace(/(^\s+)|(\s+$)/g, '')
 
148
}
 
149
 
 
150
function IsWhitespace(string)
 
151
{
 
152
  return /^\s/.test(string);
 
153
}
 
154
 
 
155
function TruncateStringAtWordEnd(string, maxLength, addEllipses)
 
156
{
 
157
  // Return empty if string is null, undefined, or the empty string
 
158
  if (!string)
 
159
    return "";
 
160
 
 
161
  // We assume they probably don't want whitespace at the beginning
 
162
  string = string.replace(/^\s+/, '');
 
163
  if (string.length <= maxLength)
 
164
    return string;
 
165
 
 
166
  // We need to truncate the string to maxLength or fewer chars
 
167
  if (addEllipses)
 
168
    maxLength -= 3;
 
169
  string = string.replace(RegExp("(.{0," + maxLength + "})\\s.*"), "$1")
 
170
 
 
171
  if (string.length > maxLength)
 
172
    string = string.slice(0, maxLength);
 
173
 
 
174
  if (addEllipses)
 
175
    string += "...";
 
176
  return string;
 
177
}
 
178
 
 
179
// Replace all whitespace characters with supplied character
 
180
// E.g.: Use charReplace = " ", to "unwrap" the string by removing line-end chars
 
181
//       Use charReplace = "_" when you don't want spaces (like in a URL)
 
182
function ReplaceWhitespace(string, charReplace)
 
183
{
 
184
  return string.replace(/(^\s+)|(\s+$)/g,'').replace(/\s+/g,charReplace)
 
185
}
 
186
 
 
187
// Replace whitespace with "_" and allow only HTML CDATA
 
188
//   characters: "a"-"z","A"-"Z","0"-"9", "_", ":", "-", ".",
 
189
//   and characters above ASCII 127
 
190
function ConvertToCDATAString(string)
 
191
{
 
192
  return string.replace(/\s+/g,"_").replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g,'');
 
193
}
 
194
 
 
195
function GetSelectionAsText()
 
196
{
 
197
  try {
 
198
    return GetCurrentEditor().outputToString("text/plain", 1); // OutputSelectionOnly
 
199
  } catch (e) {}
 
200
 
 
201
  return "";
 
202
}
 
203
 
 
204
 
 
205
/************* Get Current Editor and associated interfaces or info ***************/
 
206
const nsIPlaintextEditor = Components.interfaces.nsIPlaintextEditor;
 
207
const nsIHTMLEditor = Components.interfaces.nsIHTMLEditor;
 
208
const nsITableEditor = Components.interfaces.nsITableEditor;
 
209
const nsIEditorStyleSheets = Components.interfaces.nsIEditorStyleSheets;
 
210
const nsIEditingSession = Components.interfaces.nsIEditingSession;
 
211
 
 
212
function GetCurrentEditor()
 
213
{
 
214
  // Get the active editor from the <editor> tag
 
215
  // XXX This will probably change if we support > 1 editor in main Composer window
 
216
  //      (e.g. a plaintext editor for HTMLSource)
 
217
 
 
218
  // For dialogs: Search up parent chain to find top window with editor
 
219
  var editor;
 
220
  try {
 
221
    var editorElement = GetCurrentEditorElement();
 
222
    editor = editorElement.getEditor(editorElement.contentWindow);
 
223
 
 
224
    // Do QIs now so editor users won't have to figure out which interface to use
 
225
    // Using "instanceof" does the QI for us.
 
226
    editor instanceof Components.interfaces.nsIPlaintextEditor;
 
227
    editor instanceof Components.interfaces.nsIHTMLEditor;
 
228
  } catch (e) { dump (e)+"\n"; }
 
229
 
 
230
  return editor;
 
231
}
 
232
 
 
233
function GetCurrentTableEditor()
 
234
{
 
235
  var editor = GetCurrentEditor();
 
236
  return (editor && (editor instanceof nsITableEditor)) ? editor : null;
 
237
}
 
238
 
 
239
function GetCurrentEditorElement()
 
240
{
 
241
  var tmpWindow = window;
 
242
  
 
243
  do {
 
244
    // Get the <editor> element(s)
 
245
    var tabeditor = tmpWindow.document.getElementById("tabeditor");
 
246
 
 
247
    // This will change if we support > 1 editor element
 
248
    if (tabeditor )
 
249
      return tabeditor.getCurrentEditorElement() ;
 
250
 
 
251
    tmpWindow = tmpWindow.opener;
 
252
  } 
 
253
  while (tmpWindow);
 
254
 
 
255
  return null;
 
256
}
 
257
 
 
258
function GetCurrentEditingSession()
 
259
{
 
260
  try {
 
261
    return GetCurrentEditorElement().editingSession;
 
262
  } catch (e) { dump (e)+"\n"; }
 
263
 
 
264
  return null;
 
265
}
 
266
 
 
267
function GetCurrentCommandManager()
 
268
{
 
269
  try {
 
270
    return GetCurrentEditorElement().commandManager;
 
271
  } catch (e) { dump (e)+"\n"; }
 
272
 
 
273
  return null;
 
274
}
 
275
 
 
276
function GetCurrentEditorType()
 
277
{
 
278
  try {
 
279
    return GetCurrentEditorElement().editortype;
 
280
  } catch (e) { dump (e)+"\n"; }
 
281
 
 
282
  return "";
 
283
}
 
284
 
 
285
function IsHTMLEditor()
 
286
{
 
287
  // We don't have an editorElement, just return false
 
288
  if (!GetCurrentEditorElement())
 
289
    return false;
 
290
 
 
291
  var editortype = GetCurrentEditorType();
 
292
  switch (editortype)
 
293
  {
 
294
      case "html":
 
295
      case "htmlmail":
 
296
        return true;
 
297
 
 
298
      case "text":
 
299
      case "textmail":
 
300
        return false
 
301
 
 
302
      default:
 
303
        dump("INVALID EDITOR TYPE: " + editortype + "\n");
 
304
        break;
 
305
  }
 
306
  return false;
 
307
}
 
308
 
 
309
function PageIsEmptyAndUntouched()
 
310
{
 
311
  return IsDocumentEmpty() && !IsDocumentModified() && !IsHTMLSourceChanged();
 
312
}
 
313
 
 
314
function IsInHTMLSourceMode()
 
315
{
 
316
  return (gEditorDisplayMode == kDisplayModeSource);
 
317
}
 
318
 
 
319
// are we editing HTML (i.e. neither in HTML source mode, nor editing a text file)
 
320
function IsEditingRenderedHTML()
 
321
{
 
322
  return IsHTMLEditor() && !IsInHTMLSourceMode();
 
323
}
 
324
 
 
325
function IsWebComposer()
 
326
{
 
327
  return document.documentElement.id == "editorWindow";
 
328
}
 
329
 
 
330
function IsDocumentEditable()
 
331
{
 
332
  try {
 
333
    return GetCurrentEditor().isDocumentEditable;
 
334
  } catch (e) {}
 
335
  return false;
 
336
}
 
337
 
 
338
function IsDocumentEmpty()
 
339
{
 
340
  try {
 
341
    return GetCurrentEditor().documentIsEmpty;
 
342
  } catch (e) {}
 
343
  return false;
 
344
}
 
345
 
 
346
function IsDocumentModified()
 
347
{
 
348
  try {
 
349
    return GetCurrentEditor().documentModified;
 
350
  } catch (e) {}
 
351
  return false;
 
352
}
 
353
 
 
354
function IsHTMLSourceChanged()
 
355
{
 
356
  return gSourceTextEditor.documentModified;
 
357
}
 
358
 
 
359
function newCommandParams()
 
360
{
 
361
  try {
 
362
    return Components.classes["@mozilla.org/embedcomp/command-params;1"].createInstance(Components.interfaces.nsICommandParams);
 
363
  }
 
364
  catch(e) { dump("error thrown in newCommandParams: "+e+"\n"); }
 
365
  return null;
 
366
}
 
367
 
 
368
/************* General editing command utilities ***************/
 
369
 
 
370
function GetDocumentTitle()
 
371
{
 
372
  try {
 
373
    return GetCurrentEditor().document.title;
 
374
    // return new XPCNativeWrapper(GetCurrentEditor().document, "title").title;
 
375
  } catch (e) {}
 
376
 
 
377
  return "";
 
378
}
 
379
 
 
380
function SetDocumentTitle(title)
 
381
{
 
382
 
 
383
  try {
 
384
    GetCurrentEditor().setDocumentTitle(title);
 
385
 
 
386
    // Update window title (doesn't work if called from a dialog)
 
387
    if ("UpdateWindowTitle" in window)
 
388
      window.UpdateWindowTitle();
 
389
  } catch (e) {}
 
390
}
 
391
 
 
392
var gAtomService;
 
393
function GetAtomService()
 
394
{
 
395
  gAtomService = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
 
396
}
 
397
 
 
398
function EditorGetTextProperty(property, attribute, value, firstHas, anyHas, allHas)
 
399
{
 
400
  try {
 
401
    if (!gAtomService) GetAtomService();
 
402
    var propAtom = gAtomService.getAtom(property);
 
403
 
 
404
    GetCurrentEditor().getInlineProperty(propAtom, attribute, value,
 
405
                                         firstHas, anyHas, allHas);
 
406
  }
 
407
  catch(e) {}
 
408
}
 
409
 
 
410
function EditorSetTextProperty(property, attribute, value)
 
411
{
 
412
  try {
 
413
    if (!gAtomService) GetAtomService();
 
414
    var propAtom = gAtomService.getAtom(property);
 
415
 
 
416
    GetCurrentEditor().setInlineProperty(propAtom, attribute, value);
 
417
    if ("gContentWindow" in window)
 
418
      window.gContentWindow.focus();
 
419
  }
 
420
  catch(e) {}
 
421
}
 
422
 
 
423
function EditorRemoveTextProperty(property, attribute)
 
424
{
 
425
  try {
 
426
    if (!gAtomService) GetAtomService();
 
427
    var propAtom = gAtomService.getAtom(property);
 
428
 
 
429
    GetCurrentEditor().removeInlineProperty(propAtom, attribute);
 
430
    if ("gContentWindow" in window)
 
431
      window.gContentWindow.focus();
 
432
  }
 
433
  catch(e) {}
 
434
}
 
435
 
 
436
/************* Element enbabling/disabling ***************/
 
437
 
 
438
// this function takes an elementID and a flag
 
439
// if the element can be found by ID, then it is either enabled (by removing "disabled" attr)
 
440
// or disabled (setAttribute) as specified in the "doEnable" parameter
 
441
function SetElementEnabledById(elementID, doEnable)
 
442
{
 
443
  SetElementEnabled(document.getElementById(elementID), doEnable);
 
444
}
 
445
 
 
446
function SetElementEnabled(element, doEnable)
 
447
{
 
448
  if ( element )
 
449
  {
 
450
    // <Kaze> looks like the first try was the best one...
 
451
    //~ /* if ( doEnable )
 
452
      //~ element.removeAttribute("disabled");
 
453
    //~ else
 
454
      //~ element.setAttribute("disabled", "true"); */
 
455
    //~ element.disabled = !doEnable;
 
456
    if ( doEnable )
 
457
      element.removeAttribute("disabled");
 
458
    else
 
459
      element.setAttribute("disabled", "true");
 
460
    // </Kaze>
 
461
  }
 
462
  else
 
463
  {
 
464
    dump("Element  not found in SetElementEnabled\n");
 
465
  }
 
466
}
 
467
 
 
468
function SetElementVisible(element, isVisible)
 
469
{
 
470
  if ( element )
 
471
  {
 
472
    if ( isVisible)
 
473
      element.style.visibility = "visible";
 
474
    else
 
475
      element.style.visibility = "hidden";
 
476
  }
 
477
  else
 
478
  {
 
479
    dump("Element  not found in SetElementEnabled\n");
 
480
  }
 
481
}
 
482
 
 
483
/************* Services / Prefs ***************/
 
484
 
 
485
function GetIOService()
 
486
{
 
487
  if (gIOService)
 
488
    return gIOService;
 
489
 
 
490
  gIOService = Components.classes["@mozilla.org/network/io-service;1"]
 
491
               .getService(Components.interfaces.nsIIOService);
 
492
 
 
493
  return gIOService;
 
494
}
 
495
 
 
496
function GetFileProtocolHandler()
 
497
{
 
498
  var ios = GetIOService();
 
499
  var handler = ios.getProtocolHandler("file");
 
500
  return handler.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
 
501
}
 
502
 
 
503
function GetPrefsService()
 
504
{
 
505
  if (gPrefsService)
 
506
    return gPrefsService;
 
507
 
 
508
  try {
 
509
    gPrefsService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
 
510
  }
 
511
  catch(ex) {
 
512
    dump("failed to get prefs service!\n");
 
513
  }
 
514
 
 
515
  return gPrefsService;
 
516
}
 
517
 
 
518
function GetPrefs()
 
519
{
 
520
  if (gPrefsBranch)
 
521
    return gPrefsBranch;
 
522
 
 
523
  try {
 
524
    var prefService = GetPrefsService();
 
525
    if (prefService)
 
526
      gPrefsBranch = prefService.getBranch(null);
 
527
 
 
528
    if (gPrefsBranch)
 
529
      return gPrefsBranch;
 
530
    else
 
531
      dump("failed to get root prefs!\n");
 
532
  }
 
533
  catch(ex) {
 
534
    dump("failed to get root prefs!\n");
 
535
  }
 
536
  return null;
 
537
}
 
538
 
 
539
function GetStringPref(name)
 
540
{
 
541
  try {
 
542
    return GetPrefs().getComplexValue(name, Components.interfaces.nsISupportsString).data;
 
543
  } catch (e) {}
 
544
  return "";
 
545
}
 
546
 
 
547
function GetBoolPref(name)
 
548
{
 
549
  try {
 
550
    return GetPrefs().getBoolPref(name);
 
551
  } catch (e) {}
 
552
  return false;
 
553
}
 
554
 
 
555
function SetUnicharPref(aPrefName, aPrefValue)
 
556
{
 
557
  var prefs = GetPrefs();
 
558
  if (prefs)
 
559
  {
 
560
    try {
 
561
      var str = Components.classes["@mozilla.org/supports-string;1"]
 
562
                          .createInstance(Components.interfaces.nsISupportsString);
 
563
      str.data = aPrefValue;
 
564
      prefs.setComplexValue(aPrefName, Components.interfaces.nsISupportsString, str);
 
565
    }
 
566
    catch(e) {}
 
567
  }
 
568
}
 
569
 
 
570
function GetUnicharPref(aPrefName, aDefVal)
 
571
{
 
572
  var prefs = GetPrefs();
 
573
  if (prefs)
 
574
  {
 
575
    try {
 
576
      return prefs.getComplexValue(aPrefName, Components.interfaces.nsISupportsString).data;
 
577
    }
 
578
    catch(e) {}
 
579
  }
 
580
  return "";
 
581
}
 
582
 
 
583
// Set initial directory for a filepicker from URLs saved in prefs
 
584
function SetFilePickerDirectory(filePicker, fileType)
 
585
{
 
586
  if (filePicker)
 
587
  {
 
588
    try {
 
589
      var prefBranch = GetPrefs();
 
590
      if (prefBranch)
 
591
      {
 
592
        // Save current directory so we can reset it in SaveFilePickerDirectory
 
593
        gFilePickerDirectory = filePicker.displayDirectory;
 
594
 
 
595
        var location = prefBranch.getComplexValue("editor.lastFileLocation."+fileType, Components.interfaces.nsILocalFile);
 
596
        if (location)
 
597
          filePicker.displayDirectory = location;
 
598
      }
 
599
    }
 
600
    catch(e) {}
 
601
  }
 
602
}
 
603
 
 
604
// Save the directory of the selected file to prefs
 
605
function SaveFilePickerDirectory(filePicker, fileType)
 
606
{
 
607
  if (filePicker && filePicker.file)
 
608
  {
 
609
    try {
 
610
      var prefBranch = GetPrefs();
 
611
 
 
612
      var fileDir;
 
613
      if (filePicker.file.parent)
 
614
        fileDir = filePicker.file.parent.QueryInterface(Components.interfaces.nsILocalFile);
 
615
 
 
616
      if (prefBranch)
 
617
       prefBranch.setComplexValue("editor.lastFileLocation."+fileType, Components.interfaces.nsILocalFile, fileDir);
 
618
    
 
619
      var prefsService = GetPrefsService();
 
620
        prefsService.savePrefFile(null);
 
621
    } catch (e) {}
 
622
  }
 
623
 
 
624
  // Restore the directory used before SetFilePickerDirectory was called;
 
625
  // This reduces interference with Browser and other module directory defaults
 
626
  if (gFilePickerDirectory)
 
627
    filePicker.displayDirectory = gFilePickerDirectory;
 
628
 
 
629
  gFilePickerDirectory = null;
 
630
}
 
631
 
 
632
function GetDefaultBrowserColors()
 
633
{
 
634
  var prefs = GetPrefs();
 
635
  var colors = { TextColor:0, BackgroundColor:0, LinkColor:0, ActiveLinkColor:0 , VisitedLinkColor:0 };
 
636
  var useSysColors = false;
 
637
  try { useSysColors = prefs.getBoolPref("browser.display.use_system_colors"); } catch (e) {}
 
638
 
 
639
  if (!useSysColors)
 
640
  {
 
641
    try { colors.TextColor = prefs.getCharPref("browser.display.foreground_color"); } catch (e) {}
 
642
 
 
643
    try { colors.BackgroundColor = prefs.getCharPref("browser.display.background_color"); } catch (e) {}
 
644
  }
 
645
  // Use OS colors for text and background if explicitly asked or pref is not set
 
646
  if (!colors.TextColor)
 
647
    colors.TextColor = "windowtext";
 
648
 
 
649
  if (!colors.BackgroundColor)
 
650
    colors.BackgroundColor = "window";
 
651
 
 
652
  colors.LinkColor = prefs.getCharPref("browser.anchor_color");
 
653
  colors.ActiveLinkColor = prefs.getCharPref("browser.active_color");
 
654
  colors.VisitedLinkColor = prefs.getCharPref("browser.visited_color");
 
655
 
 
656
  return colors;
 
657
}
 
658
 
 
659
/************* URL handling ***************/
 
660
 
 
661
function TextIsURI(selectedText)
 
662
{
 
663
  return selectedText && /^http:\/\/|^https:\/\/|^file:\/\/|\
 
664
    ^ftp:\/\/|^about:|^mailto:|^news:|^snews:|^telnet:|^ldap:|\
 
665
    ^ldaps:|^gopher:|^finger:|^javascript:/i.test(selectedText);
 
666
}
 
667
 
 
668
function IsUrlAboutBlank(urlString)
 
669
{
 
670
  return (urlString == "about:blank" || urlString == "about:xblank" ||
 
671
          urlString == "about:strictblank" || urlString == "about:xstrictblank");
 
672
}
 
673
 
 
674
//~ function MakeRelativeUrl(url)
 
675
function MakeRelativeUrl(url, base) { // modified
 
676
// Added: optional "base" param (default = document URL)
 
677
 
 
678
  var inputUrl = TrimString(url);
 
679
  if (!inputUrl)
 
680
    return inputUrl;
 
681
 
 
682
  // Get the filespec relative to current document's location
 
683
  // NOTE: Can't do this if file isn't saved yet!
 
684
  var docUrl = base ? base : GetDocumentBaseUrl(); // Kaze
 
685
  var docScheme = GetScheme(docUrl);
 
686
 
 
687
  // Can't relativize if no doc scheme (page hasn't been saved)
 
688
  if (!docScheme)
 
689
    return inputUrl;
 
690
 
 
691
  var urlScheme = GetScheme(inputUrl);
 
692
 
 
693
  // Do nothing if not the same scheme or url is already relativized
 
694
  if (docScheme != urlScheme)
 
695
    return inputUrl;
 
696
 
 
697
  var IOService = GetIOService();
 
698
  if (!IOService)
 
699
    return inputUrl;
 
700
 
 
701
  // Host must be the same
 
702
  var docHost = GetHost(docUrl);
 
703
  var urlHost = GetHost(inputUrl);
 
704
  if (docHost != urlHost)
 
705
    return inputUrl;
 
706
 
 
707
 
 
708
  // Get just the file path part of the urls
 
709
  // XXX Should we use GetCurrentEditor().documentCharacterSet for 2nd param ?
 
710
  var docPath = IOService.newURI(docUrl, GetCurrentEditor().documentCharacterSet, null).path;
 
711
  var urlPath = IOService.newURI(inputUrl, GetCurrentEditor().documentCharacterSet, null).path;
 
712
 
 
713
  // We only return "urlPath", so we can convert
 
714
  //  the entire docPath for case-insensitive comparisons
 
715
  var os = GetOS();
 
716
  var doCaseInsensitive = (docScheme == "file" && os == gWin);
 
717
  if (doCaseInsensitive)
 
718
    docPath = docPath.toLowerCase();
 
719
 
 
720
  // Get document filename before we start chopping up the docPath
 
721
  var docFilename = GetFilename(docPath);
 
722
 
 
723
  // Both url and doc paths now begin with "/"
 
724
  // Look for shared dirs starting after that
 
725
  urlPath = urlPath.slice(1);
 
726
  docPath = docPath.slice(1);
 
727
 
 
728
  var firstDirTest = true;
 
729
  var nextDocSlash = 0;
 
730
  var done = false;
 
731
 
 
732
  // Remove all matching subdirs common to both doc and input urls
 
733
  do {
 
734
    nextDocSlash = docPath.indexOf("\/");
 
735
    var nextUrlSlash = urlPath.indexOf("\/");
 
736
 
 
737
    if (nextUrlSlash == -1)
 
738
    {
 
739
      // We're done matching and all dirs in url
 
740
      // what's left is the filename
 
741
      done = true;
 
742
 
 
743
      // Remove filename for named anchors in the same file
 
744
      if (nextDocSlash == -1 && docFilename)
 
745
      {
 
746
        var anchorIndex = urlPath.indexOf("#");
 
747
        if (anchorIndex > 0)
 
748
        {
 
749
          var urlFilename = doCaseInsensitive ? urlPath.toLowerCase() : urlPath;
 
750
 
 
751
          if (urlFilename.indexOf(docFilename) == 0)
 
752
            urlPath = urlPath.slice(anchorIndex);
 
753
        }
 
754
      }
 
755
    }
 
756
    else if (nextDocSlash >= 0)
 
757
    {
 
758
      // Test for matching subdir
 
759
      var docDir = docPath.slice(0, nextDocSlash);
 
760
      var urlDir = urlPath.slice(0, nextUrlSlash);
 
761
      if (doCaseInsensitive)
 
762
        urlDir = urlDir.toLowerCase();
 
763
 
 
764
      if (urlDir == docDir)
 
765
      {
 
766
 
 
767
        // Remove matching dir+"/" from each path
 
768
        //  and continue to next dir
 
769
        docPath = docPath.slice(nextDocSlash+1);
 
770
        urlPath = urlPath.slice(nextUrlSlash+1);
 
771
      }
 
772
      else
 
773
      {
 
774
        // No match, we're done
 
775
        done = true;
 
776
 
 
777
        // Be sure we are on the same local drive or volume
 
778
        //   (the first "dir" in the path) because we can't
 
779
        //   relativize to different drives/volumes.
 
780
        // UNIX doesn't have volumes, so we must not do this else
 
781
        //  the first directory will be misinterpreted as a volume name
 
782
        if (firstDirTest && docScheme == "file" && os != gUNIX)
 
783
          return inputUrl;
 
784
      }
 
785
    }
 
786
    else  // No more doc dirs left, we're done
 
787
      done = true;
 
788
 
 
789
    firstDirTest = false;
 
790
  }
 
791
  while (!done);
 
792
 
 
793
  // Add "../" for each dir left in docPath
 
794
  while (nextDocSlash > 0)
 
795
  {
 
796
    urlPath = "../" + urlPath;
 
797
    nextDocSlash = docPath.indexOf("\/", nextDocSlash+1);
 
798
  }
 
799
  return urlPath;
 
800
}
 
801
 
 
802
function MakeAbsoluteUrl(url)
 
803
{
 
804
  var resultUrl = TrimString(url);
 
805
  if (!resultUrl)
 
806
    return resultUrl;
 
807
 
 
808
  // Check if URL is already absolute, i.e., it has a scheme
 
809
  var urlScheme = GetScheme(resultUrl);
 
810
 
 
811
  if (urlScheme)
 
812
    return resultUrl;
 
813
 
 
814
  var docUrl = GetDocumentBaseUrl();
 
815
  var docScheme = GetScheme(docUrl);
 
816
 
 
817
  // Can't relativize if no doc scheme (page hasn't been saved)
 
818
  if (!docScheme)
 
819
    return resultUrl;
 
820
 
 
821
  var  IOService = GetIOService();
 
822
  if (!IOService)
 
823
    return resultUrl;
 
824
  
 
825
  // Make a URI object to use its "resolve" method
 
826
  var absoluteUrl = resultUrl;
 
827
  var docUri = IOService.newURI(docUrl, GetCurrentEditor().documentCharacterSet, null);
 
828
 
 
829
  try {
 
830
    absoluteUrl = docUri.resolve(resultUrl);
 
831
    // This is deprecated and buggy! 
 
832
    // If used, we must make it a path for the parent directory (remove filename)
 
833
    //absoluteUrl = IOService.resolveRelativePath(resultUrl, docUrl);
 
834
  } catch (e) {}
 
835
 
 
836
  return absoluteUrl;
 
837
}
 
838
 
 
839
// Get the HREF of the page's <base> tag or the document location
 
840
// returns empty string if no base href and document hasn't been saved yet
 
841
function GetDocumentBaseUrl()
 
842
{
 
843
  try {
 
844
    var docUrl;
 
845
 
 
846
    // if document supplies a <base> tag, use that URL instead 
 
847
    var baseList = GetCurrentEditor().document.getElementsByTagName("base");
 
848
    if (baseList)
 
849
    {
 
850
      var base = baseList.item(0);
 
851
      if (base)
 
852
        docUrl = base.getAttribute("href");
 
853
    }
 
854
    if (!docUrl)
 
855
      docUrl = GetDocumentUrl();
 
856
 
 
857
    if (!IsUrlAboutBlank(docUrl))
 
858
      return docUrl;
 
859
  } catch (e) {}
 
860
  return "";
 
861
}
 
862
 
 
863
function GetDocumentUrl()
 
864
{
 
865
  try {
 
866
    var aDOMHTMLDoc = GetCurrentEditor().document.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
 
867
    return aDOMHTMLDoc.URL;
 
868
  }
 
869
  catch (e) {}
 
870
  return "";
 
871
}
 
872
 
 
873
// Extract the scheme (e.g., 'file', 'http') from a URL string
 
874
function GetScheme(urlspec)
 
875
{
 
876
  var resultUrl = TrimString(urlspec);
 
877
  // Unsaved document URL has no acceptable scheme yet
 
878
  if (!resultUrl || IsUrlAboutBlank(resultUrl))
 
879
    return "";
 
880
 
 
881
  var IOService = GetIOService();
 
882
  if (!IOService)
 
883
    return "";
 
884
 
 
885
  var scheme = "";
 
886
  try {
 
887
    // This fails if there's no scheme
 
888
    scheme = IOService.extractScheme(resultUrl);
 
889
  } catch (e) {}
 
890
 
 
891
  return scheme ? scheme.toLowerCase() : "";
 
892
}
 
893
 
 
894
function GetHost(urlspec)
 
895
{
 
896
  if (!urlspec)
 
897
    return "";
 
898
 
 
899
  var IOService = GetIOService();
 
900
  if (!IOService)
 
901
    return "";
 
902
 
 
903
  var host = "";
 
904
  try {
 
905
    host = IOService.newURI(urlspec, null, null).host;
 
906
   } catch (e) {}
 
907
 
 
908
  return host;
 
909
}
 
910
 
 
911
function GetUsername(urlspec)
 
912
{
 
913
  if (!urlspec)
 
914
    return "";
 
915
 
 
916
  var IOService = GetIOService();
 
917
  if (!IOService)
 
918
    return "";
 
919
 
 
920
  var username = "";
 
921
  try {
 
922
    username = IOService.newURI(urlspec, null, null).username;
 
923
  } catch (e) {}
 
924
 
 
925
  return username;
 
926
}
 
927
 
 
928
function GetFilename(urlspec)
 
929
{
 
930
  if (!urlspec || IsUrlAboutBlank(urlspec))
 
931
    return "";
 
932
 
 
933
  var IOService = GetIOService();
 
934
  if (!IOService)
 
935
    return "";
 
936
 
 
937
  var filename;
 
938
 
 
939
  try {
 
940
    var uri = IOService.newURI(urlspec, null, null);
 
941
    if (uri)
 
942
    {
 
943
      var url = uri.QueryInterface(Components.interfaces.nsIURL);
 
944
      if (url)
 
945
        filename = url.fileName;
 
946
    }
 
947
  } catch (e) {}
 
948
 
 
949
  return filename ? filename : "";
 
950
}
 
951
 
 
952
// Return the url without username and password
 
953
// Optional output objects return extracted username and password strings
 
954
// This uses just string routines via nsIIOServices
 
955
function StripUsernamePassword(urlspec, usernameObj, passwordObj)
 
956
{
 
957
  urlspec = TrimString(urlspec);
 
958
  if (!urlspec || IsUrlAboutBlank(urlspec))
 
959
    return urlspec;
 
960
 
 
961
  if (usernameObj)
 
962
    usernameObj.value = "";
 
963
  if (passwordObj)
 
964
    passwordObj.value = "";
 
965
 
 
966
  // "@" must exist else we will never detect username or password
 
967
  var atIndex = urlspec.indexOf("@");
 
968
  if (atIndex > 0)
 
969
  {
 
970
    try {
 
971
      var IOService = GetIOService();
 
972
      if (!IOService)
 
973
        return urlspec;
 
974
 
 
975
      var uri = IOService.newURI(urlspec, null, null);
 
976
      var username = uri.username;
 
977
      var password = uri.password;
 
978
 
 
979
      if (usernameObj && username)
 
980
        usernameObj.value = username;
 
981
      if (passwordObj && password)
 
982
        passwordObj.value = password;
 
983
      if (username)
 
984
      {
 
985
        var usernameStart = urlspec.indexOf(username);
 
986
        if (usernameStart != -1)
 
987
          return urlspec.slice(0, usernameStart) + urlspec.slice(atIndex+1);
 
988
      }
 
989
    } catch (e) {}
 
990
  }
 
991
  return urlspec;
 
992
}
 
993
 
 
994
function StripPassword(urlspec, passwordObj)
 
995
{
 
996
  urlspec = TrimString(urlspec);
 
997
  if (!urlspec || IsUrlAboutBlank(urlspec))
 
998
    return urlspec;
 
999
 
 
1000
  if (passwordObj)
 
1001
    passwordObj.value = "";
 
1002
 
 
1003
  // "@" must exist else we will never detect password
 
1004
  var atIndex = urlspec.indexOf("@");
 
1005
  if (atIndex > 0)
 
1006
  {
 
1007
    try {
 
1008
      var IOService = GetIOService();
 
1009
      if (!IOService)
 
1010
        return urlspec;
 
1011
 
 
1012
      var password = IOService.newURI(urlspec, null, null).password;
 
1013
 
 
1014
      if (passwordObj && password)
 
1015
        passwordObj.value = password;
 
1016
      if (password)
 
1017
      {
 
1018
        // Find last ":" before "@"
 
1019
        var colon = urlspec.lastIndexOf(":", atIndex);
 
1020
        if (colon != -1)
 
1021
        {
 
1022
          // Include the "@"
 
1023
          return urlspec.slice(0, colon) + urlspec.slice(atIndex);
 
1024
        }
 
1025
      }
 
1026
    } catch (e) {}
 
1027
  }
 
1028
  return urlspec;
 
1029
}
 
1030
 
 
1031
// Version to use when you have an nsIURI object
 
1032
function StripUsernamePasswordFromURI(uri)
 
1033
{
 
1034
  var urlspec = "";
 
1035
  if (uri)
 
1036
  {
 
1037
    try {
 
1038
      urlspec = uri.spec;
 
1039
      var userPass = uri.userPass;
 
1040
      if (userPass)
 
1041
      {
 
1042
        start = urlspec.indexOf(userPass);
 
1043
        urlspec = urlspec.slice(0, start) + urlspec.slice(start+userPass.length+1);
 
1044
      }
 
1045
    } catch (e) {}    
 
1046
  }
 
1047
  return urlspec;
 
1048
}
 
1049
 
 
1050
function InsertUsernameIntoUrl(urlspec, username)
 
1051
{
 
1052
  if (!urlspec || !username)
 
1053
    return urlspec;
 
1054
 
 
1055
  try {
 
1056
    var ioService = GetIOService();
 
1057
    var URI = ioService.newURI(urlspec, GetCurrentEditor().documentCharacterSet, null);
 
1058
    URI.username = username;
 
1059
    return URI.spec;
 
1060
  } catch (e) {}
 
1061
 
 
1062
  return urlspec;
 
1063
}
 
1064
 
 
1065
function GetOS()
 
1066
{
 
1067
  if (gOS)
 
1068
    return gOS;
 
1069
 
 
1070
  var platform = navigator.platform.toLowerCase();
 
1071
 
 
1072
  if (platform.indexOf("win") != -1)
 
1073
    gOS = gWin;
 
1074
  else if (platform.indexOf("mac") != -1)
 
1075
    gOS = gMac;
 
1076
  else if (platform.indexOf("unix") != -1 || platform.indexOf("linux") != -1 || platform.indexOf("sun") != -1)
 
1077
    gOS = gUNIX;
 
1078
  else
 
1079
    gOS = "";
 
1080
  // Add other tests?
 
1081
 
 
1082
  return gOS;
 
1083
}
 
1084
 
 
1085
function ConvertRGBColorIntoHEXColor(color)
 
1086
{
 
1087
  if ( /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.test(color) ) {
 
1088
    var r = Number(RegExp.$1).toString(16);
 
1089
    if (r.length == 1) r = "0"+r;
 
1090
    var g = Number(RegExp.$2).toString(16);
 
1091
    if (g.length == 1) g = "0"+g;
 
1092
    var b = Number(RegExp.$3).toString(16);
 
1093
    if (b.length == 1) b = "0"+b;
 
1094
    return "#"+r+g+b;
 
1095
  }
 
1096
  else
 
1097
  {
 
1098
    return color;
 
1099
  }
 
1100
}
 
1101
 
 
1102
/************* CSS ***************/
 
1103
 
 
1104
function GetHTMLOrCSSStyleValue(element, attrName, cssPropertyName)
 
1105
{
 
1106
  var prefs = GetPrefs();
 
1107
  var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
 
1108
  var value;
 
1109
  if (IsCSSPrefChecked && IsHTMLEditor())
 
1110
    value = element.style.getPropertyValue(cssPropertyName);
 
1111
 
 
1112
  if (!value)
 
1113
    value = element.getAttribute(attrName);
 
1114
 
 
1115
  if (!value)
 
1116
    return "";
 
1117
 
 
1118
  return value;
 
1119
}
 
1120
 
 
1121
/************* Miscellaneous ***************/
 
1122
// Clone simple JS objects
 
1123
function Clone(obj) 
 
1124
 
1125
  var clone = {};
 
1126
  for (var i in obj)
 
1127
  {
 
1128
    if( typeof obj[i] == 'object')
 
1129
      clone[i] = Clone(obj[i]);
 
1130
    else
 
1131
      clone[i] = obj[i];
 
1132
  }
 
1133
  return clone;
 
1134
}
 
1135
 
 
1136
function GetCSSPropertyValueForSelection(property)
 
1137
{
 
1138
  var value = "";
 
1139
  try {
 
1140
    if (!gAtomService) GetAtomService();
 
1141
    var propAtom = gAtomService.getAtom(property);
 
1142
 
 
1143
    value = GetCurrentEditor().getCSSPropertyValueForSelection(propAtom);
 
1144
  }
 
1145
  catch(e) {}
 
1146
 
 
1147
  return value;
 
1148
}
 
1149
 
 
1150
function ListAvailableCharSets()
 
1151
{
 
1152
  try {
 
1153
    var availCharsetDict     = [];
 
1154
    var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService); 
 
1155
    var kNC_Root = rdf.GetResource("NC:DecodersRoot");
 
1156
    var kNC_name = rdf.GetResource("http://home.netscape.com/NC-rdf#Name");
 
1157
    var rdfDataSource = rdf.GetDataSource("rdf:charset-menu"); 
 
1158
    var rdfContainer = Components.classes["@mozilla.org/rdf/container;1"].getService(Components.interfaces.nsIRDFContainer);
 
1159
 
 
1160
    rdfContainer.Init(rdfDataSource, kNC_Root);
 
1161
    var availableCharsets = rdfContainer.GetElements();
 
1162
    var charset;
 
1163
 
 
1164
    for (var i = 0; i < rdfContainer.GetCount(); i++) {
 
1165
      charset = availableCharsets.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
 
1166
      availCharsetDict[i] = new Array(2);
 
1167
      availCharsetDict[i][0] = readRDFString(rdfDataSource, charset, kNC_name);
 
1168
      availCharsetDict[i][1] = charset.Value;
 
1169
    }
 
1170
    return availCharsetDict;
 
1171
  }
 
1172
  catch (e) { return null; }
 
1173
}
 
1174
 
 
1175
function ExplodeElement(node)
 
1176
{
 
1177
  var child = node.firstChild;
 
1178
  var parent = node.parentNode;
 
1179
  if (!parent)
 
1180
    return;
 
1181
  while (child)
 
1182
  {
 
1183
    var tmp = child.nextSibling;
 
1184
    parent.insertBefore(child, node);
 
1185
    child = tmp;
 
1186
  }
 
1187
  var brNode = document.createElement("br");
 
1188
  parent.insertBefore(brNode, node);
 
1189
  parent.removeChild(node);
 
1190
}
 
1191
 
 
1192
function NormalizeURL(url)
 
1193
{
 
1194
  if (!GetScheme(url) && !IsUrlAboutBlank(url))
 
1195
  {
 
1196
    var k = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
 
1197
 
 
1198
    var noBackSlashUrl = url.replace(/\\\"/g, "\"");
 
1199
    var c0 = noBackSlashUrl[0];
 
1200
    var c1 = noBackSlashUrl[1]
 
1201
    if (c0 == '/' ||
 
1202
        ( ((c0 >= 'a' && c0 <= 'z') || (c0 >= 'A' && c0 <= 'Z')) && c1 == ":"))
 
1203
    {
 
1204
      // this is an absolute path
 
1205
      k.initWithPath(url);
 
1206
    }
 
1207
    else
 
1208
    {
 
1209
      // First, get the current dir for the process...
 
1210
      var dirServiceProvider = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIDirectoryServiceProvider);
 
1211
      var p = new Object();
 
1212
      var currentProcessDir = dirServiceProvider.getFile("CurWorkD", p).path;
 
1213
      k.initWithPath(currentProcessDir);
 
1214
 
 
1215
      // then try to append the relative path
 
1216
      try {
 
1217
        k.appendRelativePath(url);
 
1218
      }
 
1219
      catch (e) {
 
1220
        dump("### Can't understand the filepath\n");
 
1221
        return "about:blank";
 
1222
      }
 
1223
      var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
 
1224
      var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
 
1225
      url = fileHandler.getURLSpecFromFile(k);
 
1226
    }
 
1227
  }
 
1228
  return url;
 
1229
}
 
1230
 
 
1231
function IsXHTMLDocument()
 
1232
{
 
1233
  var doctype = GetCurrentEditor().document.doctype;
 
1234
  return (doctype.publicId == "-//W3C//DTD XHTML 1.0 Transitional//EN" ||
 
1235
          doctype.publicId == "-//W3C//DTD XHTML 1.0 Strict//EN");
 
1236
}
 
1237
 
 
1238
function IsStrictDTD()
 
1239
{
 
1240
  var doctype = GetCurrentEditor().document.doctype;
 
1241
  return (doctype.publicId.lastIndexOf("Strict") != -1);
 
1242
}
 
1243
 
 
1244
function IsCSSDisabledAndStrictDTD()
 
1245
{
 
1246
  var prefs = GetPrefs();
 
1247
  var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
 
1248
  return !IsCSSPrefChecked && IsStrictDTD();
 
1249
}