home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 97 / CD-ROM 97 / CD-ROM 97.iso / internet / ghostzilla / ghsetup.exe / chrome / comm.jar / content / editor / ComposerCommands.js next >
Encoding:
JavaScript  |  2002-05-22  |  100.0 KB  |  3,296 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Netscape Public License
  6.  * Version 1.1 (the "License"); you may not use this file except in
  7.  * compliance with the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/NPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is mozilla.org code.
  16.  *
  17.  * The Initial Developer of the Original Code is 
  18.  * Netscape Communications Corporation.
  19.  * Portions created by the Initial Developer are Copyright (C) 1998-1999
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *    Simon Fraser (sfraser@netscape.com)
  24.  *    Ryan Cassin (rcassin@supernova.org)
  25.  *    Kathleen Brade (brade@netscape.com)
  26.  *    Daniel Glazman (glazman@netscape.com)
  27.  *    Akkana Peck (akkana@netscape.com)
  28.  *
  29.  *
  30.  * Alternatively, the contents of this file may be used under the terms of
  31.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  32.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  33.  * in which case the provisions of the GPL or the LGPL are applicable instead
  34.  * of those above. If you wish to allow use of your version of this file only
  35.  * under the terms of either the GPL or the LGPL, and not to allow others to
  36.  * use your version of this file under the terms of the NPL, indicate your
  37.  * decision by deleting the provisions above and replace them with the notice
  38.  * and other provisions required by the GPL or the LGPL. If you do not delete
  39.  * the provisions above, a recipient may use your version of this file under
  40.  * the terms of any one of the NPL, the GPL or the LGPL.
  41.  *
  42.  * ***** END LICENSE BLOCK ***** */
  43.  
  44. /* Implementations of nsIControllerCommand for composer commands */
  45.  
  46. //-----------------------------------------------------------------------------------
  47. function SetupHTMLEditorCommands()
  48. {
  49.   var controller = GetEditorController();
  50.   if (!controller)
  51.     return;
  52.   
  53.  
  54.   // Include everthing a text editor does
  55.   SetupTextEditorCommands();
  56.  
  57.   //dump("Registering HTML editor commands\n");
  58.  
  59.   controller.registerCommand("cmd_renderedHTMLEnabler",           nsDummyHTMLCommand);
  60.  
  61.   controller.registerCommand("cmd_listProperties",  nsListPropertiesCommand);
  62.   controller.registerCommand("cmd_pageProperties",  nsPagePropertiesCommand);
  63.   controller.registerCommand("cmd_colorProperties", nsColorPropertiesCommand);
  64.   controller.registerCommand("cmd_advancedProperties", nsAdvancedPropertiesCommand);
  65.   controller.registerCommand("cmd_objectProperties",   nsObjectPropertiesCommand);
  66.   controller.registerCommand("cmd_removeLinks",        nsRemoveLinksCommand);
  67.   controller.registerCommand("cmd_removeNamedAnchors", nsRemoveNamedAnchorsCommand);
  68.   controller.registerCommand("cmd_editLink",        nsEditLinkCommand);
  69.   
  70.   controller.registerCommand("cmd_form",          nsFormCommand);
  71.   controller.registerCommand("cmd_inputtag",      nsInputTagCommand);
  72.   controller.registerCommand("cmd_inputimage",    nsInputImageCommand);
  73.   controller.registerCommand("cmd_textarea",      nsTextAreaCommand);
  74.   controller.registerCommand("cmd_select",        nsSelectCommand);
  75.   controller.registerCommand("cmd_button",        nsButtonCommand);
  76.   controller.registerCommand("cmd_label",         nsLabelCommand);
  77.   controller.registerCommand("cmd_fieldset",      nsFieldSetCommand);
  78.   controller.registerCommand("cmd_isindex",       nsIsIndexCommand);
  79.   controller.registerCommand("cmd_image",         nsImageCommand);
  80.   controller.registerCommand("cmd_hline",         nsHLineCommand);
  81.   controller.registerCommand("cmd_link",          nsLinkCommand);
  82.   controller.registerCommand("cmd_anchor",        nsAnchorCommand);
  83.   controller.registerCommand("cmd_insertHTML",    nsInsertHTMLCommand);
  84.   controller.registerCommand("cmd_insertBreak",   nsInsertBreakCommand);
  85.   controller.registerCommand("cmd_insertBreakAll",nsInsertBreakAllCommand);
  86.  
  87.   controller.registerCommand("cmd_table",              nsInsertOrEditTableCommand);
  88.   controller.registerCommand("cmd_editTable",          nsEditTableCommand);
  89.   controller.registerCommand("cmd_SelectTable",        nsSelectTableCommand);
  90.   controller.registerCommand("cmd_SelectRow",          nsSelectTableRowCommand);
  91.   controller.registerCommand("cmd_SelectColumn",       nsSelectTableColumnCommand);
  92.   controller.registerCommand("cmd_SelectCell",         nsSelectTableCellCommand);
  93.   controller.registerCommand("cmd_SelectAllCells",     nsSelectAllTableCellsCommand);
  94.   controller.registerCommand("cmd_InsertTable",        nsInsertTableCommand);
  95.   controller.registerCommand("cmd_InsertRowAbove",     nsInsertTableRowAboveCommand);
  96.   controller.registerCommand("cmd_InsertRowBelow",     nsInsertTableRowBelowCommand);
  97.   controller.registerCommand("cmd_InsertColumnBefore", nsInsertTableColumnBeforeCommand);
  98.   controller.registerCommand("cmd_InsertColumnAfter",  nsInsertTableColumnAfterCommand);
  99.   controller.registerCommand("cmd_InsertCellBefore",   nsInsertTableCellBeforeCommand);
  100.   controller.registerCommand("cmd_InsertCellAfter",    nsInsertTableCellAfterCommand);
  101.   controller.registerCommand("cmd_DeleteTable",        nsDeleteTableCommand);
  102.   controller.registerCommand("cmd_DeleteRow",          nsDeleteTableRowCommand);
  103.   controller.registerCommand("cmd_DeleteColumn",       nsDeleteTableColumnCommand);
  104.   controller.registerCommand("cmd_DeleteCell",         nsDeleteTableCellCommand);
  105.   controller.registerCommand("cmd_DeleteCellContents", nsDeleteTableCellContentsCommand);
  106.   controller.registerCommand("cmd_JoinTableCells",     nsJoinTableCellsCommand);
  107.   controller.registerCommand("cmd_SplitTableCell",     nsSplitTableCellCommand);
  108.   controller.registerCommand("cmd_TableOrCellColor",   nsTableOrCellColorCommand);
  109.   controller.registerCommand("cmd_NormalizeTable",     nsNormalizeTableCommand);
  110.   controller.registerCommand("cmd_FinishHTMLSource",   nsFinishHTMLSource);
  111.   controller.registerCommand("cmd_CancelHTMLSource",   nsCancelHTMLSource);
  112.   controller.registerCommand("cmd_smiley",             nsSetSmiley);
  113.   controller.registerCommand("cmd_buildRecentPagesMenu", nsBuildRecentPagesMenu);
  114.   controller.registerCommand("cmd_ConvertToTable",     nsConvertToTable);
  115. }
  116.  
  117. function SetupTextEditorCommands()
  118. {
  119.   var controller = GetEditorController();
  120.   if (!controller)
  121.     return;
  122.   
  123.   //dump("Registering plain text editor commands\n");
  124.   
  125.   controller.registerCommand("cmd_find",       nsFindCommand);
  126.   controller.registerCommand("cmd_findNext",   nsFindNextCommand);
  127.   controller.registerCommand("cmd_spelling",   nsSpellingCommand);
  128.   controller.registerCommand("cmd_validate",   nsValidateCommand);
  129.   controller.registerCommand("cmd_checkLinks", nsCheckLinksCommand);
  130.   controller.registerCommand("cmd_insertChars", nsInsertCharsCommand);
  131. }
  132.  
  133. function SetupComposerWindowCommands()
  134. {
  135.   // Create a command controller and register commands
  136.   //   specific to Web Composer window (file-related commands, HTML Source...)
  137.   // IMPORTANT: For each of these commands, the doCommand method 
  138.   //            must first call FinishHTMLSource() 
  139.   //            to go from HTML Source mode to any other edit mode
  140.  
  141.   var windowCommandManager = window.controllers;
  142.  
  143.   if (!windowCommandManager) return;
  144.  
  145.   var composerController = Components.classes["@mozilla.org/editor/composercontroller;1"].createInstance();
  146.   if (!composerController)
  147.   {
  148.     dump("Failed to create composerController\n");
  149.     return;
  150.   }
  151.  
  152.   var editorController = composerController.QueryInterface(Components.interfaces.nsIEditorController);
  153.   if (!editorController)
  154.   {
  155.     dump("Failed to get interface for nsIEditorController\n");
  156.     return;
  157.   }
  158.  
  159.   // Note: We init with the editorShell for the main composer window, not the HTML Source textfield?
  160.   editorController.Init(window.editorShell);
  161.  
  162.   var interfaceRequestor = composerController.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  163.   if (!interfaceRequestor)
  164.   {
  165.     dump("Failed to get iterfaceRequestor for composerController\n");
  166.     return;
  167.   }
  168.     
  169.  
  170.   // Get the nsIControllerCommandManager interface we need to register more commands
  171.   var commandManager = interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandManager);
  172.   if (!commandManager)
  173.   {
  174.     dump("Failed to get interface for nsIControllerCommandManager\n");
  175.     return;
  176.   }
  177.  
  178.   // File-related commands
  179.   commandManager.registerCommand("cmd_open",           nsOpenCommand);
  180.   commandManager.registerCommand("cmd_save",           nsSaveCommand);
  181.   commandManager.registerCommand("cmd_saveAs",         nsSaveAsCommand);
  182.   commandManager.registerCommand("cmd_exportToText",   nsExportToTextCommand);
  183.   commandManager.registerCommand("cmd_saveAsCharset",  nsSaveAsCharsetCommand);
  184.   commandManager.registerCommand("cmd_publish",        nsPublishCommand);
  185.   commandManager.registerCommand("cmd_publishAs",      nsPublishAsCommand);
  186.   commandManager.registerCommand("cmd_publishSettings",nsPublishSettingsCommand);
  187.   commandManager.registerCommand("cmd_revert",         nsRevertCommand);
  188.   commandManager.registerCommand("cmd_openRemote",     nsOpenRemoteCommand);
  189.   commandManager.registerCommand("cmd_preview",        nsPreviewCommand);
  190.   commandManager.registerCommand("cmd_editSendPage",   nsSendPageCommand);
  191.   commandManager.registerCommand("cmd_print",          nsPrintCommand);
  192.   commandManager.registerCommand("cmd_printSetup",     nsPrintSetupCommand);
  193.   commandManager.registerCommand("cmd_quit",           nsQuitCommand);
  194.   commandManager.registerCommand("cmd_close",          nsCloseCommand);
  195.   commandManager.registerCommand("cmd_preferences",    nsPreferencesCommand);
  196.  
  197.   // Edit Mode commands
  198.   if (window.editorShell.editorType == "html")
  199.   {
  200.     commandManager.registerCommand("cmd_NormalMode",         nsNormalModeCommand);
  201.     commandManager.registerCommand("cmd_AllTagsMode",        nsAllTagsModeCommand);
  202.     commandManager.registerCommand("cmd_HTMLSourceMode",     nsHTMLSourceModeCommand);
  203.     commandManager.registerCommand("cmd_PreviewMode",        nsPreviewModeCommand);
  204.     commandManager.registerCommand("cmd_FinishHTMLSource",   nsFinishHTMLSource);
  205.     commandManager.registerCommand("cmd_CancelHTMLSource",   nsCancelHTMLSource);
  206.   }
  207.  
  208.   windowCommandManager.insertControllerAt(0, editorController);
  209. }
  210.  
  211. //-----------------------------------------------------------------------------------
  212. function GetEditorController()
  213. {
  214.   var numControllers = window._content.controllers.getControllerCount();
  215.     
  216.   // count down to find a controller that supplies a nsIControllerCommandManager interface
  217.   for (var i = numControllers-1; i >= 0 ; i --)
  218.   {
  219.     var commandManager = null;
  220.     
  221.     try { 
  222.       var controller = window._content.controllers.getControllerAt(i);
  223.       
  224.       var interfaceRequestor = controller.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  225.       if (!interfaceRequestor) continue;
  226.     
  227.       commandManager = interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandManager);
  228.     }
  229.     catch(ex)
  230.     {
  231.         //dump(ex + "\n");
  232.     }
  233.  
  234.     if (commandManager)
  235.       return commandManager;
  236.   }
  237.  
  238.   dump("Failed to find a controller to register commands with\n");
  239.   return null;
  240. }
  241.  
  242. //-----------------------------------------------------------------------------------
  243. function goUpdateComposerMenuItems(commandset)
  244. {
  245.   // dump("Updating commands for " + commandset.id + "\n");
  246.   
  247.   for (var i = 0; i < commandset.childNodes.length; i++)
  248.   {
  249.     var commandID = commandset.childNodes[i].getAttribute("id");
  250.     if (commandID)
  251.     {
  252.       goUpdateCommand(commandID);
  253.     }
  254.   }
  255. }
  256.  
  257. //-----------------------------------------------------------------------------------
  258. function PrintObject(obj)
  259. {
  260.   dump("-----" + obj + "------\n");
  261.   var names = "";
  262.   for (var i in obj)
  263.   {
  264.     if (i == "value")
  265.       names += i + ": " + obj.value + "\n";
  266.     else if (i == "id")
  267.       names += i + ": " + obj.id + "\n";
  268.     else
  269.       names += i + "\n";
  270.   }
  271.   
  272.   dump(names + "-----------\n");
  273. }
  274.  
  275. //-----------------------------------------------------------------------------------
  276. function PrintNodeID(id)
  277. {
  278.   PrintObject(document.getElementById(id));
  279. }
  280.  
  281. //-----------------------------------------------------------------------------------
  282. var nsDummyHTMLCommand =
  283. {
  284.   isCommandEnabled: function(aCommand, dummy)
  285.   {
  286.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  287.   },
  288.  
  289.   doCommand: function(aCommand)
  290.   {
  291.     // do nothing
  292.     dump("Hey, who's calling the dummy command?\n");
  293.   }
  294.  
  295. };
  296.  
  297. //-----------------------------------------------------------------------------------
  298. var nsOpenCommand =
  299. {
  300.   isCommandEnabled: function(aCommand, dummy)
  301.   {
  302.     return true;    // we can always do this
  303.   },
  304.  
  305.   doCommand: function(aCommand)
  306.   {
  307.     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  308.     fp.init(window, GetString("OpenHTMLFile"), nsIFilePicker.modeOpen);
  309.  
  310.     SetFilePickerDirectory(fp, "html");
  311.  
  312.     // When loading into Composer, direct user to prefer HTML files and text files,
  313.     //   so we call separately to control the order of the filter list
  314.     fp.appendFilters(nsIFilePicker.filterHTML);
  315.     fp.appendFilters(nsIFilePicker.filterText);
  316.     fp.appendFilters(nsIFilePicker.filterAll);
  317.  
  318.     /* doesn't handle *.shtml files */
  319.     try {
  320.       fp.show();
  321.       /* need to handle cancel (uncaught exception at present) */
  322.     }
  323.     catch (ex) {
  324.       dump("filePicker.chooseInputFile threw an exception\n");
  325.     }
  326.   
  327.     /* This checks for already open window and activates it... 
  328.      * note that we have to test the native path length
  329.      *  since file.URL will be "file:///" if no filename picked (Cancel button used)
  330.      */
  331.     if (fp.file && fp.file.path.length > 0) {
  332.       SaveFilePickerDirectory(fp, "html");
  333.       editPage(fp.fileURL.spec, window, false);
  334.     }
  335.   }
  336. };
  337.  
  338. // ******* File output commands and utilities ******** //
  339. //-----------------------------------------------------------------------------------
  340. var nsSaveCommand =
  341. {
  342.   isCommandEnabled: function(aCommand, dummy)
  343.   {
  344.     return window.editorShell && window.editorShell.documentEditable &&
  345.       (window.editorShell.documentModified || 
  346.        IsUrlAboutBlank(GetDocumentUrl()) ||
  347.        window.gHTMLSourceChanged);
  348.   },
  349.   
  350.   doCommand: function(aCommand)
  351.   {
  352.     var result = false;
  353.     if (window.editorShell)
  354.     {
  355.       // XXX Switching keybinding from Save to Publish isn't working now :(
  356.       //     so do publishing if editing remote url
  357.       var docUrl = GetDocumentUrl();
  358.       var scheme = GetScheme(docUrl);
  359.       if (scheme && scheme != "file")
  360.       {
  361.         goDoCommand("cmd_publish");
  362.         return true;
  363.       }
  364.  
  365.       FinishHTMLSource();
  366.       result = SaveDocument(IsUrlAboutBlank(docUrl), false, editorShell.contentsMIMEType);
  367.       window._content.focus();
  368.     }
  369.     return result;
  370.   }
  371. }
  372.  
  373. var nsSaveAsCommand =
  374. {
  375.   isCommandEnabled: function(aCommand, dummy)
  376.   {
  377.     return (window.editorShell && window.editorShell.documentEditable);
  378.   },
  379.  
  380.   doCommand: function(aCommand)
  381.   {
  382.     if (window.editorShell)
  383.     {
  384.       FinishHTMLSource();
  385.       var result = SaveDocument(true, false, editorShell.contentsMIMEType);
  386.       window._content.focus();
  387.       return result;
  388.     }
  389.     return false;
  390.   }
  391. }
  392.  
  393. var nsExportToTextCommand =
  394. {
  395.   isCommandEnabled: function(aCommand, dummy)
  396.   {
  397.     return (window.editorShell && window.editorShell.documentEditable);
  398.   },
  399.  
  400.   doCommand: function(aCommand)
  401.   {
  402.     if (window.editorShell)
  403.     {
  404.       FinishHTMLSource();
  405.       var result = SaveDocument(true, true, "text/plain");
  406.       window._content.focus();
  407.       return result;
  408.     }
  409.     return false;
  410.   }
  411. }
  412.  
  413. var nsSaveAsCharsetCommand =
  414. {
  415.   isCommandEnabled: function(aCommand, dummy)
  416.   {
  417.     return (window.editorShell && window.editorShell.documentEditable);
  418.   },
  419.   doCommand: function(aCommand)
  420.   {    
  421.     FinishHTMLSource();
  422.     window.ok = false;
  423.     window.exportToText = false;
  424.     window.openDialog("chrome://editor/content/EditorSaveAsCharset.xul","_blank", "chrome,close,titlebar,modal,resizable=yes");
  425.  
  426.     if (window.newTitle != null) {
  427.       try {
  428.         editorShell.SetDocumentTitle(window.newTitle);
  429.       } 
  430.       catch (ex) {}
  431.     }    
  432.  
  433.     if (window.ok)
  434.     {
  435.       if (window.exportToText)
  436.       {
  437.         window.ok = SaveDocument(true, true, "text/plain");
  438.       }
  439.       else
  440.       {
  441.         window.ok = SaveDocument(true, false, editorShell.contentsMIMEType);
  442.       }
  443.     }
  444.  
  445.     window._content.focus();
  446.     return window.ok;
  447.   }
  448. };
  449.  
  450. var nsPublishCommand =
  451. {
  452.   isCommandEnabled: function(aCommand, dummy)
  453.   {
  454.     if (window.editorShell && window.editorShell.documentEditable)
  455.     {
  456.       // Always allow publishing when editing a local document,
  457.       //  otherwise the document modified state would prevent that
  458.       //  when you first open any local file.
  459.       var docUrl = GetDocumentUrl();
  460.       return window.editorShell.documentModified || window.gHTMLSourceChanged
  461.              || IsUrlAboutBlank(docUrl) || GetScheme(docUrl) == "file";
  462.              
  463.     }
  464.     return false;
  465.   },
  466.   
  467.   doCommand: function(aCommand)
  468.   {
  469.     if (window.editorShell)
  470.     {
  471.       var docUrl = GetDocumentUrl();
  472.       var filename = GetFilename(docUrl);
  473.       var publishData;
  474.       var showPublishDialog = false;
  475.  
  476.       // First check pref to always show publish dialog
  477.       try {
  478.         var prefs = GetPrefs();
  479.         if (prefs)
  480.           showPublishDialog = prefs.getBoolPref("editor.always_show_publish_dialog");
  481.       } catch(e) {}
  482.  
  483.       if (!showPublishDialog && filename)
  484.       {
  485.         // Try to get publish data from the document url
  486.         publishData = CreatePublishDataFromUrl(docUrl);
  487.  
  488.         // If none, use default publishing site? Need a pref for this
  489.         //if (!publishData)
  490.         //  publishData = GetPublishDataFromSiteName(GetDefaultPublishSiteName(), filename);
  491.       }
  492.  
  493.       if (showPublishDialog || !publishData)
  494.       {
  495.         // Show the publish dialog
  496.         publishData = {};
  497.         window.ok = false;
  498.         window.openDialog("chrome://editor/content/EditorPublish.xul","_blank", 
  499.                           "chrome,close,titlebar,modal", "", "", publishData);
  500.         window._content.focus();
  501.         if (!window.ok)
  502.           return false;
  503.       }
  504.       if (publishData)
  505.       {
  506.         FinishHTMLSource();
  507.         return Publish(publishData);
  508.       }
  509.     }
  510.     return false;
  511.   }
  512. }
  513.  
  514. var nsPublishAsCommand =
  515. {
  516.   isCommandEnabled: function(aCommand, dummy)
  517.   {
  518.     return (window.editorShell && window.editorShell.documentEditable);
  519.   },
  520.   
  521.   doCommand: function(aCommand)
  522.   {
  523.     if (window.editorShell)
  524.     {
  525.       FinishHTMLSource();
  526.  
  527.       window.ok = false;
  528.       publishData = {};
  529.       window.openDialog("chrome://editor/content/EditorPublish.xul","_blank", 
  530.                         "chrome,close,titlebar,modal", "", "", publishData);
  531.       window._content.focus();
  532.       if (window.ok)
  533.         return Publish(publishData);
  534.     }
  535.     return false;
  536.   }
  537. }
  538.  
  539. // ------- output utilites   ----- //
  540.  
  541. // returns a fileExtension string
  542. function GetExtensionBasedOnMimeType(aMIMEType)
  543. {
  544.   try {
  545.     var mimeService = null;
  546.     mimeService = Components.classes["@mozilla.org/mime;1"].getService();
  547.     mimeService = mimeService.QueryInterface(Components.interfaces.nsIMIMEService);
  548.     if (!mimeService) return "";
  549.  
  550.     var mimeInfo = mimeService.GetFromMIMEType(aMIMEType);
  551.     if (!mimeInfo) return "";
  552.  
  553.     var fileExtension = mimeInfo.primaryExtension;
  554.  
  555.     // the MIME service likes to give back ".htm" for text/html files,
  556.     // so do a special-case fix here.
  557.     if (fileExtension == "htm")
  558.       fileExtension = "html";
  559.  
  560.     return fileExtension;
  561.   }
  562.   catch (e) {}
  563.   return "";
  564. }
  565.  
  566. function GetSuggestedFileName(aDocumentURLString, aMIMEType, aHTMLDoc)
  567. {
  568.   var extension = GetExtensionBasedOnMimeType(aMIMEType);
  569.   if (extension)
  570.     extension = "." + extension;
  571.  
  572.   // check for existing file name we can use
  573.   if (aDocumentURLString.length >= 0 && !IsUrlAboutBlank(aDocumentURLString))
  574.   {
  575.     var docURI = null;
  576.     try {
  577.  
  578.       var ioService = GetIOService();
  579.       docURI = ioService.newURI(aDocumentURLString, window.editorShell.GetDocumentCharacterSet(), null);
  580.       docURI = docURI.QueryInterface(Components.interfaces.nsIURL);
  581.  
  582.       // grab the file name
  583.       var url = docURI.fileBaseName;
  584.       if (url)
  585.         return url+extension;
  586.     } catch(e) {}
  587.   } 
  588.  
  589.   // check if there is a title we can use
  590.   var title = aHTMLDoc.title;
  591.   if (title.length > 0) // we have a title; let's see if it's usable
  592.   {
  593.     // clean up the title to make it a usable filename
  594.     title = title.replace(/\"/g, "");  // Strip out quote character: "
  595.     title = TrimString(title); // trim whitespace from beginning and end
  596.     title = title.replace(/[ \.\\@\/:]/g, "_");  //Replace "bad" filename characters with "_"
  597.     if (title.length > 0)
  598.       return title + extension;
  599.   }
  600.  
  601.   // if we still don't have a file name, let's just go with "untitled"
  602.   return GetString("untitled") + extension;
  603. }
  604.  
  605. // returns file picker result
  606. function PromptForSaveLocation(aDoSaveAsText, aEditorType, aMIMEType, ahtmlDocument, aDocumentURLString)
  607. {
  608.   var dialogResult = new Object;
  609.   dialogResult.filepickerClick = nsIFilePicker.returnCancel;
  610.   dialogResult.resultingURI = "";
  611.   dialogResult.resultingLocalFile = null;
  612.  
  613.   var fp = null;
  614.   try {
  615.     fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  616.   } catch (e) {}
  617.   if (!fp) return dialogResult;
  618.  
  619.   // determine prompt string based on type of saving we'll do
  620.   var promptString;
  621.   if (aDoSaveAsText || aEditorType == "text")
  622.     promptString = GetString("ExportToText");
  623.   else
  624.     promptString = GetString("SaveDocumentAs")
  625.  
  626.   fp.init(window, promptString, nsIFilePicker.modeSave);
  627.  
  628.   // Set filters according to the type of output
  629.   if (aDoSaveAsText)
  630.     fp.appendFilters(nsIFilePicker.filterText);
  631.   else
  632.     fp.appendFilters(nsIFilePicker.filterHTML);
  633.   fp.appendFilters(nsIFilePicker.filterAll);
  634.  
  635.   // now let's actually set the filepicker's suggested filename
  636.   var suggestedFileName = GetSuggestedFileName(aDocumentURLString, aMIMEType, ahtmlDocument);
  637.   if (suggestedFileName)
  638.     fp.defaultString = suggestedFileName;
  639.  
  640.   // set the file picker's current directory
  641.   // assuming we have information needed (like prior saved location)
  642.   try {
  643.     var ioService = GetIOService();
  644.     
  645.     var isLocalFile = true;
  646.     try {
  647.       var docURI = ioService.newURI(aDocumentURLString, window.editorShell.GetDocumentCharacterSet(), null);
  648.       isLocalFile = docURI.schemeIs("file");
  649.     }
  650.     catch (e) {}
  651.  
  652.     var parentLocation = null;
  653.     if (isLocalFile)
  654.     {
  655.       var fileLocation = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile);
  656.       ioService.initFileFromURLSpec(fileLocation, aDocumentURLString);  // this asserts if url is not local
  657.       parentLocation = fileLocation.parent;
  658.     }
  659.     if (parentLocation)
  660.     {
  661.       // Save current filepicker's default location
  662.       if ("gFilePickerDirectory" in window)
  663.         gFilePickerDirectory = fp.displayDirectory;
  664.  
  665.       fp.displayDirectory = parentLocation;
  666.     }
  667.     else
  668.     {
  669.       // Initialize to the last-used directory for the particular type (saved in prefs)
  670.       SetFilePickerDirectory(fp, aEditorType);
  671.     }
  672.   }
  673.   catch(e) {}
  674.  
  675.   dialogResult.filepickerClick = fp.show();
  676.   if (dialogResult.filepickerClick != nsIFilePicker.returnCancel)
  677.   {
  678.     // reset urlstring to new save location
  679.     dialogResult.resultingURIString = ioService.getURLSpecFromFile(fp.file);
  680.     dialogResult.resultingLocalFile = fp.file;
  681.     SaveFilePickerDirectory(fp, aEditorType);
  682.   }
  683.   else if ("gFilePickerDirectory" in window && gFilePickerDirectory)
  684.     fp.displayDirectory = gFilePickerDirectory; 
  685.  
  686.   return dialogResult;
  687. }
  688.  
  689. // returns a boolean (whether to continue (true) or not (false) because user canceled)
  690. function PromptAndSetTitleIfNone(aHTMLDoc)
  691. {
  692.   if (!aHTMLDoc) throw NS_ERROR_NULL_POINTER;
  693.  
  694.   var title = aHTMLDoc.title;
  695.   if (title.length > 0) // we have a title; no need to prompt!
  696.     return true;
  697.  
  698.   var promptService = null;
  699.   try {
  700.     promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  701.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  702.   }
  703.   catch (e) {}
  704.   if (!promptService) return false;
  705.  
  706.   var result = {value:null};
  707.   var captionStr = GetString("DocumentTitle");
  708.   var msgStr = GetString("NeedDocTitle") + '\n' + GetString("DocTitleHelp");
  709.   var confirmed = promptService.prompt(window, captionStr, msgStr, result, null, {value:0});
  710.   if (confirmed && result.value && result.value != "")
  711.     window.editorShell.SetDocumentTitle(result.value);
  712.  
  713.   return confirmed;
  714. }
  715.  
  716. var gPersistObj;
  717.  
  718. // Don't forget to do these things after calling OutputFileWithPersistAPI:
  719. //    window.editorShell.doAfterSave(doUpdateURLOnDocument, urlstring);  // we need to update the url before notifying listeners
  720. //    if (!aSaveCopy && success)
  721. //      window.editorShell.editor.resetModificationCount();
  722.       // this should cause notification to listeners that document has changed
  723.  
  724. const webPersist = Components.interfaces.nsIWebBrowserPersist;
  725. function OutputFileWithPersistAPI(editorDoc, aDestinationLocation, aRelatedFilesParentDir, aMimeType)
  726. {
  727.   gPersistObj = null;
  728.   try {
  729.     var imeEditor = window.editorShell.editor.QueryInterface(Components.interfaces.nsIEditorIMESupport);
  730.     if (imeEditor)
  731.       imeEditor.ForceCompositionEnd();
  732.     } catch (e) {}
  733.  
  734.   var isLocalFile = false;
  735.   try {
  736.     var tmp1 = aDestinationLocation.QueryInterface(Components.interfaces.nsIFile);
  737.     isLocalFile = true;
  738.   } 
  739.   catch (e) {
  740.     try {
  741.       var tmp = aDestinationLocation.QueryInterface(Components.interfaces.nsIURI);
  742.       isLocalFile = tmp.schemeIs("file");
  743.     }
  744.     catch (e) {}
  745.   }
  746.  
  747.   try {
  748.     // we should supply a parent directory if/when we turn on functionality to save related documents
  749.     var persistObj = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(webPersist);
  750.     persistObj.progressListener = gEditorOutputProgressListener;
  751.     
  752.     var wrapColumn = GetWrapColumn();
  753.     var outputFlags = GetOutputFlags(aMimeType, wrapColumn);
  754.  
  755.     // for 4.x parity as well as improving readability of file locally on server
  756.     // this will always send crlf for upload (http/ftp)
  757.     if (!isLocalFile) // if we aren't saving locally then send both cr and lf
  758.       outputFlags |= webPersist.ENCODE_FLAGS_CR_LINEBREAKS | webPersist.ENCODE_FLAGS_LF_LINEBREAKS;
  759.  
  760.     // note: we always want to set the replace existing files flag since we have
  761.     // already given user the chance to not replace an existing file (file picker)
  762.     // or the user picked an option where the file is implicitly being replaced (save)
  763.     persistObj.persistFlags = persistObj.persistFlags 
  764.                             | webPersist.PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS
  765.                             | webPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES
  766.                             | webPersist.PERSIST_FLAGS_DONT_FIXUP_LINKS
  767.                             | webPersist.PERSIST_FLAGS_FIXUP_ORIGINAL_DOM;
  768.     persistObj.saveDocument(editorDoc, aDestinationLocation, aRelatedFilesParentDir, 
  769.                             aMimeType, outputFlags, wrapColumn);
  770.     gPersistObj = persistObj;
  771.   }
  772.   catch(e) { dump("caught an error, bail\n"); return false; }
  773.  
  774.   return true;
  775. }
  776.  
  777. // returns output flags based on mimetype, wrapCol and prefs
  778. function GetOutputFlags(aMimeType, aWrapColumn)
  779. {
  780.   var outputFlags = webPersist.ENCODE_FLAGS_ENCODE_ENTITIES;
  781.   if (aMimeType == "text/plain")
  782.   {
  783.     // When saving in "text/plain" format, always do formatting
  784.     outputFlags |= webPersist.ENCODE_FLAGS_FORMATTED;
  785.   }
  786.   else
  787.   {
  788.     // Should we prettyprint? Check the pref
  789.     try {
  790.       var prefs = GetPrefs();
  791.       if (prefs.getBoolPref("editor.prettyprint"))
  792.         outputFlags |= webPersist.ENCODE_FLAGS_FORMATTED;
  793.     }
  794.     catch (e) {}
  795.   }
  796.  
  797.   if (aWrapColumn > 0)
  798.     outputFlags |= webPersist.ENCODE_FLAGS_WRAP;
  799.  
  800.   return outputFlags;
  801. }
  802.  
  803. // returns number of column where to wrap
  804. const nsIPlaintextEditor = Components.interfaces.nsIPlaintextEditor;
  805. function GetWrapColumn()
  806. {
  807.   var wrapCol = 72;
  808.   try {
  809.     var textEditor = window.editorShell.editor.QueryInterface(nsIPlaintextEditor);
  810.     wrapCol = textEditor.wrapWidth;
  811.   }
  812.   catch (e) {}
  813.  
  814.   return wrapCol;
  815. }
  816.  
  817. function GetPromptService()
  818. {
  819.   var promptService;
  820.   try {
  821.     promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  822.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  823.   }
  824.   catch (e) {}
  825.   return promptService;
  826. }
  827.  
  828. const gShowDebugOutputStateChange = false;
  829. const gShowDebugOutputProgress = false;
  830. const gShowDebugOutputStatusChange = false;
  831.  
  832. const gShowDebugOutputLocationChange = false;
  833. const gShowDebugOutputSecurityChange = false;
  834.  
  835. const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  836. const nsIChannel = Components.interfaces.nsIChannel;
  837.  
  838. var gEditorOutputProgressListener =
  839. {
  840.   onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
  841.   {
  842.     // Use this to access onStateChange flags
  843.     var requestSpec;
  844.     try {
  845.       var channel = aRequest.QueryInterface(nsIChannel);
  846.       requestSpec = StripUsernamePasswordFromURI(channel.URI);
  847.     } catch (e) {
  848.       if ( gShowDebugOutputStateChange)
  849.         dump("***** onStateChange; NO REQUEST CHANNEL\n");
  850.     }
  851.  
  852.     var pubSpec;
  853.     if (gPublishData)
  854.       pubSpec = gPublishData.publishUrl + gPublishData.docDir + gPublishData.filename;
  855.  
  856.     if (gShowDebugOutputStateChange)
  857.     {
  858.       dump("***** onStateChange request: " + requestSpec + "\n");
  859.       dump("      state flags: ");
  860.  
  861.       if (aStateFlags & nsIWebProgressListener.STATE_START)
  862.         dump(" STATE_START, ");
  863.       if (aStateFlags & nsIWebProgressListener.STATE_STOP)
  864.         dump(" STATE_STOP, ");
  865.       if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK)
  866.         dump(" STATE_IS_NETWORK ");
  867.  
  868.       dump("\n * requestSpec="+requestSpec+", pubSpec="+pubSpec+", aStatus="+aStatus+"\n");
  869.  
  870.       DumpDebugStatus(aStatus);
  871.     }
  872.  
  873.     // Detect start of file upload of any file:
  874.     if ((aStateFlags & nsIWebProgressListener.STATE_START)
  875.          && requestSpec && gProgressDialog)
  876.     {
  877.       try {
  878.         // Add url to progress dialog's list showing each file uploading
  879.         // Note that even though we create dialog before calling OutputFileWithPersistAPI,
  880.         //  we can get here before dialog is initialized.
  881.         //  This will cause exception calling AddProgressListitem,
  882.         //  But we'll add any missed files in dialog later
  883.         gProgressDialog.SetProgressStatus(GetFilename(requestSpec), "busy");
  884.       } catch(e) {
  885.         dump(" Exception error calling SetProgressStatus\n");
  886.       }
  887.     }
  888.  
  889.     // Detect end of file upload of any file:
  890.     if ((aStateFlags & nsIWebProgressListener.STATE_STOP))
  891.     {
  892.       // ignore aStatus == kErrorBindingAborted; check http response for possible errors
  893.       try {
  894.         // check http channel for response: 200 range is ok; other ranges are not
  895.         var httpChannel = aRequest.QueryInterface(Components.interfaces.nsIHttpChannel);
  896.         var httpResponse = httpChannel.responseStatus;
  897.         if (httpResponse < 200 || httpResponse >= 300)
  898.           aStatus = httpResponse;   // not a real error but enough to pass check below
  899.         else if (aStatus == kErrorBindingAborted)
  900.           aStatus = 0;
  901.  
  902.         if (gShowDebugOutputStateChange)
  903.           dump("http response is: "+httpResponse+"\n");
  904.       } 
  905.       catch(e) 
  906.       {
  907.         if (aStatus == kErrorBindingAborted)
  908.           aStatus = 0;
  909.       }
  910.  
  911.       // Notify progress dialog when we receive the STOP
  912.       //  notification for a file if there was an error 
  913.       //  or for a successful finish only if 
  914.       //  destination url is contains the publishing location
  915.       if (gProgressDialog &&
  916.           (aStatus != 0 
  917.            || requestSpec && requestSpec.indexOf(gPublishData.publishUrl) == 0))
  918.       {
  919.         try {
  920.           gProgressDialog.SetProgressFinished(GetFilename(requestSpec), aStatus);
  921.         } catch(e) {}
  922.       }
  923.  
  924.       if (aStatus)
  925.       {
  926.         // Cancel the publish 
  927.         gPersistObj.cancelSave();
  928.         gProgressDialog.SetProgressStatusCancel();
  929.  
  930.         //XXX TODO: we should provide more meaningful errors (if possible)
  931.         var failedStr = GetString("PublishFailed");
  932.         
  933.         // XXX We don't have error codes in IDL !!!
  934.         // Give better error messages for cases we know about:
  935.         if (aStatus == 2152398868)  // Bad directory
  936.         {
  937.           var requestFilename = requestSpec ? GetFilename(requestSpec) : "";
  938.           var dir = (gPublishData.filename == requestFilename) ? 
  939.                        gPublishData.docDir : gPublishData.otherDir;
  940.  
  941.           failedStr = GetString("PublishDirFailed").replace(/%dir%/, gPublishData.docDir);
  942.           if (gProgressDialog)
  943.             gProgressDialog.SetStatusMessage(failedStr);
  944.  
  945.           // Remove directory from saved prefs
  946.           RemovePublishSubdirectoryFromPrefs(gPublishData, dir);
  947.         }
  948.  
  949.         // Do not do any commands after failure
  950.         gCommandAfterPublishing = null;
  951.  
  952.         // Show error in progress dialog and let user close it
  953.         if (gProgressDialog)
  954.         {
  955.           try {
  956.             // Tell dialog final status value so it can show appropriate message
  957.             gProgressDialog.SetProgressFinished(null, aStatus);
  958.           } catch (e) { 
  959.             dump(" **** EXCEPTION ERROR CALLING ProgressDialog.SetProgressFinished\n");
  960.             AlertWithTitle(GetString("Publish"), failedStr); 
  961.           }
  962.         }
  963.         else
  964.         {
  965.           // In case we ever get final alert with no dialog
  966.           AlertWithTitle(GetString("Publish"), failedStr);
  967.  
  968.           // Final cleanup
  969.           FinishPublishing();
  970.         }
  971.         return;  // we don't want to change location or reset mod count, etc.
  972.       }
  973.  
  974.       if ((aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK))
  975.       {
  976.         // All files are finished uploading
  977.         
  978.         // Publishing succeeded...
  979.         try {
  980.           // Get the new docUrl from the "browse location" in case "publish location" was FTP
  981.           var urlstring = GetDocUrlFromPublishData(gPublishData);
  982.  
  983.           window.editorShell.doAfterSave(true, urlstring);  // we need to update the url before notifying listeners
  984.           var editor = window.editorShell.editor.QueryInterface(Components.interfaces.nsIEditor);
  985.           editor.resetModificationCount();
  986.           // this should cause notification to listeners that doc has changed
  987.  
  988.           // Set UI based on whether we're editing a remote or local url
  989.           SetSaveAndPublishUI(urlstring);
  990.  
  991.         } catch (e) {}
  992.  
  993.         // Save publishData to prefs
  994.         if (gPublishData)
  995.         {
  996.           if (gPublishData.savePublishData)
  997.           {
  998.             // We published successfully, so we can safely
  999.             //  save docDir and otherDir to prefs
  1000.             gPublishData.saveDirs = true;
  1001.             SavePublishDataToPrefs(gPublishData);
  1002.           }
  1003.           else
  1004.             SavePassword(gPublishData);
  1005.         }
  1006.  
  1007.         // Ask progress dialog to close, but it may not
  1008.         // if user checked checkbox to keep it open
  1009.         if (gProgressDialog)
  1010.           gProgressDialog.RequestCloseDialog();
  1011.         else
  1012.           FinishPublishing();
  1013.       }
  1014.     }
  1015.   },
  1016.  
  1017.   onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress,
  1018.                               aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
  1019.   {
  1020.     if (gShowDebugOutputProgress)
  1021.     {
  1022.       try {
  1023.       var channel = aRequest.QueryInterface(nsIChannel);
  1024.       dump("***** onProgressChange request: " + channel.URI.spec + "\n");
  1025.       }
  1026.       catch (e) {}
  1027.       dump("*****       self:  "+aCurSelfProgress+" / "+aMaxSelfProgress+"\n");
  1028.       dump("*****       total: "+aCurTotalProgress+" / "+aMaxTotalProgress+"\n\n");
  1029.  
  1030.       if (gPersistObj)
  1031.       {
  1032.         if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_READY)
  1033.           dump(" Persister is ready to save data\n\n");
  1034.         else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_SAVING)
  1035.           dump(" Persister is saving data.\n\n");
  1036.         else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_FINISHED)
  1037.         {
  1038.           dump(" PERSISTER HAS FINISHED SAVING DATA\n\n\n");
  1039.         }
  1040.       }
  1041.     }
  1042.   },
  1043.  
  1044.   onLocationChange : function(aWebProgress, aRequest, aLocation)
  1045.   {
  1046.     if (gShowDebugOutputLocationChange)
  1047.     {
  1048.       dump("***** onLocationChange: "+aLocation.spec+"\n");
  1049.       var channel = aRequest.QueryInterface(nsIChannel);
  1050.       dump("*****          request: " + channel.URI.spec + "\n");
  1051.     }
  1052.   },
  1053.  
  1054.   onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
  1055.   {
  1056.     if (gShowDebugOutputStatusChange)
  1057.     {
  1058.       dump("***** onStatusChange: "+aMessage+"\n");
  1059.       try {
  1060.         var channel = aRequest.QueryInterface(nsIChannel);
  1061.         dump("*****        request: " + channel.URI.spec + "\n");
  1062.       }
  1063.       catch (e) { dump("          couldn't get request\n"); }
  1064.       
  1065.       DumpDebugStatus(aStatus);
  1066.  
  1067.       if (gPersistObj)
  1068.       {
  1069.         if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_READY)
  1070.           dump(" Persister is ready to save data\n\n");
  1071.         else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_SAVING)
  1072.           dump(" Persister is saving data.\n\n");
  1073.         else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_FINISHED)
  1074.           dump(" PERSISTER HAS FINISHED SAVING DATA\n\n\n");
  1075.       }
  1076.     }
  1077.   },
  1078.  
  1079.   onSecurityChange : function(aWebProgress, aRequest, state)
  1080.   {
  1081.     if (gShowDebugOutputSecurityChange)
  1082.     {
  1083.       try {
  1084.         var channel = aRequest.QueryInterface(nsIChannel);
  1085.         dump("***** onSecurityChange request: " + channel.URI.spec + "\n");
  1086.       } catch (e) {}
  1087.     }
  1088.   },
  1089.  
  1090.   QueryInterface : function(aIID)
  1091.   {
  1092.     if (aIID.equals(Components.interfaces.nsIWebProgressListener)
  1093.     || aIID.equals(Components.interfaces.nsISupports)
  1094.     || aIID.equals(Components.interfaces.nsISupportsWeakReference)
  1095.     || aIID.equals(Components.interfaces.nsIPrompt)
  1096.     || aIID.equals(Components.interfaces.nsIAuthPrompt))
  1097.       return this;
  1098.     throw Components.results.NS_NOINTERFACE;
  1099.   },
  1100.  
  1101. // nsIPrompt
  1102.   alert : function(dlgTitle, text)
  1103.   {
  1104.     AlertWithTitle(dlgTitle, text, gProgressDialog ? gProgressDialog : window);
  1105.   },
  1106.   alertCheck : function(dialogTitle, text, checkBoxLabel, checkObj)
  1107.   {
  1108.     AlertWithTitle(dialogTitle, text);
  1109.   },
  1110.   confirm : function(dlgTitle, text)
  1111.   {
  1112.     return ConfirmWithTitle(dlgTitle, text, null, null);
  1113.   },
  1114.   confirmCheck : function(dlgTitle, text, checkBoxLabel, checkObj)
  1115.   {
  1116.     var promptServ = GetPromptService();
  1117.     if (!promptServ)
  1118.       return;
  1119.  
  1120.     promptServ.confirmEx(window, dlgTitle, text, nsIPromptService.STD_OK_CANCEL_BUTTONS,
  1121.                          "", "", "", checkBoxLabel, checkObj);
  1122.   },
  1123.   confirmEx : function(dlgTitle, text, btnFlags, btn0Title, btn1Title, btn2Title, checkBoxLabel, checkVal)
  1124.   {
  1125.     var promptServ = GetPromptService();
  1126.     if (!promptServ)
  1127.      return 0;
  1128.  
  1129.     return promptServ.confirmEx(window, dlgTitle, text, btnFlags,
  1130.                         btn0Title, btn1Title, btn2Title,
  1131.                         checkBoxLabel, checkVal);
  1132.   },
  1133.   prompt : function(dlgTitle, text, inoutText, checkBoxLabel, checkObj)
  1134.   {
  1135.     var promptServ = GetPromptService();
  1136.     if (!promptServ)
  1137.      return false;
  1138.  
  1139.     return promptServ.prompt(window, dlgTitle, text, inoutText, checkBoxLabel, checkObj);
  1140.   },
  1141.   promptPassword : function(dlgTitle, text, pwObj, checkBoxLabel, savePWObj)
  1142.   {
  1143.  
  1144.     var promptServ = GetPromptService();
  1145.     if (!promptServ)
  1146.      return false;
  1147.  
  1148.     var ret = false;
  1149.     try {
  1150.       // Note difference with nsIAuthPrompt::promptPassword, which has 
  1151.       // just "in" savePassword param, while nsIPrompt is "inout"
  1152.       // Initialize with user's previous preference for this site
  1153.       if (gPublishData)
  1154.         savePWObj.value = gPublishData.savePassword;
  1155.  
  1156.       ret = promptServ.promptPassword(gProgressDialog ? gProgressDialog : window,
  1157.                                       dlgTitle, text, pwObj, checkBoxLabel, savePWObj);
  1158.  
  1159.       if (!ret)
  1160.         setTimeout(CancelPublishing,0);
  1161.  
  1162.       if (ret && gPublishData)
  1163.         UpdateUsernamePasswordFromPrompt(gPublishData, gPublishData.username, pwObj.value, savePWObj.value);
  1164.     } catch(e) {}
  1165.  
  1166.     return ret;
  1167.   },
  1168.   promptUsernameAndPassword : function(dlgTitle, text, userObj, pwObj, checkBoxLabel, savePWObj)
  1169.   {
  1170.     var ret = PromptUsernameAndPassword(dlgTitle, text, savePWObj, userObj, pwObj);
  1171.     if (!ret)
  1172.       setTimeout(CancelPublishing,0);
  1173.  
  1174.     return ret;
  1175.   },
  1176.   select : function(dlgTitle, text, count, selectList, outSelection)
  1177.   {
  1178.     var promptServ = GetPromptService();
  1179.     if (!promptServ)
  1180.       return false;
  1181.  
  1182.     return promptServ.select(window, dlgTitle, text, count, selectList, outSelection);
  1183.   },
  1184.  
  1185. // nsIAuthPrompt
  1186.   prompt : function(dlgTitle, text, pwrealm, savePW, defaultText, result)
  1187.   {
  1188.     var promptServ = GetPromptService();
  1189.     if (!promptServ)
  1190.       return false;
  1191.  
  1192.     var savePWObj = {value:savePW};
  1193.     var ret = promptServ.prompt(gProgressDialog ? gProgressDialog : window,
  1194.                                 dlgTitle, text, defaultText, pwrealm, savePWObj);
  1195.     if (!ret)
  1196.       setTimeout(CancelPublishing,0);
  1197.     return ret;
  1198.   },
  1199.  
  1200.   promptUsernameAndPassword : function(dlgTitle, text, pwrealm, savePW, userObj, pwObj)
  1201.   {
  1202.     var ret = PromptUsernameAndPassword(dlgTitle, text, savePW, userObj, pwObj);
  1203.     if (!ret)
  1204.       setTimeout(CancelPublishing,0);
  1205.     return ret;
  1206.   },
  1207.  
  1208.   promptPassword : function(dlgTitle, text, pwrealm, savePW, pwObj)
  1209.   {
  1210.     var ret = false;
  1211.     try {
  1212.       var promptServ = GetPromptService();
  1213.       if (!promptServ)
  1214.         return false;
  1215.  
  1216.       // Note difference with nsIPrompt::promptPassword, which has 
  1217.       // "inout" savePassword param, while nsIAuthPrompt is just "in"
  1218.       // Also nsIAuth doesn't supply "checkBoxLabel"
  1219.       // Initialize with user's previous preference for this site
  1220.       var savePWObj = {value:savePW};
  1221.       // Initialize with user's previous preference for this site
  1222.       if (gPublishData)
  1223.         savePWObj.value = gPublishData.savePassword;
  1224.  
  1225.       ret = promptServ.promptPassword(gProgressDialog ? gProgressDialog : window,
  1226.                                       dlgTitle, text, pwObj, GetString("SavePassword"), savePWObj);
  1227.  
  1228.       if (!ret)
  1229.         setTimeout(CancelPublishing,0);
  1230.  
  1231.       if (ret && gPublishData)
  1232.         UpdateUsernamePasswordFromPrompt(gPublishData, gPublishData.username, pwObj.value, savePWObj.value);
  1233.     } catch(e) {}
  1234.  
  1235.     return ret;
  1236.   }
  1237. }
  1238.  
  1239. function PromptUsernameAndPassword(dlgTitle, text, savePW, userObj, pwObj)
  1240. {
  1241.   // HTTP prompts us twice even if user Cancels from 1st attempt!
  1242.   // So never put up dialog if there's no publish data
  1243.   if (!gPublishData)
  1244.     return false
  1245.  
  1246.   var ret = false;
  1247.   try {
  1248.     var promptServ = GetPromptService();
  1249.     if (!promptServ)
  1250.       return false;
  1251.  
  1252.     var savePWObj = {value:savePW};
  1253.  
  1254.     // Initialize with user's previous preference for this site
  1255.     if (gPublishData)
  1256.     {
  1257.       // HTTP put uses this dialog if either username or password is bad,
  1258.       //   so prefill username input field with the previous value for modification
  1259.       savePWObj.value = gPublishData.savePassword;
  1260.       if (!userObj.value)
  1261.         userObj.value = gPublishData.username;
  1262.     }
  1263.  
  1264.     ret = promptServ.promptUsernameAndPassword(gProgressDialog ? gProgressDialog : window, 
  1265.                                                dlgTitle, text, userObj, pwObj, 
  1266.                                                GetString("SavePassword"), savePWObj);
  1267.     if (ret && gPublishData)
  1268.       UpdateUsernamePasswordFromPrompt(gPublishData, userObj.value, pwObj.value, savePWObj.value);
  1269.  
  1270.   } catch (e) {}
  1271.  
  1272.   return ret;
  1273. }
  1274.  
  1275. const kErrorBindingAborted = 2152398850;
  1276. const kErrorBindingRedirected = 2152398851;
  1277.  
  1278. function DumpDebugStatus(aStatus)
  1279. {
  1280.   if (aStatus == kErrorBindingAborted)
  1281.     dump("*****        status is NS_BINDING_ABORTED\n");
  1282.   else if (aStatus == kErrorBindingRedirected)
  1283.     dump("*****        status is NS_BINDING_REDIRECTED\n");
  1284.   else if (aStatus == 2152398852)
  1285.     dump("*****        status is UNKNOWN_TYPE\n");
  1286.   else if (aStatus == 2152398853)
  1287.     dump("*****        status is DESTINATION_NOT_DIR\n");
  1288.   else if (aStatus == 2152398854)
  1289.     dump("*****        status is TARGET_DOES_NOT_EXIST\n");
  1290.   else if (aStatus == 2152398856)
  1291.     dump("*****        status is ALREADY_EXISTS\n");
  1292.   else if (aStatus == 2152398858)
  1293.     dump("*****        status is DISK_FULL\n");
  1294.   else if (aStatus == 2152398860)
  1295.     dump("*****        status is NOT_DIRECTORY\n");
  1296.   else if (aStatus == 2152398861)
  1297.     dump("*****        status is IS_DIRECTORY\n");
  1298.   else if (aStatus == 2152398862)
  1299.     dump("*****        status is IS_LOCKED\n");
  1300.   else if (aStatus == 2152398863)
  1301.     dump("*****        status is TOO_BIG\n");
  1302.   else if (aStatus == 2152398865)
  1303.     dump("*****        status is NAME_TOO_LONG\n");
  1304.   else if (aStatus == 2152398866)
  1305.     dump("*****        status is NOT_FOUND\n");
  1306.   else if (aStatus == 2152398867)
  1307.     dump("*****        status is READ_ONLY\n");
  1308.   else if (aStatus == 2152398868)
  1309.     dump("*****        status is DIR_NOT_EMPTY\n");
  1310.   else if (aStatus == 2152398869)
  1311.     dump("*****        status is ACCESS_DENIED\n");
  1312.   else
  1313.     dump("*****        status is " + aStatus + "\n");
  1314. }
  1315.  
  1316. // Update any data that the user supplied in a prompt dialog
  1317. function UpdateUsernamePasswordFromPrompt(publishData, username, password, savePassword)
  1318. {
  1319.   if (!publishData)
  1320.     return;
  1321.   
  1322.   // Set flag to save publish data after publishing if it changed in dialog 
  1323.   //  and the "SavePassword" checkbox was checked
  1324.   //  or we already had site data for this site
  1325.   // (Thus we don't automatically create a site until user brings up Publish As dialog)
  1326.   publishData.savePublishData = (gPublishData.username != username || gPublishData.password != password)
  1327.                                 && (savePassword || !publishData.notInSiteData);
  1328.  
  1329.   publishData.username = username;
  1330.   publishData.password = password;
  1331.   publishData.savePassword = savePassword;
  1332. }
  1333.  
  1334. // throws an error or returns true if user attempted save; false if user canceled save
  1335. function SaveDocument(aSaveAs, aSaveCopy, aMimeType)
  1336. {
  1337.   if (!aMimeType || aMimeType == "" || !window.editorShell)
  1338.     throw NS_ERROR_NOT_INITIALIZED;
  1339.  
  1340.   var editorDoc = window.editorShell.editorDocument;
  1341.   if (!editorDoc)
  1342.     throw NS_ERROR_NOT_INITIALIZED;
  1343.  
  1344.   // if we don't have the right editor type bail (we handle text and html)
  1345.   var editorType = window.editorShell.editorType;
  1346. //  var isMailType = (editorType == "textmail" || editorType == "htmlmail")
  1347.   if (editorType != "text" && editorType != "html" && editorType != "htmlmail")
  1348.     throw NS_ERROR_NOT_IMPLEMENTED;
  1349.  
  1350.   var saveAsTextFile = window.editorShell.isSupportedTextType(aMimeType);
  1351.  
  1352.   // check if the file is to be saved in a format we don't understand; if so, bail
  1353.   if (aMimeType != "text/html" && !saveAsTextFile)
  1354.     throw NS_ERROR_NOT_IMPLEMENTED;
  1355.  
  1356.   if (saveAsTextFile)
  1357.     aMimeType = "text/plain";
  1358.  
  1359.   var urlstring = GetDocumentUrl();
  1360.   var mustShowFileDialog = (aSaveAs || IsUrlAboutBlank(urlstring) || (urlstring == ""));
  1361.  
  1362.   // If not doing "Save As" and editing a remote URL, do publishing instead
  1363.   if (!mustShowFileDialog && GetScheme(urlstring) != "file")
  1364.   {
  1365.     goDoCommand("cmd_publish");
  1366.     return true;
  1367.   }
  1368.  
  1369.   var replacing = !aSaveAs;
  1370.   var titleChanged = false;
  1371.   var doUpdateURL = false;
  1372.   var tempLocalFile = null;
  1373.  
  1374.   if (mustShowFileDialog)
  1375.   {
  1376.       try {
  1377.         var domhtmldoc = editorDoc.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
  1378.  
  1379.         // Prompt for title if we are saving to HTML
  1380.         if (!saveAsTextFile && (editorType == "html"))
  1381.         {
  1382.           var userContinuing = PromptAndSetTitleIfNone(domhtmldoc); // not cancel
  1383.           if (!userContinuing)
  1384.             return false;
  1385.         }
  1386.  
  1387.         var dialogResult = PromptForSaveLocation(saveAsTextFile, editorType, aMimeType, domhtmldoc, urlstring);
  1388.         if (dialogResult.filepickerClick == nsIFilePicker.returnCancel)
  1389.           return false;
  1390.  
  1391.         replacing = (dialogResult.filepickerClick == nsIFilePicker.returnReplace);
  1392.         urlstring = dialogResult.resultingURIString;
  1393.         tempLocalFile = dialogResult.resultingLocalFile;
  1394.  
  1395.       // update the new URL for the webshell unless we are saving a copy
  1396.       if (!aSaveCopy)
  1397.         doUpdateURL = true;
  1398.    } catch (e) {  return false; }
  1399.   } // mustShowFileDialog
  1400.  
  1401.   var success = true;
  1402.   var ioService;
  1403.   try {
  1404.     // if somehow we didn't get a local file but we did get a uri, 
  1405.     // attempt to create the localfile if it's a "file" url
  1406.     var docURI;
  1407.     if (!tempLocalFile)
  1408.     {
  1409.       docURI = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIURI);
  1410.       docURI.spec = urlstring;
  1411.       
  1412.       if (docURI.schemeIs("file"))
  1413.       {
  1414.         tempLocalFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
  1415.         ioService = GetIOService();
  1416.         ioService.initFileFromURLSpec(tempLocalFile, urlstring);
  1417.       }
  1418.     }
  1419.  
  1420.     // this is the location where the related files will go
  1421.     var parentDir = null;
  1422.     
  1423.     // First check pref for saving associated files
  1424.     var saveAssociatedFiles = false;
  1425.     try {
  1426.       var prefs = GetPrefs();
  1427.       saveAssociatedFiles = prefs.getBoolPref("editor.save_associated_files");
  1428.     } catch (e) {}
  1429.  
  1430.     // Only change links or move files if pref is set 
  1431.     //  and we are saving to a new location
  1432.     if (saveAssociatedFiles && aSaveAs)
  1433.     {
  1434.       try {
  1435.         if (tempLocalFile)
  1436.         {
  1437.           // if we are saving to the same parent directory, don't set parentDir
  1438.           // grab old location, chop off file
  1439.           // grab new location, chop off file, compare
  1440.           var oldLocation = GetDocumentUrl();
  1441.           var oldLocationLastSlash = oldLocation.lastIndexOf("\/");
  1442.           if (oldLocationLastSlash != -1)
  1443.             oldLocation = oldLocation.slice(0, oldLocationLastSlash);
  1444.  
  1445.           var curParentString = urlstring;
  1446.           var newLocationLastSlash = curParentString.lastIndexOf("\/");
  1447.           if (newLocationLastSlash != -1)
  1448.             curParentString = curParentString.slice(0, newLocationLastSlash);
  1449.           if (oldLocation == curParentString || IsUrlAboutBlank(oldLocation))
  1450.             parentDir = null;
  1451.           else
  1452.             parentDir = tempLocalFile.parent;  // this is wrong if parent is the root!
  1453.         }
  1454.         else
  1455.         {
  1456.           var lastSlash = urlstring.lastIndexOf("\/");
  1457.           if (lastSlash != -1)
  1458.           {
  1459.             var parentDirString = urlstring.slice(0, lastSlash + 1);  // include last slash
  1460.             ioService = GetIOService();
  1461.             parentDir = ioService.newURI(parentDirString, window.editorShell.GetDocumentCharacterSet(), null);
  1462.           }
  1463.         }
  1464.       } catch(e) { parentDir = null; }
  1465.     }
  1466.  
  1467.     var destinationLocation;
  1468.     if (tempLocalFile)
  1469.       destinationLocation = tempLocalFile;
  1470.     else
  1471.       destinationLocation = docURI;
  1472.  
  1473.     success = OutputFileWithPersistAPI(editorDoc, destinationLocation, parentDir, aMimeType);
  1474.   }
  1475.   catch (e)
  1476.   {
  1477.     success = false;
  1478.   }
  1479.  
  1480.   if (success)
  1481.   {
  1482.     try {
  1483.       window.editorShell.doAfterSave(doUpdateURL, urlstring);  // we need to update the url before notifying listeners
  1484.       if (!aSaveCopy)
  1485.         window.editorShell.editor.resetModificationCount();
  1486.       // this should cause notification to listeners that document has changed
  1487.  
  1488.       // Set UI based on whether we're editing a remote or local url
  1489.       SetSaveAndPublishUI(urlstring);
  1490.     } catch (e) {}
  1491.   }
  1492.   else
  1493.   {
  1494.     var saveDocStr = GetString("SaveDocument");
  1495.     var failedStr = GetString("SaveFileFailed");
  1496.     AlertWithTitle(saveDocStr, failedStr);
  1497.   }
  1498.   return success;
  1499. }
  1500.  
  1501.  
  1502. //-------------------------------  Publishing
  1503. var gPublishData;
  1504. var gProgressDialog;
  1505. var gCommandAfterPublishing = null;
  1506.  
  1507. function Publish(publishData)
  1508. {
  1509.   if (!publishData)
  1510.     return false;
  1511.  
  1512.   // Set data in global for username password requests
  1513.   //  and to do "post saving" actions after monitoring nsIWebProgressListener messages
  1514.   //  and we are sure file transfer was successful
  1515.   gPublishData = publishData;
  1516.  
  1517.   gPublishData.docURI = CreateURIFromPublishData(publishData, true);
  1518.   if (!gPublishData.docURI)
  1519.   {
  1520.     AlertWithTitle(GetString("Publish"), GetString("PublishFailed"));
  1521.     return false;
  1522.   }
  1523.  
  1524.   if (gPublishData.publishOtherFiles)
  1525.     gPublishData.otherFilesURI = CreateURIFromPublishData(publishData, false);
  1526.   else
  1527.     gPublishData.otherFilesURI = null;
  1528.  
  1529.   if (gShowDebugOutputStateChange)
  1530.   {
  1531.     dump("\n *** publishData: PublishUrl="+publishData.publishUrl+", BrowseUrl="+publishData.browseUrl+
  1532.       ", Username="+publishData.username+", Dir="+publishData.docDir+
  1533.       ", Filename="+publishData.filename+"\n");
  1534. //    dump(" * gPublishData.docURI.spec w/o pass="+StripPassword(gPublishData.docURI.spec)+", PublishOtherFiles="+gPublishData.publishOtherFiles+"\n");
  1535.     dump(" * gPublishData.docURI.spec w/o pass="+gPublishData.docURI.spec+", PublishOtherFiles="+gPublishData.publishOtherFiles+"\n");
  1536.   }
  1537.  
  1538.   // XXX Missing username will make FTP fail 
  1539.   // and it won't call us for prompt dialog (bug 132320)
  1540.   // (It does prompt if just password is missing)
  1541.   // So we should do the prompt ourselves before trying to publish
  1542.   if (GetScheme(publishData.publishUrl) == "ftp" && !publishData.username)
  1543.   {
  1544.     var message = GetString("PromptFTPUsernamePassword").replace(/%host%/, GetHost(publishData.publishUrl));
  1545.     var savePWobj = {value:publishData.savePassword};
  1546.     var userObj = {value:publishData.username};
  1547.     var pwObj = {value:publishData.password};
  1548.     if (!PromptUsernameAndPassword(GetString("Prompt"), message, savePWobj, userObj, pwObj))
  1549.       return false; // User canceled out of dialog
  1550.  
  1551.     // Reset data in URI objects
  1552.     gPublishData.docURI.username = publishData.username;
  1553.     gPublishData.docURI.password = publishData.password;
  1554.  
  1555.     if (gPublishData.otherFilesURI)
  1556.     {
  1557.       gPublishData.otherFilesURI.username = publishData.username;
  1558.       gPublishData.otherFilesURI.password = publishData.password;
  1559.     }
  1560.   }
  1561.  
  1562.   try {
  1563.     // We launch dialog as a dependent 
  1564.     // Don't allow editing document!
  1565.     SetDocumentEditable(false);
  1566.  
  1567.     // Start progress monitoring
  1568.     gProgressDialog =
  1569.       window.openDialog("chrome://editor/content/EditorPublishProgress.xul", "_blank",
  1570.                         "chrome,dependent,titlebar", gPublishData, gPersistObj);
  1571.  
  1572.   } catch (e) {}
  1573.  
  1574.   // Network transfer is often too quick for the progress dialog to be initialized
  1575.   //  and we can completely miss messages for quickly-terminated bad URLs,
  1576.   //  so we can't call OutputFileWithPersistAPI right away.
  1577.   // StartPublishing() is called at the end of the dialog's onload method
  1578.   return true;
  1579. }
  1580.  
  1581. function StartPublishing()
  1582. {
  1583.   if (gPublishData && gPublishData.docURI)
  1584.     OutputFileWithPersistAPI(window.editorShell.editorDocument, 
  1585.                              gPublishData.docURI, gPublishData.otherFilesURI, 
  1586.                              window.editorShell.contentsMIMEType);
  1587. }
  1588.  
  1589. function CancelPublishing()
  1590. {
  1591.   try {
  1592.     gPersistObj.cancelSave(); // Cancel all networking transactions
  1593.     gProgressDialog.SetProgressStatusCancel();
  1594.   } catch (e) {}
  1595.  
  1596.   // If canceling publishing do not do any commands after this    
  1597.   gCommandAfterPublishing = null;
  1598.  
  1599.   if (gProgressDialog)
  1600.   {
  1601.     // Close Progress dialog 
  1602.     // (this will call FinishPublishing())
  1603.     gProgressDialog.CloseDialog();
  1604.   }
  1605.   else
  1606.     FinishPublishing();
  1607. }
  1608.  
  1609. function FinishPublishing()
  1610. {
  1611.   SetDocumentEditable(true);
  1612.   gProgressDialog = null;
  1613.   gPublishData = null;
  1614.  
  1615.   if (gCommandAfterPublishing)
  1616.   {
  1617.     // Be sure to null out the global now incase of trouble when executing command
  1618.     var command = gCommandAfterPublishing;
  1619.     gCommandAfterPublishing = null;
  1620.     goDoCommand(command);
  1621.   }
  1622. }
  1623.  
  1624. // Create a nsIURI object filled in with all required publishing info
  1625. function CreateURIFromPublishData(publishData, doDocUri)
  1626. {
  1627.   if (!publishData || !publishData.publishUrl)
  1628.     return null;
  1629.  
  1630.   var URI;
  1631.   try {
  1632.     var spec = publishData.publishUrl;
  1633.     if (doDocUri)
  1634.       spec += FormatDirForPublishing(publishData.docDir) + publishData.filename; 
  1635.     else
  1636.       spec += FormatDirForPublishing(publishData.otherDir);
  1637.  
  1638.     var ioService = GetIOService();
  1639.     URI = ioService.newURI(spec, window.editorShell.GetDocumentCharacterSet(), null);
  1640.  
  1641.     if (publishData.username)
  1642.       URI.username = publishData.username;
  1643.     if (publishData.password)
  1644.       URI.password = publishData.password;
  1645.   }
  1646.   catch (e) {}
  1647.  
  1648.   return URI;
  1649. }
  1650.  
  1651. // Resolve the correct "http:" document URL when publishing via ftp
  1652. function GetDocUrlFromPublishData(publishData)
  1653. {
  1654.   if (!publishData || !publishData.filename || !publishData.publishUrl)
  1655.     return "";
  1656.  
  1657.   // If user was previously editing an "ftp" url, then keep that as the new scheme
  1658.   var url;
  1659.   var docScheme = GetScheme(GetDocumentUrl());
  1660.  
  1661.   // Always use the "HTTP" address if available
  1662.   // XXX Should we do some more validation here for bad urls???
  1663.   // Let's at least check for a scheme!
  1664.   if (!GetScheme(publishData.browseUrl))
  1665.     url = publishData.publishUrl;
  1666.   else
  1667.     url = publishData.browseUrl;
  1668.  
  1669.   url += FormatDirForPublishing(publishData.docDir) + publishData.filename;
  1670.  
  1671.   if (GetScheme(url) == "ftp")
  1672.     url = InsertUsernameIntoUrl(url, publishData.username);
  1673.  
  1674.   return url;
  1675. }
  1676.  
  1677. // Depending on editing local vs. remote files:
  1678. //   * Switch the "Save" and "Publish" buttons on toolbars,
  1679. //   * Shift accel+S keybinding to Save or Publish commands
  1680. // Note: A new, unsaved file is treated as a local file
  1681. //     (XXX Have a pref to treat as remote for user's who mostly edit remote?)
  1682. function SetSaveAndPublishUI(urlstring)
  1683. {
  1684.   // Associate the "save" keybinding with Save for local files, 
  1685.   //   or with Publish for remote files
  1686.   var scheme = GetScheme(urlstring);
  1687.   var menuItem1;
  1688.   var menuItem2;
  1689.   var saveButton = document.getElementById("saveButton");
  1690.   var publishButton = document.getElementById("publishButton");
  1691.   var command;
  1692.  
  1693.   if (!scheme || scheme == "file")
  1694.   {
  1695.     // Editing a new or local file
  1696.     menuItem1 = document.getElementById("publishMenuitem");
  1697.     menuItem2 = document.getElementById("saveMenuitem");
  1698.     command = "cmd_save";
  1699.  
  1700.     // Hide "Publish". Show "Save" toolbar and menu items
  1701.     SetElementHidden(publishButton, true);
  1702.     SetElementHidden(saveButton, false);
  1703.   }
  1704.   else
  1705.   {
  1706.     // Editing a remote file
  1707.     menuItem1 = document.getElementById("saveMenuitem");
  1708.     menuItem2 = document.getElementById("publishMenuitem");
  1709.     command = "cmd_publish";
  1710.  
  1711.     // Hide "Save", show "Publish" toolbar and menuitems
  1712.     SetElementHidden(saveButton, true);
  1713.     SetElementHidden(publishButton, false);
  1714.   }
  1715.  
  1716. //  Use this to hide "Save" menuitem if editing remote, Hide "Publish" if editing local
  1717. //  SetElementHidden(menuItem1, true);
  1718. //  SetElementHidden(menuItem2, false);
  1719.  
  1720.   var key = document.getElementById("savekb");
  1721.   if (key && command)
  1722.     key.setAttribute("observes", command);
  1723.  
  1724.   if (menuItem1 && menuItem2)
  1725.   {
  1726.     menuItem1.removeAttribute("key");
  1727.     menuItem2.setAttribute("key","savekb");
  1728.   }
  1729.  
  1730.   // Be sure enabled state of toolbar button is correct
  1731.   goUpdateCommand(command);
  1732. }
  1733.  
  1734. function SetDocumentEditable(isDocEditable)
  1735. {
  1736.   if (window.editorShell.editorDocument)
  1737.   {
  1738.     try {
  1739.       var flags = window.editorShell.editor.flags;
  1740.       window.editorShell.editor.flags = isDocEditable ?  
  1741.             flags &= ~nsIPlaintextEditor.eEditorReadonlyMask :
  1742.             flags | nsIPlaintextEditor.eEditorReadonlyMask;
  1743.     } catch(e) {}
  1744.  
  1745.     // update all commands
  1746.     window._content.focus();
  1747.     window.updateCommands("create");
  1748.   }  
  1749. }
  1750.  
  1751. // ****** end of save / publish **********//
  1752.  
  1753. //-----------------------------------------------------------------------------------
  1754. var nsPublishSettingsCommand =
  1755. {
  1756.   isCommandEnabled: function(aCommand, dummy)
  1757.   {
  1758.     return (window.editorShell && window.editorShell.documentEditable);
  1759.   },
  1760.  
  1761.   doCommand: function(aCommand)
  1762.   {
  1763.     if (window.editorShell)
  1764.     {
  1765.       // Launch Publish Settings dialog
  1766.  
  1767.       window.ok = window.openDialog("chrome://editor/content/EditorPublishSettings.xul","_blank", "chrome,close,titlebar,modal", "");
  1768.       window._content.focus();
  1769.       return window.ok;
  1770.     }
  1771.     return false;
  1772.   }
  1773. }
  1774.  
  1775. //-----------------------------------------------------------------------------------
  1776. var nsRevertCommand =
  1777. {
  1778.   isCommandEnabled: function(aCommand, dummy)
  1779.   {
  1780.     return (window.editorShell && window.editorShell.documentEditable &&
  1781.             window.editorShell.documentModified &&
  1782.             !IsUrlAboutBlank(GetDocumentUrl()));
  1783.   },
  1784.  
  1785.   doCommand: function(aCommand)
  1786.   {
  1787.     // Confirm with the user to abandon current changes
  1788.     var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  1789.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  1790.  
  1791.     if (promptService)
  1792.     {
  1793.       // Put the page title in the message string
  1794.       var title = window.editorShell.GetDocumentTitle();
  1795.       if (!title)
  1796.         title = GetString("untitled");
  1797.  
  1798.       var msg = GetString("AbandonChanges").replace(/%title%/,title);
  1799.  
  1800.       var result = promptService.confirmEx(window, GetString("RevertCaption"), msg,
  1801.                                 (promptService.BUTTON_TITLE_REVERT * promptService.BUTTON_POS_0) +
  1802.                                 (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
  1803.                                 null, null, null, null, {value:0});
  1804.  
  1805.       // Reload page if first button (Revert) was pressed
  1806.       if(result == 0)
  1807.       {
  1808.         FinishHTMLSource();
  1809.         window.editorShell.LoadUrl(GetDocumentUrl());
  1810.       }
  1811.     }
  1812.   }
  1813. };
  1814.  
  1815. //-----------------------------------------------------------------------------------
  1816. var nsCloseCommand =
  1817. {
  1818.   isCommandEnabled: function(aCommand, dummy)
  1819.   {
  1820.     return window.editorShell;
  1821.   },
  1822.   
  1823.   doCommand: function(aCommand)
  1824.   {
  1825.     CloseWindow();
  1826.   }
  1827. };
  1828.  
  1829. function CloseWindow()
  1830. {
  1831.   // Check to make sure document is saved. "true" means allow "Don't Save" button,
  1832.   //   so user can choose to close without saving
  1833.   if (CheckAndSaveDocument("cmd_close", true)) 
  1834.   {
  1835.     if (window.InsertCharWindow)
  1836.       SwitchInsertCharToAnotherEditorOrClose();
  1837.  
  1838.     window.editorShell.CloseWindowWithoutSaving();
  1839.   }
  1840. }
  1841.  
  1842. //-----------------------------------------------------------------------------------
  1843. var nsOpenRemoteCommand =
  1844. {
  1845.   isCommandEnabled: function(aCommand, dummy)
  1846.   {
  1847.     return true;    // we can always do this
  1848.   },
  1849.  
  1850.   doCommand: function(aCommand)
  1851.   {
  1852.       /* The last parameter is the current browser window.
  1853.          Use 0 and the default checkbox will be to load into an editor
  1854.          and loading into existing browser option is removed
  1855.        */
  1856.       window.openDialog( "chrome://communicator/content/openLocation.xul", "_blank", "chrome,modal,titlebar", 0);
  1857.     window._content.focus();
  1858.   }
  1859. };
  1860.  
  1861. //-----------------------------------------------------------------------------------
  1862. var nsPreviewCommand =
  1863. {
  1864.   isCommandEnabled: function(aCommand, dummy)
  1865.   {
  1866.     return (window.editorShell && window.editorShell.documentEditable && 
  1867.             IsEditorContentHTML() && 
  1868.             (DocumentHasBeenSaved() || window.editorShell.documentModified));
  1869.   },
  1870.  
  1871.   doCommand: function(aCommand)
  1872.   {
  1873.       // Don't continue if user canceled during prompt for saving
  1874.     // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
  1875.     if (!CheckAndSaveDocument("cmd_preview", DocumentHasBeenSaved()))
  1876.         return;
  1877.  
  1878.     // Check if we saved again just in case?
  1879.       if (DocumentHasBeenSaved())
  1880.     {
  1881.       var browser;
  1882.       try {
  1883.         // Find a browser with this URL
  1884.         var windowManager = Components.classes["@mozilla.org/rdf/datasource;1?name=window-mediator"].getService();
  1885.         var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
  1886.         var enumerator = windowManagerInterface.getEnumerator("navigator:browser");
  1887.  
  1888.         while ( enumerator.hasMoreElements() )
  1889.         {
  1890.           browser = windowManagerInterface.convertISupportsToDOMWindow( enumerator.getNext() );
  1891.           if ( browser && (window._content.location.href == browser._content.location.href))
  1892.             break;
  1893.  
  1894.           browser = null;
  1895.         }
  1896.       }
  1897.       catch (ex) {}
  1898.  
  1899.       // If none found, open a new browser
  1900.       if (!browser)
  1901.         browser = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", window._content.location);
  1902.  
  1903.       try {
  1904.         if (browser)
  1905.         {
  1906.           // Be sure browser contains real source content, not cached
  1907.           // setTimeout is needed because the "browser" created by openDialog 
  1908.           //    needs time to finish else BrowserReloadSkipCache doesn't exist
  1909.           setTimeout( function(browser) { browser.BrowserReloadSkipCache(); }, 10, browser );
  1910.           browser.focus();
  1911.         }
  1912.       } catch (ex) {}
  1913.     }
  1914.   }
  1915. };
  1916.  
  1917. //-----------------------------------------------------------------------------------
  1918. var nsSendPageCommand =
  1919. {
  1920.   isCommandEnabled: function(aCommand, dummy)
  1921.   {
  1922.     return (window.editorShell != null && window.editorShell.documentEditable &&
  1923.             (DocumentHasBeenSaved() || window.editorShell.documentModified));
  1924.   },
  1925.  
  1926.   doCommand: function(aCommand)
  1927.   {
  1928.       // Don't continue if user canceled during prompt for saving
  1929.     // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
  1930.     if (!CheckAndSaveDocument("cmd_editSendPage", DocumentHasBeenSaved()))
  1931.         return;
  1932.  
  1933.     // Check if we saved again just in case?
  1934.       if (DocumentHasBeenSaved())
  1935.     {
  1936.       // Launch Messenger Composer window with current page as contents
  1937.       var pageTitle = window.editorShell.editorDocument.title;
  1938.       var pageUrl = GetDocumentUrl();
  1939.       try
  1940.       {
  1941.         openComposeWindow(pageUrl, pageTitle);        
  1942.       } catch (ex) { dump("Cannot Send Page: " + ex + "\n"); }
  1943.     }
  1944.   }
  1945. };
  1946.  
  1947. //-----------------------------------------------------------------------------------
  1948. var nsPrintCommand =
  1949. {
  1950.   isCommandEnabled: function(aCommand, dummy)
  1951.   {
  1952.     return true;    // we can always do this
  1953.   },
  1954.  
  1955.   doCommand: function(aCommand)
  1956.   {
  1957.     // In editor.js
  1958.     FinishHTMLSource();
  1959.     try {
  1960.       window.editorShell.Print();
  1961.     } catch (e) {}
  1962.   }
  1963. };
  1964.  
  1965. //-----------------------------------------------------------------------------------
  1966. var nsPrintSetupCommand =
  1967. {
  1968.   isCommandEnabled: function(aCommand, dummy)
  1969.   {
  1970.     return true;    // we can always do this
  1971.   },
  1972.  
  1973.   doCommand: function(aCommand)
  1974.   {
  1975.     // In editor.js
  1976.     FinishHTMLSource();
  1977.     goPageSetup();
  1978.   }
  1979. };
  1980.  
  1981. //-----------------------------------------------------------------------------------
  1982. var nsQuitCommand =
  1983. {
  1984.   isCommandEnabled: function(aCommand, dummy)
  1985.   {
  1986.     return true;    // we can always do this
  1987.   },
  1988.  
  1989.   doCommand: function(aCommand)
  1990.   {
  1991.     // In editor.js
  1992.     FinishHTMLSource();
  1993.     goQuitApplication();
  1994.   }
  1995. };
  1996.  
  1997. //-----------------------------------------------------------------------------------
  1998. var nsFindCommand =
  1999. {
  2000.   isCommandEnabled: function(aCommand, dummy)
  2001.   {
  2002.     return ((window.editorShell));
  2003.   },
  2004.  
  2005.   doCommand: function(aCommand)
  2006.   {
  2007.     var prefs = GetPrefs();
  2008.     var newfind;
  2009.     if (prefs) {
  2010.       try {
  2011.         newfind = prefs.getBoolPref("editor.new_find");
  2012.       }
  2013.       catch (ex) {
  2014.         newfind = false;
  2015.       }
  2016.     }
  2017.     
  2018.     if (newfind)
  2019.     {
  2020.       try {
  2021.         window.openDialog("chrome://editor/content/EdReplace.xul", "_blank",
  2022.                           "chrome,dependent,titlebar", "");
  2023.       }
  2024.       catch(ex) {
  2025.         dump("*** Exception: couldn't open Replace Dialog\n");
  2026.       }
  2027.       window._content.focus();
  2028.     }
  2029.     else {
  2030.       window.editorShell.Replace();
  2031.     }
  2032.   }
  2033. };
  2034.  
  2035. //-----------------------------------------------------------------------------------
  2036. var nsFindNextCommand =
  2037. {
  2038.   isCommandEnabled: function(aCommand, dummy)
  2039.   {
  2040.     // we can only do this if the search pattern is non-empty. Not sure how
  2041.     // to get that from here
  2042.     return (window.editorShell && !IsInHTMLSourceMode());
  2043.   },
  2044.  
  2045.   doCommand: function(aCommand)
  2046.   {
  2047.     var prefs = GetPrefs();
  2048.     var newfind;
  2049.     if (prefs) {
  2050.       try {
  2051.         newfind = prefs.getBoolPref("editor.new_find");
  2052.       }
  2053.       catch (ex) {
  2054.         newfind = false;
  2055.       }
  2056.     }
  2057.     if (newfind)
  2058.     {
  2059.       try {
  2060.         var editorXUL = document.getElementById("content-frame");
  2061.         var findInst = editorXUL.webBrowserFind;
  2062.         findInst.findNext();
  2063.       }
  2064.       catch (ex) {
  2065.         nsFindCommand.doCommand();
  2066.       }
  2067.     }
  2068.     else {
  2069.       window.editorShell.FindNext();
  2070.     }
  2071.   }
  2072. };
  2073.  
  2074. //-----------------------------------------------------------------------------------
  2075. var nsSpellingCommand =
  2076. {
  2077.   isCommandEnabled: function(aCommand, dummy)
  2078.   {
  2079.     return (window.editorShell && window.editorShell.documentEditable && 
  2080.             !IsInHTMLSourceMode() && IsSpellCheckerInstalled());
  2081.   },
  2082.  
  2083.   doCommand: function(aCommand)
  2084.   {
  2085.     window.cancelSendMessage = false;
  2086.     try {
  2087.       window.openDialog("chrome://editor/content/EdSpellCheck.xul", "_blank",
  2088.               "chrome,close,titlebar,modal", false);
  2089.     }
  2090.     catch(ex) {}
  2091.     window._content.focus();
  2092.   }
  2093. };
  2094.  
  2095. // Validate using http://validator.w3.org/file-upload.html
  2096. var URL2Validate;
  2097. var nsValidateCommand =
  2098. {
  2099.   isCommandEnabled: function(aCommand, dummy)
  2100.   {
  2101.     return (window.editorShell != null);
  2102.   },
  2103.  
  2104.   doCommand: function(aCommand)
  2105.   {
  2106.     // If the document hasn't been modified,
  2107.     // then just validate the current url.
  2108.     if (editorShell.documentModified || gHTMLSourceChanged)
  2109.     {
  2110.       if (!CheckAndSaveDocument("cmd_validate", false))
  2111.         return;
  2112.  
  2113.       // Check if we saved again just in case?
  2114.       if (!DocumentHasBeenSaved())    // user hit cancel?
  2115.         return;
  2116.     }
  2117.  
  2118.     URL2Validate = GetDocumentUrl();
  2119.     // See if it's a file:
  2120.     var ifile = Components.classes["@mozilla.org/file/local;1"].createInstance().QueryInterface(Components.interfaces.nsIFile);
  2121.     try {
  2122.       var ioService = GetIOService();
  2123.       ioService.initFileFromURLSpec(ifile, URL2Validate);
  2124.       // nsIFile throws an exception if it's not a file url
  2125.     } catch (e) { ifile = null; }
  2126.     if (ifile)
  2127.     {
  2128.       URL2Validate = ifile.path;
  2129.       var vwin = window.open("http://validator.w3.org/file-upload.html",
  2130.                              "EditorValidate");
  2131.       // Window loads asynchronously, so pass control to the load listener:
  2132.       vwin.addEventListener("load", this.validateFilePageLoaded, false);
  2133.     }
  2134.     else
  2135.     {
  2136.       var vwin2 = window.open("http://validator.w3.org/check?uri="
  2137.                               + URL2Validate
  2138.                               + "&doctype=Inline",
  2139.                               "EditorValidate");
  2140.       // This does the validation, no need to wait for page loaded.
  2141.     }
  2142.   },
  2143.   validateFilePageLoaded: function(event)
  2144.   {
  2145.     event.target.forms[0].uploaded_file.value = URL2Validate;
  2146.   }
  2147. };
  2148.  
  2149. var nsCheckLinksCommand =
  2150. {
  2151.   isCommandEnabled: function(aCommand, dummy)
  2152.   {
  2153.     return (window.editorShell && window.editorShell.documentEditable);
  2154.   },
  2155.  
  2156.   doCommand: function(aCommand)
  2157.   {
  2158.     window.openDialog("chrome://editor/content/EdLinkChecker.xul","_blank", "chrome,close,titlebar,modal");
  2159.     window._content.focus();
  2160.   }
  2161. };
  2162.  
  2163. //-----------------------------------------------------------------------------------
  2164. var nsFormCommand =
  2165. {
  2166.   isCommandEnabled: function(aCommand, dummy)
  2167.   {
  2168.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2169.   },
  2170.   doCommand: function(aCommand)
  2171.   {
  2172.     window.openDialog("chrome://editor/content/EdFormProps.xul", "_blank", "chrome,close,titlebar,modal");
  2173.     window._content.focus();
  2174.   }
  2175. };
  2176.  
  2177. //-----------------------------------------------------------------------------------
  2178. var nsInputTagCommand =
  2179. {
  2180.   isCommandEnabled: function(aCommand, dummy)
  2181.   {
  2182.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2183.   },
  2184.   doCommand: function(aCommand)
  2185.   {
  2186.     window.openDialog("chrome://editor/content/EdInputProps.xul", "_blank", "chrome,close,titlebar,modal");
  2187.     window._content.focus();
  2188.   }
  2189. };
  2190.  
  2191. //-----------------------------------------------------------------------------------
  2192. var nsInputImageCommand =
  2193. {
  2194.   isCommandEnabled: function(aCommand, dummy)
  2195.   {
  2196.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2197.   },
  2198.   doCommand: function(aCommand)
  2199.   {
  2200.     window.openDialog("chrome://editor/content/EdInputImage.xul", "_blank", "chrome,close,titlebar,modal");
  2201.     window._content.focus();
  2202.   }
  2203. };
  2204.  
  2205. //-----------------------------------------------------------------------------------
  2206. var nsTextAreaCommand =
  2207. {
  2208.   isCommandEnabled: function(aCommand, dummy)
  2209.   {
  2210.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2211.   },
  2212.   doCommand: function(aCommand)
  2213.   {
  2214.     window.openDialog("chrome://editor/content/EdTextAreaProps.xul", "_blank", "chrome,close,titlebar,modal");
  2215.     window._content.focus();
  2216.   }
  2217. };
  2218.  
  2219. //-----------------------------------------------------------------------------------
  2220. var nsSelectCommand =
  2221. {
  2222.   isCommandEnabled: function(aCommand, dummy)
  2223.   {
  2224.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2225.   },
  2226.   doCommand: function(aCommand)
  2227.   {
  2228.     window.openDialog("chrome://editor/content/EdSelectProps.xul", "_blank", "chrome,close,titlebar,modal");
  2229.     window._content.focus();
  2230.   }
  2231. };
  2232.  
  2233. //-----------------------------------------------------------------------------------
  2234. var nsButtonCommand =
  2235. {
  2236.   isCommandEnabled: function(aCommand, dummy)
  2237.   {
  2238.     // && !editorShell.editorSelection.isCollapsed()?
  2239.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2240.   },
  2241.   doCommand: function(aCommand)
  2242.   {
  2243.     window.openDialog("chrome://editor/content/EdButtonProps.xul", "_blank", "chrome,close,titlebar,modal");
  2244.     window._content.focus();
  2245.   }
  2246. };
  2247.  
  2248. //-----------------------------------------------------------------------------------
  2249. var nsLabelCommand =
  2250. {
  2251.   isCommandEnabled: function(aCommand, dummy)
  2252.   {
  2253.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2254.   },
  2255.   doCommand: function(aCommand)
  2256.   {
  2257.     var tagName = "label";
  2258.     var labelElement = editorShell.GetSelectedElement(tagName);
  2259.     if (!labelElement)
  2260.       labelElement = editorShell.GetElementOrParentByTagName(tagName, editorShell.editorSelection.anchorNode);
  2261.     if (!labelElement)
  2262.       labelElement = editorShell.GetElementOrParentByTagName(tagName, editorShell.editorSelection.focusNode);
  2263.     if (labelElement) {
  2264.       // We only open the dialog for an existing label
  2265.       window.openDialog("chrome://editor/content/EdLabelProps.xul", "_blank", "chrome,close,titlebar,modal", labelElement);
  2266.       window._content.focus();
  2267.     } else {
  2268.       editorShell.SetTextProperty(tagName, "", "");
  2269.     }
  2270.   }
  2271. };
  2272.  
  2273. //-----------------------------------------------------------------------------------
  2274. var nsFieldSetCommand =
  2275. {
  2276.   isCommandEnabled: function(aCommand, dummy)
  2277.   {
  2278.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2279.   },
  2280.   doCommand: function(aCommand)
  2281.   {
  2282.     window.openDialog("chrome://editor/content/EdFieldSetProps.xul", "_blank", "chrome,close,titlebar,modal");
  2283.     window._content.focus();
  2284.   }
  2285. };
  2286.  
  2287. //-----------------------------------------------------------------------------------
  2288. var nsIsIndexCommand =
  2289. {
  2290.   isCommandEnabled: function(aCommand, dummy)
  2291.   {
  2292.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2293.   },
  2294.   doCommand: function(aCommand)
  2295.   {
  2296.     var isindexElement = editorShell.CreateElementWithDefaults("isindex");
  2297.     isindexElement.setAttribute("prompt", editorShell.GetContentsAs("text/plain", 1)); // OutputSelectionOnly
  2298.     editorShell.InsertElementAtSelection(isindexElement, true);
  2299.   }
  2300. };
  2301.  
  2302. //-----------------------------------------------------------------------------------
  2303. var nsImageCommand =
  2304. {
  2305.   isCommandEnabled: function(aCommand, dummy)
  2306.   {
  2307.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2308.   },
  2309.   doCommand: function(aCommand)
  2310.   {
  2311.     window.openDialog("chrome://editor/content/EdImageProps.xul","_blank", "chrome,close,titlebar,modal");
  2312.     window._content.focus();
  2313.   }
  2314. };
  2315.  
  2316. //-----------------------------------------------------------------------------------
  2317. var nsHLineCommand =
  2318. {
  2319.   isCommandEnabled: function(aCommand, dummy)
  2320.   {
  2321.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2322.   },
  2323.   doCommand: function(aCommand)
  2324.   {
  2325.     // Inserting an HLine is different in that we don't use properties dialog
  2326.     //  unless we are editing an existing line's attributes
  2327.     //  We get the last-used attributes from the prefs and insert immediately
  2328.  
  2329.     var tagName = "hr";
  2330.     var hLine = window.editorShell.GetSelectedElement(tagName);
  2331.  
  2332.     if (hLine) {
  2333.       // We only open the dialog for an existing HRule
  2334.       window.openDialog("chrome://editor/content/EdHLineProps.xul", "_blank", "chrome,close,titlebar,modal");
  2335.       window._content.focus();
  2336.     } else {
  2337.       hLine = window.editorShell.CreateElementWithDefaults(tagName);
  2338.  
  2339.       if (hLine) {
  2340.         // We change the default attributes to those saved in the user prefs
  2341.         var prefs = GetPrefs();
  2342.         if (prefs) {
  2343.           try {
  2344.             var align = prefs.getIntPref("editor.hrule.align");
  2345.             if (align == 0 ) {
  2346.               hLine.setAttribute("align", "left");
  2347.             } else if (align == 2) {
  2348.               hLine.setAttribute("align", "right");
  2349.             }
  2350.  
  2351.             //Note: Default is center (don't write attribute)
  2352.         
  2353.             var width = prefs.getIntPref("editor.hrule.width");
  2354.             var percent = prefs.getBoolPref("editor.hrule.width_percent");
  2355.             if (percent)
  2356.               width = width +"%";
  2357.  
  2358.             hLine.setAttribute("width", width);
  2359.  
  2360.             var height = prefs.getIntPref("editor.hrule.height");
  2361.             hLine.setAttribute("size", String(height));
  2362.  
  2363.             var shading = prefs.getBoolPref("editor.hrule.shading");
  2364.             if (shading) {
  2365.               hLine.removeAttribute("noshade");
  2366.             } else {
  2367.               hLine.setAttribute("noshade", "noshade");
  2368.             }
  2369.           }
  2370.           catch (ex) {
  2371.             dump("failed to get HLine prefs\n");
  2372.           }
  2373.         }
  2374.         try {
  2375.           window.editorShell.InsertElementAtSelection(hLine, true);
  2376.         } catch (e) {
  2377.           dump("Exception occured in InsertElementAtSelection\n");
  2378.         }
  2379.       }
  2380.     }
  2381.   }
  2382. };
  2383.  
  2384. //-----------------------------------------------------------------------------------
  2385. var nsLinkCommand =
  2386. {
  2387.   isCommandEnabled: function(aCommand, dummy)
  2388.   {
  2389.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2390.   },
  2391.   doCommand: function(aCommand)
  2392.   {
  2393.     window.openDialog("chrome://editor/content/EdLinkProps.xul","_blank", "chrome,close,titlebar,modal");
  2394.     window._content.focus();
  2395.   }
  2396. };
  2397.  
  2398. //-----------------------------------------------------------------------------------
  2399. var nsAnchorCommand =
  2400. {
  2401.   isCommandEnabled: function(aCommand, dummy)
  2402.   {
  2403.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2404.   },
  2405.   doCommand: function(aCommand)
  2406.   {
  2407.     window.openDialog("chrome://editor/content/EdNamedAnchorProps.xul", "_blank", "chrome,close,titlebar,modal", "");
  2408.     window._content.focus();
  2409.   }
  2410. };
  2411.  
  2412. //-----------------------------------------------------------------------------------
  2413. var nsInsertHTMLCommand =
  2414. {
  2415.   isCommandEnabled: function(aCommand, dummy)
  2416.   {
  2417.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2418.   },
  2419.   doCommand: function(aCommand)
  2420.   {
  2421.     window.openDialog("chrome://editor/content/EdInsSrc.xul","_blank", "chrome,close,titlebar,modal,resizable", "");
  2422.     window._content.focus();
  2423.   }
  2424. };
  2425.  
  2426. //-----------------------------------------------------------------------------------
  2427. var nsInsertCharsCommand =
  2428. {
  2429.   isCommandEnabled: function(aCommand, dummy)
  2430.   {
  2431.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2432.   },
  2433.   doCommand: function(aCommand)
  2434.   {
  2435.     EditorFindOrCreateInsertCharWindow();
  2436.   }
  2437. };
  2438.  
  2439. //-----------------------------------------------------------------------------------
  2440. var nsInsertBreakCommand =
  2441. {
  2442.   isCommandEnabled: function(aCommand, dummy)
  2443.   {
  2444.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2445.   },
  2446.   doCommand: function(aCommand)
  2447.   {
  2448.     window.editorShell.InsertSource("<br>");
  2449.   }
  2450. };
  2451.  
  2452. //-----------------------------------------------------------------------------------
  2453. var nsInsertBreakAllCommand =
  2454. {
  2455.   isCommandEnabled: function(aCommand, dummy)
  2456.   {
  2457.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2458.   },
  2459.   doCommand: function(aCommand)
  2460.   {
  2461.     window.editorShell.InsertSource("<br clear='all'>");
  2462.   }
  2463. };
  2464.  
  2465. //-----------------------------------------------------------------------------------
  2466. var nsListPropertiesCommand =
  2467. {
  2468.   isCommandEnabled: function(aCommand, dummy)
  2469.   {
  2470.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2471.   },
  2472.   doCommand: function(aCommand)
  2473.   {
  2474.     window.openDialog("chrome://editor/content/EdListProps.xul","_blank", "chrome,close,titlebar,modal");
  2475.     window._content.focus();
  2476.   }
  2477. };
  2478.  
  2479.  
  2480. //-----------------------------------------------------------------------------------
  2481. var nsPagePropertiesCommand =
  2482. {
  2483.   isCommandEnabled: function(aCommand, dummy)
  2484.   {
  2485.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2486.   },
  2487.   doCommand: function(aCommand)
  2488.   {
  2489.     window.openDialog("chrome://editor/content/EdPageProps.xul","_blank", "chrome,close,titlebar,modal", "");
  2490.     window._content.focus();
  2491.   }
  2492. };
  2493.  
  2494. //-----------------------------------------------------------------------------------
  2495. var nsObjectPropertiesCommand =
  2496. {
  2497.   isCommandEnabled: function(aCommand, dummy)
  2498.   {
  2499.     var isEnabled = false;
  2500.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  2501.     {
  2502.       isEnabled = (GetObjectForProperties() != null ||
  2503.                    window.editorShell.GetSelectedElement("href") != null);
  2504.     }
  2505.     return isEnabled;
  2506.   },
  2507.   doCommand: function(aCommand)
  2508.   {
  2509.     // Launch Object properties for appropriate selected element 
  2510.     var element = GetObjectForProperties();
  2511.     if (element)
  2512.     {
  2513.       var name = element.nodeName.toLowerCase();
  2514.       switch (name)
  2515.       {
  2516.         case 'img':
  2517.           goDoCommand("cmd_image");
  2518.           break;
  2519.         case 'hr':
  2520.           goDoCommand("cmd_hline");
  2521.           break;
  2522.         case 'form':
  2523.           goDoCommand("cmd_form");
  2524.           break;
  2525.         case 'input':
  2526.           var type = element.getAttribute("type");
  2527.           if (type && type.toLowerCase() == "image")
  2528.             goDoCommand("cmd_inputimage");
  2529.           else
  2530.             goDoCommand("cmd_inputtag");
  2531.           break;
  2532.         case 'textarea':
  2533.           goDoCommand("cmd_textarea");
  2534.           break;
  2535.         case 'select':
  2536.           goDoCommand("cmd_select");
  2537.           break;
  2538.         case 'button':
  2539.           goDoCommand("cmd_button");
  2540.           break;
  2541.         case 'label':
  2542.           goDoCommand("cmd_label");
  2543.           break;
  2544.         case 'fieldset':
  2545.           goDoCommand("cmd_fieldset");
  2546.           break;
  2547.         case 'table':
  2548.           EditorInsertOrEditTable(false);
  2549.           break;
  2550.         case 'td':
  2551.         case 'th':
  2552.           EditorTableCellProperties();
  2553.           break;
  2554.         case 'ol':
  2555.         case 'ul':
  2556.         case 'dl':
  2557.         case 'li':
  2558.           goDoCommand("cmd_listProperties");
  2559.           break;
  2560.         case 'a':
  2561.           if (element.name)
  2562.           {
  2563.             goDoCommand("cmd_anchor");
  2564.           }
  2565.           else if(element.href)
  2566.           {
  2567.             goDoCommand("cmd_link");
  2568.           }
  2569.           break;
  2570.         default:
  2571.           doAdvancedProperties(element);
  2572.           break;
  2573.       }
  2574.     } else {
  2575.       // We get a partially-selected link if asked for specifically
  2576.       element = window.editorShell.GetSelectedElement("href");
  2577.       if (element)
  2578.         goDoCommand("cmd_link");
  2579.     }
  2580.     window._content.focus();
  2581.   }
  2582. };
  2583.  
  2584.  
  2585. //-----------------------------------------------------------------------------------
  2586. var nsSetSmiley =
  2587. {
  2588.   isCommandEnabled: function(aCommand, dummy)
  2589.   {
  2590.     return ( window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2591.  
  2592.   },
  2593.  
  2594.   doCommand: function(aCommand)
  2595.   {
  2596.     
  2597.     var commandNode = document.getElementById(aCommand);
  2598.     var smileyCode = commandNode.getAttribute("state");
  2599.  
  2600.     var strSml;
  2601.     switch(smileyCode)
  2602.     {
  2603.         case ":-)": strSml="s1"; 
  2604.         break;
  2605.         case ":-(": strSml="s2";
  2606.         break;
  2607.         case ";-)": strSml="s3";
  2608.         break;
  2609.         case ":-P": strSml="s4";
  2610.         break;
  2611.         case ":-D": strSml="s5";
  2612.         break;
  2613.         case ":-[": strSml="s6";
  2614.         break;
  2615.         case ":-\\": strSml="s7";
  2616.         break;
  2617.         default:    strSml="";
  2618.         break;
  2619.     }
  2620.  
  2621.     try 
  2622.     {
  2623.       var selection = window.editorShell.editorSelection;
  2624.  
  2625.       if (!selection)
  2626.         return;
  2627.     
  2628.       var extElement = editorShell.CreateElementWithDefaults("span");
  2629.       if (!extElement)
  2630.         return;
  2631.     
  2632.       extElement.setAttribute("class", "moz-smiley-" + strSml);
  2633.  
  2634.     
  2635.       var intElement = editorShell.CreateElementWithDefaults("span");
  2636.       if (!intElement)
  2637.         return;
  2638.  
  2639.       //just for mailnews, because of the way it removes HTML
  2640.       var smileButMenu = document.getElementById('smileButtonMenu');      
  2641.       if (smileButMenu.getAttribute("padwithspace"))
  2642.          smileyCode = " " + smileyCode + " ";
  2643.  
  2644.       var txtElement =  document.createTextNode(smileyCode);
  2645.       if (!txtElement)
  2646.         return;
  2647.  
  2648.       intElement.appendChild (txtElement);
  2649.       extElement.appendChild (intElement);
  2650.  
  2651.  
  2652.       editorShell.InsertElementAtSelection(extElement,true);
  2653.       window._content.focus();        
  2654.  
  2655.     } 
  2656.     catch (e) 
  2657.     {
  2658.         dump("Exception occured in smiley InsertElementAtSelection\n");
  2659.     }
  2660.     
  2661.   }
  2662.  
  2663. };
  2664.  
  2665.  
  2666. function doAdvancedProperties(element)
  2667. {
  2668.   if (element)
  2669.   {
  2670.     window.openDialog("chrome://editor/content/EdAdvancedEdit.xul", "_blank", "chrome,close,titlebar,modal,resizable=yes", "", element);
  2671.     window._content.focus();
  2672.   }
  2673. }
  2674.  
  2675. var nsAdvancedPropertiesCommand =
  2676. {
  2677.   isCommandEnabled: function(aCommand, dummy)
  2678.   {
  2679.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2680.   },
  2681.   doCommand: function(aCommand)
  2682.   {
  2683.     // Launch AdvancedEdit dialog for the selected element
  2684.     var element = window.editorShell.GetSelectedElement("");
  2685.     doAdvancedProperties(element);
  2686.   }
  2687. };
  2688.  
  2689. //-----------------------------------------------------------------------------------
  2690. var nsColorPropertiesCommand =
  2691. {
  2692.   isCommandEnabled: function(aCommand, dummy)
  2693.   {
  2694.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2695.   },
  2696.   doCommand: function(aCommand)
  2697.   {
  2698.     window.openDialog("chrome://editor/content/EdColorProps.xul","_blank", "chrome,close,titlebar,modal", ""); 
  2699.     UpdateDefaultColors(); 
  2700.     window._content.focus();
  2701.   }
  2702. };
  2703.  
  2704. //-----------------------------------------------------------------------------------
  2705. var nsRemoveLinksCommand =
  2706. {
  2707.   isCommandEnabled: function(aCommand, dummy)
  2708.   {
  2709.     // We could see if there's any link in selection, but it doesn't seem worth the work!
  2710.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2711.   },
  2712.   doCommand: function(aCommand)
  2713.   {
  2714.     window.editorShell.RemoveTextProperty("href", "");
  2715.     window._content.focus();
  2716.   }
  2717. };
  2718.  
  2719.  
  2720. //-----------------------------------------------------------------------------------
  2721. var nsRemoveNamedAnchorsCommand =
  2722. {
  2723.   isCommandEnabled: function(aCommand, dummy)
  2724.   {
  2725.     // We could see if there's any link in selection, but it doesn't seem worth the work!
  2726.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2727.   },
  2728.   doCommand: function(aCommand)
  2729.   {
  2730.     window.editorShell.RemoveTextProperty("name", "");
  2731.     window._content.focus();
  2732.   }
  2733. };
  2734.  
  2735.  
  2736. //-----------------------------------------------------------------------------------
  2737. var nsEditLinkCommand =
  2738. {
  2739.   isCommandEnabled: function(aCommand, dummy)
  2740.   {
  2741.     // Not really used -- this command is only in context menu, and we do enabling there
  2742.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2743.   },
  2744.   doCommand: function(aCommand)
  2745.   {
  2746.     var element = window.editorShell.GetSelectedElement("href");
  2747.     if (element)
  2748.       editPage(element.href, window, false);
  2749.  
  2750.     window._content.focus();
  2751.   }
  2752. };
  2753.  
  2754.  
  2755. //-----------------------------------------------------------------------------------
  2756. var nsNormalModeCommand =
  2757. {
  2758.   isCommandEnabled: function(aCommand, dummy)
  2759.   {
  2760.     return IsEditorContentHTML() && window.editorShell.documentEditable;
  2761.   },
  2762.   doCommand: function(aCommand)
  2763.   {
  2764.     if (gEditorDisplayMode != DisplayModeNormal)
  2765.       SetEditMode(DisplayModeNormal);
  2766.   }
  2767. };
  2768.  
  2769. var nsAllTagsModeCommand =
  2770. {
  2771.   isCommandEnabled: function(aCommand, dummy)
  2772.   {
  2773.     return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML());
  2774.   },
  2775.   doCommand: function(aCommand)
  2776.   {
  2777.     if (gEditorDisplayMode != DisplayModeAllTags)
  2778.       SetEditMode(DisplayModeAllTags);
  2779.   }
  2780. };
  2781.  
  2782. var nsHTMLSourceModeCommand =
  2783. {
  2784.   isCommandEnabled: function(aCommand, dummy)
  2785.   {
  2786.     return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML());
  2787.   },
  2788.   doCommand: function(aCommand)
  2789.   {
  2790.     if (gEditorDisplayMode != DisplayModeSource)
  2791.       SetEditMode(DisplayModeSource);
  2792.   }
  2793. };
  2794.  
  2795. var nsPreviewModeCommand =
  2796. {
  2797.   isCommandEnabled: function(aCommand, dummy)
  2798.   {
  2799.     return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML());
  2800.   },
  2801.   doCommand: function(aCommand)
  2802.   {
  2803.     FinishHTMLSource();
  2804.     if (gEditorDisplayMode != DisplayModePreview)
  2805.       SetEditMode(DisplayModePreview);
  2806.   }
  2807. };
  2808.  
  2809. //-----------------------------------------------------------------------------------
  2810. var nsInsertOrEditTableCommand =
  2811. {
  2812.   isCommandEnabled: function(aCommand, dummy)
  2813.   {
  2814.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  2815.   },
  2816.   doCommand: function(aCommand)
  2817.   {
  2818.     if (IsInTableCell())
  2819.       EditorTableCellProperties();
  2820.     else
  2821.       EditorInsertOrEditTable(true);
  2822.   }
  2823. };
  2824.  
  2825. //-----------------------------------------------------------------------------------
  2826. var nsEditTableCommand =
  2827. {
  2828.   isCommandEnabled: function(aCommand, dummy)
  2829.   {
  2830.     return IsInTable();
  2831.   },
  2832.   doCommand: function(aCommand)
  2833.   {
  2834.     EditorInsertOrEditTable(false);
  2835.   }
  2836. };
  2837.  
  2838. //-----------------------------------------------------------------------------------
  2839. var nsSelectTableCommand =
  2840. {
  2841.   isCommandEnabled: function(aCommand, dummy)
  2842.   {
  2843.     return IsInTable();
  2844.   },
  2845.   doCommand: function(aCommand)
  2846.   {
  2847.     window.editorShell.SelectTable();
  2848.     window._content.focus();
  2849.   }
  2850. };
  2851.  
  2852. var nsSelectTableRowCommand =
  2853. {
  2854.   isCommandEnabled: function(aCommand, dummy)
  2855.   {
  2856.     return IsInTableCell();
  2857.   },
  2858.   doCommand: function(aCommand)
  2859.   {
  2860.     window.editorShell.SelectTableRow();
  2861.     window._content.focus();
  2862.   }
  2863. };
  2864.  
  2865. var nsSelectTableColumnCommand =
  2866. {
  2867.   isCommandEnabled: function(aCommand, dummy)
  2868.   {
  2869.     return IsInTableCell();
  2870.   },
  2871.   doCommand: function(aCommand)
  2872.   {
  2873.     window.editorShell.SelectTableColumn();
  2874.     window._content.focus();
  2875.   }
  2876. };
  2877.  
  2878. var nsSelectTableCellCommand =
  2879. {
  2880.   isCommandEnabled: function(aCommand, dummy)
  2881.   {
  2882.     return IsInTableCell();
  2883.   },
  2884.   doCommand: function(aCommand)
  2885.   {
  2886.     window.editorShell.SelectTableCell();
  2887.     window._content.focus();
  2888.   }
  2889. };
  2890.  
  2891. var nsSelectAllTableCellsCommand =
  2892. {
  2893.   isCommandEnabled: function(aCommand, dummy)
  2894.   {
  2895.     return IsInTable();
  2896.   },
  2897.   doCommand: function(aCommand)
  2898.   {
  2899.     window.editorShell.SelectAllTableCells();
  2900.     window._content.focus();
  2901.   }
  2902. };
  2903.  
  2904. //-----------------------------------------------------------------------------------
  2905. var nsInsertTableCommand =
  2906. {
  2907.   isCommandEnabled: function(aCommand, dummy)
  2908.   {
  2909.     return window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML();
  2910.   },
  2911.   doCommand: function(aCommand)
  2912.   {
  2913.     EditorInsertTable();
  2914.   }
  2915. };
  2916.  
  2917. var nsInsertTableRowAboveCommand =
  2918. {
  2919.   isCommandEnabled: function(aCommand, dummy)
  2920.   {
  2921.     return IsInTableCell();
  2922.   },
  2923.   doCommand: function(aCommand)
  2924.   {
  2925.     window.editorShell.InsertTableRow(1, false);
  2926.     window._content.focus();
  2927.   }
  2928. };
  2929.  
  2930. var nsInsertTableRowBelowCommand =
  2931. {
  2932.   isCommandEnabled: function(aCommand, dummy)
  2933.   {
  2934.     return IsInTableCell();
  2935.   },
  2936.   doCommand: function(aCommand)
  2937.   {
  2938.     window.editorShell.InsertTableRow(1,true);
  2939.     window._content.focus();
  2940.   }
  2941. };
  2942.  
  2943. var nsInsertTableColumnBeforeCommand =
  2944. {
  2945.   isCommandEnabled: function(aCommand, dummy)
  2946.   {
  2947.     return IsInTableCell();
  2948.   },
  2949.   doCommand: function(aCommand)
  2950.   {
  2951.     window.editorShell.InsertTableColumn(1, false);
  2952.     window._content.focus();
  2953.   }
  2954. };
  2955.  
  2956. var nsInsertTableColumnAfterCommand =
  2957. {
  2958.   isCommandEnabled: function(aCommand, dummy)
  2959.   {
  2960.     return IsInTableCell();
  2961.   },
  2962.   doCommand: function(aCommand)
  2963.   {
  2964.     window.editorShell.InsertTableColumn(1, true);
  2965.     window._content.focus();
  2966.   }
  2967. };
  2968.  
  2969. var nsInsertTableCellBeforeCommand =
  2970. {
  2971.   isCommandEnabled: function(aCommand, dummy)
  2972.   {
  2973.     return IsInTableCell();
  2974.   },
  2975.   doCommand: function(aCommand)
  2976.   {
  2977.     window.editorShell.InsertTableCell(1, false);
  2978.   }
  2979. };
  2980.  
  2981. var nsInsertTableCellAfterCommand =
  2982. {
  2983.   isCommandEnabled: function(aCommand, dummy)
  2984.   {
  2985.     return IsInTableCell();
  2986.   },
  2987.   doCommand: function(aCommand)
  2988.   {
  2989.     window.editorShell.InsertTableCell(1, true);
  2990.     window._content.focus();
  2991.   }
  2992. };
  2993.  
  2994. //-----------------------------------------------------------------------------------
  2995. var nsDeleteTableCommand =
  2996. {
  2997.   isCommandEnabled: function(aCommand, dummy)
  2998.   {
  2999.     return IsInTable();
  3000.   },
  3001.   doCommand: function(aCommand)
  3002.   {
  3003.     window.editorShell.DeleteTable();        
  3004.     window._content.focus();
  3005.   }
  3006. };
  3007.  
  3008. var nsDeleteTableRowCommand =
  3009. {
  3010.   isCommandEnabled: function(aCommand, dummy)
  3011.   {
  3012.     return IsInTableCell();
  3013.   },
  3014.   doCommand: function(aCommand)
  3015.   {
  3016.     var rows = GetNumberOfContiguousSelectedRows();
  3017.     // Delete at least one row
  3018.     if (rows == 0)
  3019.       rows = 1;
  3020.  
  3021.     try {
  3022.       window.editorShell.BeginBatchChanges();
  3023.  
  3024.       // Loop to delete all blocks of contiguous, selected rows
  3025.       while (rows)
  3026.       {
  3027.         window.editorShell.DeleteTableRow(rows);
  3028.         rows = GetNumberOfContiguousSelectedRows();
  3029.       }
  3030.       window.editorShell.EndBatchChanges();
  3031.     } catch(ex) {
  3032.       window.editorShell.EndBatchChanges();
  3033.     }
  3034.     window._content.focus();
  3035.   }
  3036. };
  3037.  
  3038. var nsDeleteTableColumnCommand =
  3039. {
  3040.   isCommandEnabled: function(aCommand, dummy)
  3041.   {
  3042.     return IsInTableCell();
  3043.   },
  3044.   doCommand: function(aCommand)
  3045.   {
  3046.     var columns = GetNumberOfContiguousSelectedColumns();
  3047.     // Delete at least one column
  3048.     if (columns == 0)
  3049.       columns = 1;
  3050.  
  3051.     try {
  3052.       window.editorShell.BeginBatchChanges();
  3053.  
  3054.       // Loop to delete all blocks of contiguous, selected columns
  3055.       while (columns)
  3056.       {
  3057.         window.editorShell.DeleteTableColumn(columns);
  3058.         columns = GetNumberOfContiguousSelectedColumns();
  3059.       }
  3060.       window.editorShell.EndBatchChanges();
  3061.     } catch(ex) {
  3062.       window.editorShell.EndBatchChanges();
  3063.     }
  3064.     window._content.focus();
  3065.   }
  3066. };
  3067.  
  3068. var nsDeleteTableCellCommand =
  3069. {
  3070.   isCommandEnabled: function(aCommand, dummy)
  3071.   {
  3072.     return IsInTableCell();
  3073.   },
  3074.   doCommand: function(aCommand)
  3075.   {
  3076.     window.editorShell.DeleteTableCell(1);   
  3077.     window._content.focus();
  3078.   }
  3079. };
  3080.  
  3081. var nsDeleteTableCellContentsCommand =
  3082. {
  3083.   isCommandEnabled: function(aCommand, dummy)
  3084.   {
  3085.     return IsInTableCell();
  3086.   },
  3087.   doCommand: function(aCommand)
  3088.   {
  3089.     window.editorShell.DeleteTableCellContents();
  3090.     window._content.focus();
  3091.   }
  3092. };
  3093.  
  3094.  
  3095. //-----------------------------------------------------------------------------------
  3096. var nsNormalizeTableCommand =
  3097. {
  3098.   isCommandEnabled: function(aCommand, dummy)
  3099.   {
  3100.     return IsInTable();
  3101.   },
  3102.   doCommand: function(aCommand)
  3103.   {
  3104.     // Use nsnull to let editor find table enclosing current selection
  3105.     window.editorShell.NormalizeTable(null);
  3106.     window._content.focus();
  3107.   }
  3108. };
  3109.  
  3110. //-----------------------------------------------------------------------------------
  3111. var nsJoinTableCellsCommand =
  3112. {
  3113.   isCommandEnabled: function(aCommand, dummy)
  3114.   {
  3115.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  3116.     {
  3117.       var tagNameObj = new Object;
  3118.       var countObj = new Object;
  3119.       var cell = window.editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  3120.  
  3121.       // We need a cell and either > 1 selected cell or a cell to the right
  3122.       //  (this cell may originate in a row spanned from above current row)
  3123.       // Note that editorShell returns "td" for "th" also.
  3124.       // (this is a pain! Editor and gecko use lowercase tagNames, JS uses uppercase!)
  3125.       if( cell && (tagNameObj.value == "td"))
  3126.       {
  3127.         // Selected cells
  3128.         if (countObj.value > 1) return true;
  3129.  
  3130.         var colSpan = cell.getAttribute("colspan");
  3131.  
  3132.         // getAttribute returns string, we need number
  3133.         // no attribute means colspan = 1
  3134.         if (!colSpan)
  3135.           colSpan = Number(1);
  3136.         else
  3137.           colSpan = Number(colSpan);
  3138.  
  3139.         // Test if cell exists to the right of current cell
  3140.         // (cells with 0 span should never have cells to the right
  3141.         //  if there is, user can select the 2 cells to join them)
  3142.         return (colSpan != 0 &&
  3143.                 window.editorShell.GetCellAt(null, 
  3144.                                    window.editorShell.GetRowIndex(cell), 
  3145.                                    window.editorShell.GetColumnIndex(cell) + colSpan));
  3146.       }
  3147.     }
  3148.     return false;
  3149.   },
  3150.   doCommand: function(aCommand)
  3151.   {
  3152.     // Param: Don't merge non-contiguous cells
  3153.     window.editorShell.JoinTableCells(false);
  3154.     window._content.focus();
  3155.   }
  3156. };
  3157.  
  3158. //-----------------------------------------------------------------------------------
  3159. var nsSplitTableCellCommand =
  3160. {
  3161.   isCommandEnabled: function(aCommand, dummy)
  3162.   {
  3163.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  3164.     {
  3165.       var tagNameObj = new Object;
  3166.       var countObj = new Object;
  3167.       var cell = window.editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  3168.       // We need a cell parent and there's just 1 selected cell 
  3169.       // or selection is entirely inside 1 cell
  3170.       if ( cell && (tagNameObj.value == "td") && 
  3171.            countObj.value <= 1 &&
  3172.            IsSelectionInOneCell() )
  3173.       {
  3174.         var colSpan = cell.getAttribute("colspan");
  3175.         var rowSpan = cell.getAttribute("rowspan");
  3176.         if (!colSpan) colSpan = 1;
  3177.         if (!rowSpan) rowSpan = 1;
  3178.         return (colSpan > 1  || rowSpan > 1 ||
  3179.                 colSpan == 0 || rowSpan == 0);
  3180.       }
  3181.     }
  3182.     return false;
  3183.   },
  3184.   doCommand: function(aCommand)
  3185.   {
  3186.     window.editorShell.SplitTableCell();
  3187.     window._content.focus();
  3188.   }
  3189. };
  3190.  
  3191. //-----------------------------------------------------------------------------------
  3192. var nsTableOrCellColorCommand =
  3193. {
  3194.   isCommandEnabled: function(aCommand, dummy)
  3195.   {
  3196.     return IsInTable();
  3197.   },
  3198.   doCommand: function(aCommand)
  3199.   {
  3200.     EditorSelectColor("TableOrCell");
  3201.   }
  3202. };
  3203.  
  3204. //-----------------------------------------------------------------------------------
  3205. var nsPreferencesCommand =
  3206. {
  3207.   isCommandEnabled: function(aCommand, dummy)
  3208.   {
  3209.     return true;
  3210.   },
  3211.   doCommand: function(aCommand)
  3212.   {
  3213.     goPreferences('navigator.xul', 'chrome://editor/content/pref-composer.xul','editor');
  3214.     window._content.focus();
  3215.   }
  3216. };
  3217.  
  3218.  
  3219. var nsFinishHTMLSource =
  3220. {
  3221.   isCommandEnabled: function(aCommand, dummy)
  3222.   {
  3223.     return true;
  3224.   },
  3225.   doCommand: function(aCommand)
  3226.   {
  3227.     // In editor.js
  3228.     FinishHTMLSource();
  3229.   }
  3230. };
  3231.  
  3232. var nsCancelHTMLSource =
  3233. {
  3234.   isCommandEnabled: function(aCommand, dummy)
  3235.   {
  3236.     return true;
  3237.   },
  3238.   doCommand: function(aCommand)
  3239.   {
  3240.     // In editor.js
  3241.     CancelHTMLSource();
  3242.   }
  3243. };
  3244.  
  3245. var nsBuildRecentPagesMenu =
  3246. {
  3247.   isCommandEnabled: function(aCommand, dummy)
  3248.   {
  3249.     return true;
  3250.   },
  3251.   doCommand: function(aCommand)
  3252.   {
  3253.     // In editor.js. True means save menu to prefs
  3254.     BuildRecentMenu(true);
  3255.   }
  3256. };
  3257.  
  3258. var nsConvertToTable =
  3259. {
  3260.   isCommandEnabled: function(aCommand, dummy)
  3261.   {
  3262.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  3263.     {
  3264.     var selection = window.editorShell.editorSelection;
  3265.  
  3266.     if (selection && !selection.isCollapsed)
  3267.     {
  3268.       // Don't allow if table or cell is the selection
  3269.       var element = window.editorShell.GetSelectedElement("");
  3270.  
  3271.       if (element && (element.nodeName == "td" ||
  3272.                       element.nodeName == "table"))
  3273.         return false;
  3274.  
  3275.       // Selection start and end must be in the same cell
  3276.       //   in same cell or both are NOT in a cell
  3277.       if ( GetParentTableCell(selection.focusNode) !=
  3278.            GetParentTableCell(selection.anchorNode) )
  3279.         return false
  3280.       
  3281.       return true;
  3282.       }
  3283.     }
  3284.     return false;
  3285.   },
  3286.   doCommand: function(aCommand)
  3287.   {
  3288.     if (this.isCommandEnabled())
  3289.     {
  3290.       window.openDialog("chrome://editor/content/EdConvertToTable.xul","_blank", "chrome,close,titlebar,modal")
  3291.     }
  3292.     window._content.focus();
  3293.   }
  3294. };
  3295.  
  3296.