home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 April / CMCD0404.ISO / Software / Complet / thunderbird / chrome / mail.jar / content / editor / ComposerCommands.js next >
Encoding:
JavaScript  |  2003-11-13  |  121.7 KB  |  3,924 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.  *
  28.  *
  29.  * Alternatively, the contents of this file may be used under the terms of
  30.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  31.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  32.  * in which case the provisions of the GPL or the LGPL are applicable instead
  33.  * of those above. If you wish to allow use of your version of this file only
  34.  * under the terms of either the GPL or the LGPL, and not to allow others to
  35.  * use your version of this file under the terms of the NPL, indicate your
  36.  * decision by deleting the provisions above and replace them with the notice
  37.  * and other provisions required by the GPL or the LGPL. If you do not delete
  38.  * the provisions above, a recipient may use your version of this file under
  39.  * the terms of any one of the NPL, the GPL or the LGPL.
  40.  *
  41.  * ***** END LICENSE BLOCK ***** */
  42.  
  43. /* Implementations of nsIControllerCommand for composer commands */
  44.  
  45. var gComposerJSCommandControllerID = 0;
  46.  
  47.  
  48. //-----------------------------------------------------------------------------------
  49. function SetupHTMLEditorCommands()
  50. {
  51.   var commandTable = GetComposerCommandTable();
  52.   if (!commandTable)
  53.     return;
  54.   
  55.   // Include everthing a text editor does
  56.   SetupTextEditorCommands();
  57.  
  58.   //dump("Registering HTML editor commands\n");
  59.  
  60.   commandTable.registerCommand("cmd_renderedHTMLEnabler", nsDummyHTMLCommand);
  61.  
  62.   commandTable.registerCommand("cmd_grid",  nsGridCommand);
  63.  
  64.   commandTable.registerCommand("cmd_listProperties",  nsListPropertiesCommand);
  65.   commandTable.registerCommand("cmd_pageProperties",  nsPagePropertiesCommand);
  66.   commandTable.registerCommand("cmd_colorProperties", nsColorPropertiesCommand);
  67.   commandTable.registerCommand("cmd_advancedProperties", nsAdvancedPropertiesCommand);
  68.   commandTable.registerCommand("cmd_objectProperties",   nsObjectPropertiesCommand);
  69.   commandTable.registerCommand("cmd_removeNamedAnchors", nsRemoveNamedAnchorsCommand);
  70.   commandTable.registerCommand("cmd_editLink",        nsEditLinkCommand);
  71.   
  72.   commandTable.registerCommand("cmd_form",          nsFormCommand);
  73.   commandTable.registerCommand("cmd_inputtag",      nsInputTagCommand);
  74.   commandTable.registerCommand("cmd_inputimage",    nsInputImageCommand);
  75.   commandTable.registerCommand("cmd_textarea",      nsTextAreaCommand);
  76.   commandTable.registerCommand("cmd_select",        nsSelectCommand);
  77.   commandTable.registerCommand("cmd_button",        nsButtonCommand);
  78.   commandTable.registerCommand("cmd_label",         nsLabelCommand);
  79.   commandTable.registerCommand("cmd_fieldset",      nsFieldSetCommand);
  80.   commandTable.registerCommand("cmd_isindex",       nsIsIndexCommand);
  81.   commandTable.registerCommand("cmd_image",         nsImageCommand);
  82.   commandTable.registerCommand("cmd_hline",         nsHLineCommand);
  83.   commandTable.registerCommand("cmd_link",          nsLinkCommand);
  84.   commandTable.registerCommand("cmd_anchor",        nsAnchorCommand);
  85.   commandTable.registerCommand("cmd_insertHTMLWithDialog", nsInsertHTMLWithDialogCommand);
  86.   commandTable.registerCommand("cmd_insertBreak",   nsInsertBreakCommand);
  87.   commandTable.registerCommand("cmd_insertBreakAll",nsInsertBreakAllCommand);
  88.  
  89.   commandTable.registerCommand("cmd_table",              nsInsertOrEditTableCommand);
  90.   commandTable.registerCommand("cmd_editTable",          nsEditTableCommand);
  91.   commandTable.registerCommand("cmd_SelectTable",        nsSelectTableCommand);
  92.   commandTable.registerCommand("cmd_SelectRow",          nsSelectTableRowCommand);
  93.   commandTable.registerCommand("cmd_SelectColumn",       nsSelectTableColumnCommand);
  94.   commandTable.registerCommand("cmd_SelectCell",         nsSelectTableCellCommand);
  95.   commandTable.registerCommand("cmd_SelectAllCells",     nsSelectAllTableCellsCommand);
  96.   commandTable.registerCommand("cmd_InsertTable",        nsInsertTableCommand);
  97.   commandTable.registerCommand("cmd_InsertRowAbove",     nsInsertTableRowAboveCommand);
  98.   commandTable.registerCommand("cmd_InsertRowBelow",     nsInsertTableRowBelowCommand);
  99.   commandTable.registerCommand("cmd_InsertColumnBefore", nsInsertTableColumnBeforeCommand);
  100.   commandTable.registerCommand("cmd_InsertColumnAfter",  nsInsertTableColumnAfterCommand);
  101.   commandTable.registerCommand("cmd_InsertCellBefore",   nsInsertTableCellBeforeCommand);
  102.   commandTable.registerCommand("cmd_InsertCellAfter",    nsInsertTableCellAfterCommand);
  103.   commandTable.registerCommand("cmd_DeleteTable",        nsDeleteTableCommand);
  104.   commandTable.registerCommand("cmd_DeleteRow",          nsDeleteTableRowCommand);
  105.   commandTable.registerCommand("cmd_DeleteColumn",       nsDeleteTableColumnCommand);
  106.   commandTable.registerCommand("cmd_DeleteCell",         nsDeleteTableCellCommand);
  107.   commandTable.registerCommand("cmd_DeleteCellContents", nsDeleteTableCellContentsCommand);
  108.   commandTable.registerCommand("cmd_JoinTableCells",     nsJoinTableCellsCommand);
  109.   commandTable.registerCommand("cmd_SplitTableCell",     nsSplitTableCellCommand);
  110.   commandTable.registerCommand("cmd_TableOrCellColor",   nsTableOrCellColorCommand);
  111.   commandTable.registerCommand("cmd_NormalizeTable",     nsNormalizeTableCommand);
  112.   commandTable.registerCommand("cmd_smiley",             nsSetSmiley);
  113.   commandTable.registerCommand("cmd_ConvertToTable",     nsConvertToTable);
  114. }
  115.  
  116. function SetupTextEditorCommands()
  117. {
  118.   var commandTable = GetComposerCommandTable();
  119.   if (!commandTable)
  120.     return;
  121.   
  122.   //dump("Registering plain text editor commands\n");
  123.   
  124.   commandTable.registerCommand("cmd_find",       nsFindCommand);
  125.   commandTable.registerCommand("cmd_findNext",   nsFindAgainCommand);
  126.   commandTable.registerCommand("cmd_findPrev",   nsFindAgainCommand);
  127.   commandTable.registerCommand("cmd_rewrap",     nsRewrapCommand);
  128.   commandTable.registerCommand("cmd_spelling",   nsSpellingCommand);
  129.   commandTable.registerCommand("cmd_validate",   nsValidateCommand);
  130.   commandTable.registerCommand("cmd_checkLinks", nsCheckLinksCommand);
  131.   commandTable.registerCommand("cmd_insertChars", nsInsertCharsCommand);
  132. }
  133.  
  134. function SetupComposerWindowCommands()
  135. {
  136.   // Don't need to do this if already done
  137.   if (gComposerWindowControllerID)
  138.     return;
  139.  
  140.   // Create a command controller and register commands
  141.   //   specific to Web Composer window (file-related commands, HTML Source...)
  142.   //   We can't use the composer controller created on the content window else
  143.   //     we can't process commands when in HTMLSource editor
  144.   // IMPORTANT: For each of these commands, the doCommand method 
  145.   //            must first call FinishHTMLSource() 
  146.   //            to go from HTML Source mode to any other edit mode
  147.  
  148.   var windowControllers = window.controllers;
  149.  
  150.   if (!windowControllers) return;
  151.  
  152.   var commandTable;
  153.   var composerController;
  154.   var editorController;
  155.   try {
  156.     composerController = Components.classes["@mozilla.org/embedcomp/base-command-controller;1"].createInstance();
  157.  
  158.     editorController = composerController.QueryInterface(Components.interfaces.nsIControllerContext);
  159.     editorController.init(null); // init it without passing in a command table
  160.  
  161.     // Get the nsIControllerCommandTable interface we need to register commands
  162.     var interfaceRequestor = composerController.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  163.     commandTable = interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandTable);
  164.   }
  165.   catch (e)
  166.   {
  167.     dump("Failed to create composerController\n");
  168.     return;
  169.   }
  170.  
  171.  
  172.   if (!commandTable)
  173.   {
  174.     dump("Failed to get interface for nsIControllerCommandManager\n");
  175.     return;
  176.   }
  177.  
  178.   // File-related commands
  179.   commandTable.registerCommand("cmd_open",           nsOpenCommand);
  180.   commandTable.registerCommand("cmd_save",           nsSaveCommand);
  181.   commandTable.registerCommand("cmd_saveAs",         nsSaveAsCommand);
  182.   commandTable.registerCommand("cmd_exportToText",   nsExportToTextCommand);
  183.   commandTable.registerCommand("cmd_saveAsCharset",  nsSaveAsCharsetCommand);
  184.   commandTable.registerCommand("cmd_publish",        nsPublishCommand);
  185.   commandTable.registerCommand("cmd_publishAs",      nsPublishAsCommand);
  186.   commandTable.registerCommand("cmd_publishSettings",nsPublishSettingsCommand);
  187.   commandTable.registerCommand("cmd_revert",         nsRevertCommand);
  188.   commandTable.registerCommand("cmd_openRemote",     nsOpenRemoteCommand);
  189.   commandTable.registerCommand("cmd_preview",        nsPreviewCommand);
  190.   commandTable.registerCommand("cmd_editSendPage",   nsSendPageCommand);
  191.   commandTable.registerCommand("cmd_print",          nsPrintCommand);
  192.   commandTable.registerCommand("cmd_printSetup",     nsPrintSetupCommand);
  193.   commandTable.registerCommand("cmd_quit",           nsQuitCommand);
  194.   commandTable.registerCommand("cmd_close",          nsCloseCommand);
  195.   commandTable.registerCommand("cmd_preferences",    nsPreferencesCommand);
  196.  
  197.   // Edit Mode commands
  198.   if (GetCurrentEditorType() == "html")
  199.   {
  200.     commandTable.registerCommand("cmd_NormalMode",         nsNormalModeCommand);
  201.     commandTable.registerCommand("cmd_AllTagsMode",        nsAllTagsModeCommand);
  202.     commandTable.registerCommand("cmd_HTMLSourceMode",     nsHTMLSourceModeCommand);
  203.     commandTable.registerCommand("cmd_PreviewMode",        nsPreviewModeCommand);
  204.     commandTable.registerCommand("cmd_FinishHTMLSource",   nsFinishHTMLSource);
  205.     commandTable.registerCommand("cmd_CancelHTMLSource",   nsCancelHTMLSource);
  206.     commandTable.registerCommand("cmd_updateStructToolbar", nsUpdateStructToolbarCommand);
  207.   }
  208.  
  209.   windowControllers.insertControllerAt(0, editorController);
  210.  
  211.   // Store the controller ID so we can be sure to get the right one later
  212.   gComposerWindowControllerID = windowControllers.getControllerId(editorController);
  213. }
  214.  
  215. //-----------------------------------------------------------------------------------
  216. function GetComposerCommandTable()
  217. {
  218.   var controller;
  219.   if (gComposerJSCommandControllerID)
  220.   {
  221.     try { 
  222.       controller = window.content.controllers.getControllerById(gComposerJSCommandControllerID);
  223.     } catch (e) {}
  224.   }
  225.   if (!controller)
  226.   {
  227.     //create it
  228.     controller = Components.classes["@mozilla.org/embedcomp/base-command-controller;1"].createInstance();
  229.  
  230.     var editorController = controller.QueryInterface(Components.interfaces.nsIControllerContext);
  231.     editorController.init(null);
  232.     editorController.setCommandContext(GetCurrentEditorElement());
  233.     window.content.controllers.insertControllerAt(0, controller);
  234.   
  235.     // Store the controller ID so we can be sure to get the right one later
  236.     gComposerJSCommandControllerID = window.content.controllers.getControllerId(controller);
  237.   }
  238.  
  239.   if (controller)
  240.   {
  241.     var interfaceRequestor = controller.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  242.     return interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandTable);
  243.   }
  244.   return null;
  245. }
  246.  
  247. //-----------------------------------------------------------------------------------
  248. function goUpdateCommandState(command)
  249. {
  250.   try
  251.   {
  252.     var controller = top.document.commandDispatcher.getControllerForCommand(command);
  253.     if (!(controller instanceof Components.interfaces.nsICommandController))
  254.       return;
  255.  
  256.     var params = newCommandParams();
  257.     if (!params) return;
  258.  
  259.     controller.getCommandStateWithParams(command, params);
  260.  
  261.     switch (command)
  262.     {
  263.       case "cmd_bold":
  264.       case "cmd_italic":
  265.       case "cmd_underline":
  266.       case "cmd_var":
  267.       case "cmd_samp":
  268.       case "cmd_code":
  269.       case "cmd_acronym":
  270.       case "cmd_abbr":
  271.       case "cmd_cite":
  272.       case "cmd_strong":
  273.       case "cmd_em":
  274.       case "cmd_superscript":
  275.       case "cmd_subscript":
  276.       case "cmd_strikethrough":
  277.       case "cmd_tt":
  278.       case "cmd_nobreak":
  279.       case "cmd_ul":
  280.       case "cmd_ol":
  281.         pokeStyleUI(command, params.getBooleanValue("state_all"));
  282.         break;
  283.  
  284.       case "cmd_paragraphState":
  285.       case "cmd_align":
  286.       case "cmd_highlight":
  287.       case "cmd_backgroundColor":
  288.       case "cmd_fontColor":
  289.       case "cmd_fontFace":
  290.       case "cmd_fontSize":
  291.       case "cmd_absPos":
  292.         pokeMultiStateUI(command, params);
  293.         break;
  294.  
  295.       case "cmd_decreaseZIndex":
  296.       case "cmd_increaseZIndex":
  297.       case "cmd_indent":
  298.       case "cmd_outdent":
  299.       case "cmd_increaseFont":
  300.       case "cmd_decreaseFont":
  301.       case "cmd_removeStyles":
  302.         break;
  303.  
  304.       default: dump("no update for command: " +command+"\n");
  305.     }
  306.   }
  307.   catch (e) { dump("An error occurred updating the "+command+" command: \n"+e+"\n"); }
  308. }
  309.  
  310. function goUpdateComposerMenuItems(commandset)
  311. {
  312.   //dump("Updating commands for " + commandset.id + "\n");
  313.  
  314.   for (var i = 0; i < commandset.childNodes.length; i++)
  315.   {
  316.     var commandNode = commandset.childNodes[i];
  317.     var commandID = commandNode.id;
  318.     if (commandID)
  319.     {
  320.       goUpdateCommand(commandID);  // enable or disable
  321.       if (commandNode.hasAttribute("state"))
  322.         goUpdateCommandState(commandID);
  323.     }
  324.   }
  325. }
  326.  
  327. //-----------------------------------------------------------------------------------
  328. function goDoCommandParams(command, params)
  329. {
  330.   try
  331.   {
  332.     var controller = top.document.commandDispatcher.getControllerForCommand(command);
  333.     if (controller && controller.isCommandEnabled(command))
  334.     {
  335.       if (controller instanceof Components.interfaces.nsICommandController)
  336.       {
  337.         controller.doCommandWithParams(command, params);
  338.  
  339.         // the following two lines should be removed when we implement observers
  340.         if (params)
  341.           controller.getCommandStateWithParams(command, params);
  342.       }
  343.       else
  344.       {
  345.         controller.doCommand(command);
  346.       }
  347.       ResetStructToolbar();
  348.     }
  349.   }
  350.   catch (e)
  351.   {
  352.     dump("An error occurred executing the "+command+" command\n");
  353.   }
  354. }
  355.  
  356. function pokeStyleUI(uiID, aDesiredState)
  357. {
  358.  try {
  359.   var commandNode = top.document.getElementById(uiID);
  360.   if (!commandNode)
  361.     return;
  362.  
  363.   var uiState = ("true" == commandNode.getAttribute("state"));
  364.   if (aDesiredState != uiState)
  365.   {
  366.     var newState;
  367.     if (aDesiredState)
  368.       newState = "true";
  369.     else
  370.       newState = "false";
  371.     commandNode.setAttribute("state", newState);
  372.   }
  373.  } catch(e) { dump("poking UI for "+uiID+" failed: "+e+"\n"); }
  374. }
  375.  
  376. function doStyleUICommand(cmdStr)
  377. {
  378.   try
  379.   {
  380.     var cmdParams = newCommandParams();
  381.     goDoCommandParams(cmdStr, cmdParams);
  382.     if (cmdParams)
  383.       pokeStyleUI(cmdStr, cmdParams.getBooleanValue("state_all"));
  384.  
  385.     ResetStructToolbar();
  386.   } catch(e) {}
  387. }
  388.  
  389. function pokeMultiStateUI(uiID, cmdParams)
  390. {
  391.   try
  392.   {
  393.     var commandNode = document.getElementById(uiID);
  394.     if (!commandNode)
  395.       return;
  396.  
  397.     var isMixed = cmdParams.getBooleanValue("state_mixed");
  398.     var desiredAttrib;
  399.     if (isMixed)
  400.       desiredAttrib = "mixed";
  401.     else
  402.       desiredAttrib = cmdParams.getCStringValue("state_attribute");
  403.  
  404.     var uiState = commandNode.getAttribute("state");
  405.     if (desiredAttrib != uiState)
  406.     {
  407.       commandNode.setAttribute("state", desiredAttrib);
  408.     }
  409.   } catch(e) {}
  410. }
  411.  
  412. function doStatefulCommand(commandID, newState)
  413. {
  414.   var commandNode = document.getElementById(commandID);
  415.   if (commandNode)
  416.       commandNode.setAttribute("state", newState);
  417.   gContentWindow.focus();   // needed for command dispatch to work
  418.  
  419.   try
  420.   {
  421.     var cmdParams = newCommandParams();
  422.     if (!cmdParams) return;
  423.  
  424.     cmdParams.setCStringValue("state_attribute", newState);
  425.     goDoCommandParams(commandID, cmdParams);
  426.  
  427.     pokeMultiStateUI(commandID, cmdParams);
  428.  
  429.     ResetStructToolbar();
  430.   } catch(e) { dump("error thrown in doStatefulCommand: "+e+"\n"); }
  431. }
  432.  
  433. //-----------------------------------------------------------------------------------
  434. function PrintObject(obj)
  435. {
  436.   dump("-----" + obj + "------\n");
  437.   var names = "";
  438.   for (var i in obj)
  439.   {
  440.     if (i == "value")
  441.       names += i + ": " + obj.value + "\n";
  442.     else if (i == "id")
  443.       names += i + ": " + obj.id + "\n";
  444.     else
  445.       names += i + "\n";
  446.   }
  447.   
  448.   dump(names + "-----------\n");
  449. }
  450.  
  451. //-----------------------------------------------------------------------------------
  452. function PrintNodeID(id)
  453. {
  454.   PrintObject(document.getElementById(id));
  455. }
  456.  
  457. //-----------------------------------------------------------------------------------
  458. var nsDummyHTMLCommand =
  459. {
  460.   isCommandEnabled: function(aCommand, dummy)
  461.   {
  462.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  463.   },
  464.  
  465.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  466.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  467.  
  468.   doCommand: function(aCommand)
  469.   {
  470.     // do nothing
  471.     dump("Hey, who's calling the dummy command?\n");
  472.   }
  473.  
  474. };
  475.  
  476. //-----------------------------------------------------------------------------------
  477. var nsOpenCommand =
  478. {
  479.   isCommandEnabled: function(aCommand, dummy)
  480.   {
  481.     return true;    // we can always do this
  482.   },
  483.  
  484.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  485.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  486.  
  487.   doCommand: function(aCommand)
  488.   {
  489.     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  490.     fp.init(window, GetString("OpenHTMLFile"), nsIFilePicker.modeOpen);
  491.  
  492.     SetFilePickerDirectory(fp, "html");
  493.  
  494.     // When loading into Composer, direct user to prefer HTML files and text files,
  495.     //   so we call separately to control the order of the filter list
  496.     fp.appendFilters(nsIFilePicker.filterHTML);
  497.     fp.appendFilters(nsIFilePicker.filterText);
  498.     fp.appendFilters(nsIFilePicker.filterAll);
  499.  
  500.     /* doesn't handle *.shtml files */
  501.     try {
  502.       fp.show();
  503.       /* need to handle cancel (uncaught exception at present) */
  504.     }
  505.     catch (ex) {
  506.       dump("filePicker.chooseInputFile threw an exception\n");
  507.     }
  508.   
  509.     /* This checks for already open window and activates it... 
  510.      * note that we have to test the native path length
  511.      *  since file.URL will be "file:///" if no filename picked (Cancel button used)
  512.      */
  513.     if (fp.file && fp.file.path.length > 0) {
  514.       SaveFilePickerDirectory(fp, "html");
  515.       editPage(fp.fileURL.spec, window, false);
  516.     }
  517.   }
  518. };
  519.  
  520. // STRUCTURE TOOLBAR
  521. //
  522. var nsUpdateStructToolbarCommand =
  523. {
  524.   isCommandEnabled: function(aCommand, dummy)
  525.   {
  526.     UpdateStructToolbar();
  527.     return true;
  528.   },
  529.  
  530.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  531.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  532.   doCommand: function(aCommand)  {}
  533. }
  534.  
  535. // ******* File output commands and utilities ******** //
  536. //-----------------------------------------------------------------------------------
  537. var nsSaveCommand =
  538. {
  539.   isCommandEnabled: function(aCommand, dummy)
  540.   {
  541.     // Always allow saving when editing a remote document,
  542.     //  otherwise the document modified state would prevent that
  543.     //  when you first open a remote file.
  544.     try {
  545.       var docUrl = GetDocumentUrl();
  546.       return IsDocumentEditable() &&
  547.         (IsDocumentModified() || IsHTMLSourceChanged() ||
  548.          IsUrlAboutBlank(docUrl) || GetScheme(docUrl) != "file");
  549.     } catch (e) {return false;}
  550.   },
  551.   
  552.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  553.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  554.  
  555.   doCommand: function(aCommand)
  556.   {
  557.     var result = false;
  558.     var editor = GetCurrentEditor();
  559.     if (editor)
  560.     {
  561.       FinishHTMLSource();
  562.       result = SaveDocument(IsUrlAboutBlank(GetDocumentUrl()), false, editor.contentsMIMEType);
  563.       window.content.focus();
  564.     }
  565.     return result;
  566.   }
  567. }
  568.  
  569. var nsSaveAsCommand =
  570. {
  571.   isCommandEnabled: function(aCommand, dummy)
  572.   {
  573.     return (IsDocumentEditable());
  574.   },
  575.  
  576.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  577.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  578.  
  579.   doCommand: function(aCommand)
  580.   {
  581.     var editor = GetCurrentEditor();
  582.     if (editor)
  583.     {
  584.       FinishHTMLSource();
  585.       var result = SaveDocument(true, false, editor.contentsMIMEType);
  586.       window.content.focus();
  587.       return result;
  588.     }
  589.     return false;
  590.   }
  591. }
  592.  
  593. var nsExportToTextCommand =
  594. {
  595.   isCommandEnabled: function(aCommand, dummy)
  596.   {
  597.     return (IsDocumentEditable());
  598.   },
  599.  
  600.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  601.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  602.  
  603.   doCommand: function(aCommand)
  604.   {
  605.     if (GetCurrentEditor())
  606.     {
  607.       FinishHTMLSource();
  608.       var result = SaveDocument(true, true, "text/plain");
  609.       window.content.focus();
  610.       return result;
  611.     }
  612.     return false;
  613.   }
  614. }
  615.  
  616. var nsSaveAsCharsetCommand =
  617. {
  618.   isCommandEnabled: function(aCommand, dummy)
  619.   {
  620.     return (IsDocumentEditable());
  621.   },
  622.  
  623.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  624.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  625.  
  626.   doCommand: function(aCommand)
  627.   {    
  628.     FinishHTMLSource();
  629.     window.ok = false;
  630.     window.exportToText = false;
  631.     var oldTitle = GetDocumentTitle();
  632.     window.openDialog("chrome://editor/content/EditorSaveAsCharset.xul","_blank", "chrome,close,titlebar,modal,resizable=yes");
  633.  
  634.     if (GetDocumentTitle() != oldTitle)
  635.       UpdateWindowTitle();
  636.  
  637.     if (window.ok)
  638.     {
  639.       if (window.exportToText)
  640.       {
  641.         window.ok = SaveDocument(true, true, "text/plain");
  642.       }
  643.       else
  644.       {
  645.         var editor = GetCurrentEditor();
  646.         window.ok = SaveDocument(true, false, editor ? editor.contentsMIMEType : null);
  647.       }
  648.     }
  649.  
  650.     window.content.focus();
  651.     return window.ok;
  652.   }
  653. };
  654.  
  655. var nsPublishCommand =
  656. {
  657.   isCommandEnabled: function(aCommand, dummy)
  658.   {
  659.     if (IsDocumentEditable())
  660.     {
  661.       // Always allow publishing when editing a local document,
  662.       //  otherwise the document modified state would prevent that
  663.       //  when you first open any local file.
  664.       try {
  665.         var docUrl = GetDocumentUrl();
  666.         return IsDocumentModified() || IsHTMLSourceChanged()
  667.                || IsUrlAboutBlank(docUrl) || GetScheme(docUrl) == "file";
  668.       } catch (e) {return false;}
  669.     }
  670.     return false;
  671.   },
  672.   
  673.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  674.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  675.  
  676.   doCommand: function(aCommand)
  677.   {
  678.     if (GetCurrentEditor())
  679.     {
  680.       var docUrl = GetDocumentUrl();
  681.       var filename = GetFilename(docUrl);
  682.       var publishData;
  683.       var showPublishDialog = false;
  684.  
  685.       // First check pref to always show publish dialog
  686.       try {
  687.         var prefs = GetPrefs();
  688.         if (prefs)
  689.           showPublishDialog = prefs.getBoolPref("editor.always_show_publish_dialog");
  690.       } catch(e) {}
  691.  
  692.       if (!showPublishDialog && filename)
  693.       {
  694.         // Try to get publish data from the document url
  695.         publishData = CreatePublishDataFromUrl(docUrl);
  696.  
  697.         // If none, use default publishing site? Need a pref for this
  698.         //if (!publishData)
  699.         //  publishData = GetPublishDataFromSiteName(GetDefaultPublishSiteName(), filename);
  700.       }
  701.  
  702.       if (showPublishDialog || !publishData)
  703.       {
  704.         // Show the publish dialog
  705.         publishData = {};
  706.         window.ok = false;
  707.         var oldTitle = GetDocumentTitle();
  708.         window.openDialog("chrome://editor/content/EditorPublish.xul","_blank", 
  709.                           "chrome,close,titlebar,modal", "", "", publishData);
  710.         if (GetDocumentTitle() != oldTitle)
  711.           UpdateWindowTitle();
  712.  
  713.         window.content.focus();
  714.         if (!window.ok)
  715.           return false;
  716.       }
  717.       if (publishData)
  718.       {
  719.         FinishHTMLSource();
  720.         return Publish(publishData);
  721.       }
  722.     }
  723.     return false;
  724.   }
  725. }
  726.  
  727. var nsPublishAsCommand =
  728. {
  729.   isCommandEnabled: function(aCommand, dummy)
  730.   {
  731.     return (IsDocumentEditable());
  732.   },
  733.   
  734.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  735.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  736.  
  737.   doCommand: function(aCommand)
  738.   {
  739.     if (GetCurrentEditor())
  740.     {
  741.       FinishHTMLSource();
  742.  
  743.       window.ok = false;
  744.       publishData = {};
  745.       var oldTitle = GetDocumentTitle();
  746.       window.openDialog("chrome://editor/content/EditorPublish.xul","_blank", 
  747.                         "chrome,close,titlebar,modal", "", "", publishData);
  748.       if (GetDocumentTitle() != oldTitle)
  749.         UpdateWindowTitle();
  750.  
  751.       window.content.focus();
  752.       if (window.ok)
  753.         return Publish(publishData);
  754.     }
  755.     return false;
  756.   }
  757. }
  758.  
  759. // ------- output utilites   ----- //
  760.  
  761. // returns a fileExtension string
  762. function GetExtensionBasedOnMimeType(aMIMEType)
  763. {
  764.   try {
  765.     var mimeService = null;
  766.     mimeService = Components.classes["@mozilla.org/mime;1"].getService();
  767.     mimeService = mimeService.QueryInterface(Components.interfaces.nsIMIMEService);
  768.  
  769.     var mimeInfo = mimeService.getFromTypeAndExtension(aMIMEType, null);
  770.     if (!mimeInfo) return "";
  771.  
  772.     var fileExtension = mimeInfo.primaryExtension;
  773.  
  774.     // the MIME service likes to give back ".htm" for text/html files,
  775.     // so do a special-case fix here.
  776.     if (fileExtension == "htm")
  777.       fileExtension = "html";
  778.  
  779.     return fileExtension;
  780.   }
  781.   catch (e) {}
  782.   return "";
  783. }
  784.  
  785. function GetSuggestedFileName(aDocumentURLString, aMIMEType)
  786. {
  787.   var extension = GetExtensionBasedOnMimeType(aMIMEType);
  788.   if (extension)
  789.     extension = "." + extension;
  790.  
  791.   // check for existing file name we can use
  792.   if (aDocumentURLString.length >= 0 && !IsUrlAboutBlank(aDocumentURLString))
  793.   {
  794.     var docURI = null;
  795.     try {
  796.  
  797.       var ioService = GetIOService();
  798.       docURI = ioService.newURI(aDocumentURLString, GetCurrentEditor().documentCharacterSet, null);
  799.       docURI = docURI.QueryInterface(Components.interfaces.nsIURL);
  800.  
  801.       // grab the file name
  802.       var url = docURI.fileBaseName;
  803.       if (url)
  804.         return url+extension;
  805.     } catch(e) {}
  806.   } 
  807.  
  808.   // check if there is a title we can use
  809.   var title = GetDocumentTitle();
  810.   // generate a valid filename, if we can't just go with "untitled"
  811.   return GenerateValidFilename(title, extension) || GetString("untitled") + extension;
  812. }
  813.  
  814. // returns file picker result
  815. function PromptForSaveLocation(aDoSaveAsText, aEditorType, aMIMEType, aDocumentURLString)
  816. {
  817.   var dialogResult = {};
  818.   dialogResult.filepickerClick = nsIFilePicker.returnCancel;
  819.   dialogResult.resultingURI = "";
  820.   dialogResult.resultingLocalFile = null;
  821.  
  822.   var fp = null;
  823.   try {
  824.     fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  825.   } catch (e) {}
  826.   if (!fp) return dialogResult;
  827.  
  828.   // determine prompt string based on type of saving we'll do
  829.   var promptString;
  830.   if (aDoSaveAsText || aEditorType == "text")
  831.     promptString = GetString("ExportToText");
  832.   else
  833.     promptString = GetString("SaveDocumentAs")
  834.  
  835.   fp.init(window, promptString, nsIFilePicker.modeSave);
  836.  
  837.   // Set filters according to the type of output
  838.   if (aDoSaveAsText)
  839.     fp.appendFilters(nsIFilePicker.filterText);
  840.   else
  841.     fp.appendFilters(nsIFilePicker.filterHTML);
  842.   fp.appendFilters(nsIFilePicker.filterAll);
  843.  
  844.   // now let's actually set the filepicker's suggested filename
  845.   var suggestedFileName = GetSuggestedFileName(aDocumentURLString, aMIMEType);
  846.   if (suggestedFileName)
  847.     fp.defaultString = suggestedFileName;
  848.  
  849.   // set the file picker's current directory
  850.   // assuming we have information needed (like prior saved location)
  851.   try {
  852.     var ioService = GetIOService();
  853.     var fileHandler = GetFileProtocolHandler();
  854.     
  855.     var isLocalFile = true;
  856.     try {
  857.       var docURI = ioService.newURI(aDocumentURLString, GetCurrentEditor().documentCharacterSet, null);
  858.       isLocalFile = docURI.schemeIs("file");
  859.     }
  860.     catch (e) {}
  861.  
  862.     var parentLocation = null;
  863.     if (isLocalFile)
  864.     {
  865.       var fileLocation = fileHandler.getFileFromURLSpec(aDocumentURLString); // this asserts if url is not local
  866.       parentLocation = fileLocation.parent;
  867.     }
  868.     if (parentLocation)
  869.     {
  870.       // Save current filepicker's default location
  871.       if ("gFilePickerDirectory" in window)
  872.         gFilePickerDirectory = fp.displayDirectory;
  873.  
  874.       fp.displayDirectory = parentLocation;
  875.     }
  876.     else
  877.     {
  878.       // Initialize to the last-used directory for the particular type (saved in prefs)
  879.       SetFilePickerDirectory(fp, aEditorType);
  880.     }
  881.   }
  882.   catch(e) {}
  883.  
  884.   dialogResult.filepickerClick = fp.show();
  885.   if (dialogResult.filepickerClick != nsIFilePicker.returnCancel)
  886.   {
  887.     // reset urlstring to new save location
  888.     dialogResult.resultingURIString = fileHandler.getURLSpecFromFile(fp.file);
  889.     dialogResult.resultingLocalFile = fp.file;
  890.     SaveFilePickerDirectory(fp, aEditorType);
  891.   }
  892.   else if ("gFilePickerDirectory" in window && gFilePickerDirectory)
  893.     fp.displayDirectory = gFilePickerDirectory; 
  894.  
  895.   return dialogResult;
  896. }
  897.  
  898. // returns a boolean (whether to continue (true) or not (false) because user canceled)
  899. function PromptAndSetTitleIfNone()
  900. {
  901.   if (GetDocumentTitle()) // we have a title; no need to prompt!
  902.     return true;
  903.  
  904.   var promptService = GetPromptService();
  905.   if (!promptService) return false;
  906.  
  907.   var result = {value:null};
  908.   var captionStr = GetString("DocumentTitle");
  909.   var msgStr = GetString("NeedDocTitle") + '\n' + GetString("DocTitleHelp");
  910.   var confirmed = promptService.prompt(window, captionStr, msgStr, result, null, {value:0});
  911.   if (confirmed)
  912.     SetDocumentTitle(TrimString(result.value));
  913.  
  914.   return confirmed;
  915. }
  916.  
  917. var gPersistObj;
  918.  
  919. // Don't forget to do these things after calling OutputFileWithPersistAPI:
  920. // we need to update the uri before notifying listeners
  921. //    if (doUpdateURI)
  922. //      SetDocumentURI(docURI);
  923. //    UpdateWindowTitle();
  924. //    if (!aSaveCopy)
  925. //      editor.resetModificationCount();
  926.       // this should cause notification to listeners that document has changed
  927.  
  928. const webPersist = Components.interfaces.nsIWebBrowserPersist;
  929. function OutputFileWithPersistAPI(editorDoc, aDestinationLocation, aRelatedFilesParentDir, aMimeType)
  930. {
  931.   gPersistObj = null;
  932.   var editor = GetCurrentEditor();
  933.   try {
  934.     var imeEditor = editor.QueryInterface(Components.interfaces.nsIEditorIMESupport);
  935.     imeEditor.ForceCompositionEnd();
  936.     } catch (e) {}
  937.  
  938.   var isLocalFile = false;
  939.   try {
  940.     var tmp1 = aDestinationLocation.QueryInterface(Components.interfaces.nsIFile);
  941.     isLocalFile = true;
  942.   } 
  943.   catch (e) {
  944.     try {
  945.       var tmp = aDestinationLocation.QueryInterface(Components.interfaces.nsIURI);
  946.       isLocalFile = tmp.schemeIs("file");
  947.     }
  948.     catch (e) {}
  949.   }
  950.  
  951.   try {
  952.     // we should supply a parent directory if/when we turn on functionality to save related documents
  953.     var persistObj = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(webPersist);
  954.     persistObj.progressListener = gEditorOutputProgressListener;
  955.     
  956.     var wrapColumn = GetWrapColumn();
  957.     var outputFlags = GetOutputFlags(aMimeType, wrapColumn);
  958.  
  959.     // for 4.x parity as well as improving readability of file locally on server
  960.     // this will always send crlf for upload (http/ftp)
  961.     if (!isLocalFile) // if we aren't saving locally then send both cr and lf
  962.     {
  963.       outputFlags |= webPersist.ENCODE_FLAGS_CR_LINEBREAKS | webPersist.ENCODE_FLAGS_LF_LINEBREAKS;
  964.  
  965.       // we want to serialize the output for all remote publishing
  966.       // some servers can handle only one connection at a time
  967.       // some day perhaps we can make this user-configurable per site?
  968.       persistObj.persistFlags = persistObj.persistFlags | webPersist.PERSIST_FLAGS_SERIALIZE_OUTPUT;
  969.     }
  970.  
  971.     // note: we always want to set the replace existing files flag since we have
  972.     // already given user the chance to not replace an existing file (file picker)
  973.     // or the user picked an option where the file is implicitly being replaced (save)
  974.     persistObj.persistFlags = persistObj.persistFlags 
  975.                             | webPersist.PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS
  976.                             | webPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES
  977.                             | webPersist.PERSIST_FLAGS_DONT_FIXUP_LINKS
  978.                             | webPersist.PERSIST_FLAGS_DONT_CHANGE_FILENAMES
  979.                             | webPersist.PERSIST_FLAGS_FIXUP_ORIGINAL_DOM;
  980.     persistObj.saveDocument(editorDoc, aDestinationLocation, aRelatedFilesParentDir, 
  981.                             aMimeType, outputFlags, wrapColumn);
  982.     gPersistObj = persistObj;
  983.   }
  984.   catch(e) { dump("caught an error, bail\n"); return false; }
  985.  
  986.   return true;
  987. }
  988.  
  989. // returns output flags based on mimetype, wrapCol and prefs
  990. function GetOutputFlags(aMimeType, aWrapColumn)
  991. {
  992.   var outputFlags = 0;
  993.   var editor = GetCurrentEditor();
  994.   var outputEntity = (editor && editor.documentCharacterSet == "ISO-8859-1")
  995.     ? webPersist.ENCODE_FLAGS_ENCODE_LATIN1_ENTITIES
  996.     : webPersist.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES;
  997.   if (aMimeType == "text/plain")
  998.   {
  999.     // When saving in "text/plain" format, always do formatting
  1000.     outputFlags |= webPersist.ENCODE_FLAGS_FORMATTED;
  1001.   }
  1002.   else
  1003.   {
  1004.     try {
  1005.       // Should we prettyprint? Check the pref
  1006.       var prefs = GetPrefs();
  1007.       if (prefs.getBoolPref("editor.prettyprint"))
  1008.         outputFlags |= webPersist.ENCODE_FLAGS_FORMATTED;
  1009.  
  1010.       // How much entity names should we output? Check the pref
  1011.       var encodeEntity = prefs.getCharPref("editor.encode_entity");
  1012.       switch (encodeEntity) {
  1013.         case "basic"  : outputEntity = webPersist.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES; break;
  1014.         case "latin1" : outputEntity = webPersist.ENCODE_FLAGS_ENCODE_LATIN1_ENTITIES; break;
  1015.         case "html"   : outputEntity = webPersist.ENCODE_FLAGS_ENCODE_HTML_ENTITIES; break;
  1016.         case "none"   : outputEntity = 0; break;
  1017.       }
  1018.     }
  1019.     catch (e) {}
  1020.   }
  1021.   outputFlags |= outputEntity;
  1022.  
  1023.   if (aWrapColumn > 0)
  1024.     outputFlags |= webPersist.ENCODE_FLAGS_WRAP;
  1025.  
  1026.   return outputFlags;
  1027. }
  1028.  
  1029. // returns number of column where to wrap
  1030. const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
  1031. function GetWrapColumn()
  1032. {
  1033.   try {
  1034.     return GetCurrentEditor().wrapWidth;
  1035.   } catch (e) {}
  1036.   return 0;
  1037. }
  1038.  
  1039. function GetPromptService()
  1040. {
  1041.   var promptService;
  1042.   try {
  1043.     promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  1044.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  1045.   }
  1046.   catch (e) {}
  1047.   return promptService;
  1048. }
  1049.  
  1050. const gShowDebugOutputStateChange = false;
  1051. const gShowDebugOutputProgress = false;
  1052. const gShowDebugOutputStatusChange = false;
  1053.  
  1054. const gShowDebugOutputLocationChange = false;
  1055. const gShowDebugOutputSecurityChange = false;
  1056.  
  1057. const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  1058. const nsIChannel = Components.interfaces.nsIChannel;
  1059.  
  1060. const kErrorBindingAborted = 2152398850;
  1061. const kErrorBindingRedirected = 2152398851;
  1062. const kFileNotFound = 2152857618;
  1063.  
  1064. var gEditorOutputProgressListener =
  1065. {
  1066.   onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
  1067.   {
  1068.     var editor = GetCurrentEditor();
  1069.  
  1070.     // Use this to access onStateChange flags
  1071.     var requestSpec;
  1072.     try {
  1073.       var channel = aRequest.QueryInterface(nsIChannel);
  1074.       requestSpec = StripUsernamePasswordFromURI(channel.URI);
  1075.     } catch (e) {
  1076.       if ( gShowDebugOutputStateChange)
  1077.         dump("***** onStateChange; NO REQUEST CHANNEL\n");
  1078.     }
  1079.  
  1080.     var pubSpec;
  1081.     if (gPublishData)
  1082.       pubSpec = gPublishData.publishUrl + gPublishData.docDir + gPublishData.filename;
  1083.  
  1084.     if (gShowDebugOutputStateChange)
  1085.     {
  1086.       dump("\n***** onStateChange request: " + requestSpec + "\n");
  1087.       dump("      state flags: ");
  1088.  
  1089.       if (aStateFlags & nsIWebProgressListener.STATE_START)
  1090.         dump(" STATE_START, ");
  1091.       if (aStateFlags & nsIWebProgressListener.STATE_STOP)
  1092.         dump(" STATE_STOP, ");
  1093.       if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK)
  1094.         dump(" STATE_IS_NETWORK ");
  1095.  
  1096.       dump("\n * requestSpec="+requestSpec+", pubSpec="+pubSpec+", aStatus="+aStatus+"\n");
  1097.  
  1098.       DumpDebugStatus(aStatus);
  1099.     }
  1100.     // The rest only concerns publishing, so bail out if no dialog
  1101.     if (!gProgressDialog)
  1102.       return;
  1103.  
  1104.     // Detect start of file upload of any file:
  1105.     // (We ignore any START messages after gPersistObj says publishing is finished
  1106.     if ((aStateFlags & nsIWebProgressListener.STATE_START)
  1107.          && gPersistObj && requestSpec
  1108.          && (gPersistObj.currentState != gPersistObj.PERSIST_STATE_FINISHED))
  1109.     {
  1110.       try {
  1111.         // Add url to progress dialog's list showing each file uploading
  1112.         gProgressDialog.SetProgressStatus(GetFilename(requestSpec), "busy");
  1113.       } catch(e) {}
  1114.     }
  1115.  
  1116.     // Detect end of file upload of any file:
  1117.     if (aStateFlags & nsIWebProgressListener.STATE_STOP)
  1118.     {
  1119.       // ignore aStatus == kErrorBindingAborted; check http response for possible errors
  1120.       try {
  1121.         // check http channel for response: 200 range is ok; other ranges are not
  1122.         var httpChannel = aRequest.QueryInterface(Components.interfaces.nsIHttpChannel);
  1123.         var httpResponse = httpChannel.responseStatus;
  1124.         if (httpResponse < 200 || httpResponse >= 300)
  1125.           aStatus = httpResponse;   // not a real error but enough to pass check below
  1126.         else if (aStatus == kErrorBindingAborted)
  1127.           aStatus = 0;
  1128.  
  1129.         if (gShowDebugOutputStateChange)
  1130.           dump("http response is: "+httpResponse+"\n");
  1131.       } 
  1132.       catch(e) 
  1133.       {
  1134.         if (aStatus == kErrorBindingAborted)
  1135.           aStatus = 0;
  1136.       }
  1137.  
  1138.       // We abort publishing for all errors except if image src file is not found
  1139.       var abortPublishing = (aStatus != 0 && aStatus != kFileNotFound);
  1140.  
  1141.       // Notify progress dialog when we receive the STOP
  1142.       //  notification for a file if there was an error 
  1143.       //  or a successful finish
  1144.       //  (Check requestSpec to be sure message is for destination url)
  1145.       if (aStatus != 0 
  1146.            || (requestSpec && requestSpec.indexOf(GetScheme(gPublishData.publishUrl)) == 0))
  1147.       {
  1148.         try {
  1149.           gProgressDialog.SetProgressFinished(GetFilename(requestSpec), aStatus);
  1150.         } catch(e) {}
  1151.       }
  1152.  
  1153.  
  1154.       if (abortPublishing)
  1155.       {
  1156.         // Cancel publishing
  1157.         gPersistObj.cancelSave();
  1158.  
  1159.         // Don't do any commands after failure
  1160.         gCommandAfterPublishing = null;
  1161.  
  1162.         // Restore original document to undo image src url adjustments
  1163.         if (gRestoreDocumentSource)
  1164.         {
  1165.           try {
  1166.             editor.rebuildDocumentFromSource(gRestoreDocumentSource);
  1167.  
  1168.             // Clear transaction cache since we just did a potentially 
  1169.             //  very large insert and this will eat up memory
  1170.             editor.transactionManager.clear();
  1171.           }
  1172.           catch (e) {}
  1173.         }
  1174.  
  1175.         // Notify progress dialog that we're finished
  1176.         //  and keep open to show error
  1177.         gProgressDialog.SetProgressFinished(null, 0);
  1178.  
  1179.         // We don't want to change location or reset mod count, etc.
  1180.         return;
  1181.       }
  1182.  
  1183.       //XXX HACK: "file://" protocol is not supported in network code
  1184.       //    (bug 151867 filed to add this support, bug 151869 filed
  1185.       //     to remove this and other code in nsIWebBrowserPersist)
  1186.       //    nsIWebBrowserPersist *does* copy the file(s), but we don't 
  1187.       //    get normal onStateChange messages.
  1188.  
  1189.       // Case 1: If images are included, we get fairly normal
  1190.       //    STATE_START/STATE_STOP & STATE_IS_NETWORK messages associated with the image files,
  1191.       //    thus we must finish HTML file progress below
  1192.  
  1193.       // Case 2: If just HTML file is uploaded, we get STATE_START and STATE_STOP
  1194.       //    notification with a null "requestSpec", and 
  1195.       //    the gPersistObj is destroyed before we get here!
  1196.       //    So create an new object so we can flow through normal processing below
  1197.       if (!requestSpec && GetScheme(gPublishData.publishUrl) == "file"
  1198.           && (!gPersistObj || gPersistObj.currentState == nsIWebBrowserPersist.PERSIST_STATE_FINISHED))
  1199.       {
  1200.         aStateFlags |= nsIWebProgressListener.STATE_IS_NETWORK;
  1201.         if (!gPersistObj)
  1202.         {          
  1203.           gPersistObj =
  1204.           {
  1205.             result : aStatus,
  1206.             currentState : nsIWebBrowserPersist.PERSIST_STATE_FINISHED
  1207.           }
  1208.         }
  1209.       }
  1210.  
  1211.       // STATE_IS_NETWORK signals end of publishing, as does the gPersistObj.currentState
  1212.       if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK
  1213.           && gPersistObj.currentState == nsIWebBrowserPersist.PERSIST_STATE_FINISHED)
  1214.       {
  1215.         if (GetScheme(gPublishData.publishUrl) == "file")
  1216.         {
  1217.           //XXX "file://" hack: We don't get notified about the HTML file, so end progress for it
  1218.           // (This covers both "Case 1 and 2" described above)
  1219.           gProgressDialog.SetProgressFinished(gPublishData.filename, gPersistObj.result);
  1220.         }
  1221.  
  1222.         if (gPersistObj.result == 0)
  1223.         {
  1224.           // All files are finished and publishing succeeded (some images may have failed)
  1225.           try {
  1226.             // Make a new docURI from the "browse location" in case "publish location" was FTP
  1227.             // We need to set document uri before notifying listeners
  1228.             var docUrl = GetDocUrlFromPublishData(gPublishData);
  1229.             SetDocumentURI(GetIOService().newURI(docUrl, editor.documentCharacterSet, null));
  1230.  
  1231.             UpdateWindowTitle();
  1232.  
  1233.             // this should cause notification to listeners that doc has changed
  1234.             editor.resetModificationCount();
  1235.  
  1236.             // Set UI based on whether we're editing a remote or local url
  1237.             SetSaveAndPublishUI(urlstring);
  1238.  
  1239.           } catch (e) {}
  1240.  
  1241.           // Save publishData to prefs
  1242.           if (gPublishData)
  1243.           {
  1244.             if (gPublishData.savePublishData)
  1245.             {
  1246.               // We published successfully, so we can safely
  1247.               //  save docDir and otherDir to prefs
  1248.               gPublishData.saveDirs = true;
  1249.               SavePublishDataToPrefs(gPublishData);
  1250.             }
  1251.             else
  1252.               SavePassword(gPublishData);
  1253.           }
  1254.  
  1255.           // Ask progress dialog to close, but it may not
  1256.           // if user checked checkbox to keep it open
  1257.           gProgressDialog.RequestCloseDialog();
  1258.         }
  1259.         else
  1260.         {
  1261.           // We previously aborted publishing because of error:
  1262.           //   Calling gPersistObj.cancelSave() resulted in a non-zero gPersistObj.result,
  1263.           //   so notify progress dialog we're finished
  1264.           gProgressDialog.SetProgressFinished(null, 0);
  1265.         }
  1266.       }
  1267.     }
  1268.   },
  1269.  
  1270.   onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress,
  1271.                               aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
  1272.   {
  1273.     if (!gPersistObj)
  1274.       return;
  1275.  
  1276.     if (gShowDebugOutputProgress)
  1277.     {
  1278.       dump("\n onProgressChange: gPersistObj.result="+gPersistObj.result+"\n");
  1279.       try {
  1280.       var channel = aRequest.QueryInterface(nsIChannel);
  1281.       dump("***** onProgressChange request: " + channel.URI.spec + "\n");
  1282.       }
  1283.       catch (e) {}
  1284.       dump("*****       self:  "+aCurSelfProgress+" / "+aMaxSelfProgress+"\n");
  1285.       dump("*****       total: "+aCurTotalProgress+" / "+aMaxTotalProgress+"\n\n");
  1286.  
  1287.       if (gPersistObj.currentState == gPersistObj.PERSIST_STATE_READY)
  1288.         dump(" Persister is ready to save data\n\n");
  1289.       else if (gPersistObj.currentState == gPersistObj.PERSIST_STATE_SAVING)
  1290.         dump(" Persister is saving data.\n\n");
  1291.       else if (gPersistObj.currentState == gPersistObj.PERSIST_STATE_FINISHED)
  1292.         dump(" PERSISTER HAS FINISHED SAVING DATA\n\n\n");
  1293.     }
  1294.   },
  1295.  
  1296.   onLocationChange : function(aWebProgress, aRequest, aLocation)
  1297.   {
  1298.     if (gShowDebugOutputLocationChange)
  1299.     {
  1300.       dump("***** onLocationChange: "+aLocation.spec+"\n");
  1301.       try {
  1302.         var channel = aRequest.QueryInterface(nsIChannel);
  1303.         dump("*****          request: " + channel.URI.spec + "\n");
  1304.       }
  1305.       catch(e) {}
  1306.     }
  1307.   },
  1308.  
  1309.   onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
  1310.   {
  1311.     if (gShowDebugOutputStatusChange)
  1312.     {
  1313.       dump("***** onStatusChange: "+aMessage+"\n");
  1314.       try {
  1315.         var channel = aRequest.QueryInterface(nsIChannel);
  1316.         dump("*****        request: " + channel.URI.spec + "\n");
  1317.       }
  1318.       catch (e) { dump("          couldn't get request\n"); }
  1319.       
  1320.       DumpDebugStatus(aStatus);
  1321.  
  1322.       if (gPersistObj)
  1323.       {
  1324.         if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_READY)
  1325.           dump(" Persister is ready to save data\n\n");
  1326.         else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_SAVING)
  1327.           dump(" Persister is saving data.\n\n");
  1328.         else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_FINISHED)
  1329.           dump(" PERSISTER HAS FINISHED SAVING DATA\n\n\n");
  1330.       }
  1331.     }
  1332.   },
  1333.  
  1334.   onSecurityChange : function(aWebProgress, aRequest, state)
  1335.   {
  1336.     if (gShowDebugOutputSecurityChange)
  1337.     {
  1338.       try {
  1339.         var channel = aRequest.QueryInterface(nsIChannel);
  1340.         dump("***** onSecurityChange request: " + channel.URI.spec + "\n");
  1341.       } catch (e) {}
  1342.     }
  1343.   },
  1344.  
  1345.   QueryInterface : function(aIID)
  1346.   {
  1347.     if (aIID.equals(Components.interfaces.nsIWebProgressListener)
  1348.     || aIID.equals(Components.interfaces.nsISupports)
  1349.     || aIID.equals(Components.interfaces.nsISupportsWeakReference)
  1350.     || aIID.equals(Components.interfaces.nsIPrompt)
  1351.     || aIID.equals(Components.interfaces.nsIAuthPrompt))
  1352.       return this;
  1353.     throw Components.results.NS_NOINTERFACE;
  1354.   },
  1355.  
  1356. // nsIPrompt
  1357.   alert : function(dlgTitle, text)
  1358.   {
  1359.     AlertWithTitle(dlgTitle, text, gProgressDialog ? gProgressDialog : window);
  1360.   },
  1361.   alertCheck : function(dialogTitle, text, checkBoxLabel, checkObj)
  1362.   {
  1363.     AlertWithTitle(dialogTitle, text);
  1364.   },
  1365.   confirm : function(dlgTitle, text)
  1366.   {
  1367.     return ConfirmWithTitle(dlgTitle, text, null, null);
  1368.   },
  1369.   confirmCheck : function(dlgTitle, text, checkBoxLabel, checkObj)
  1370.   {
  1371.     var promptServ = GetPromptService();
  1372.     if (!promptServ)
  1373.       return;
  1374.  
  1375.     promptServ.confirmEx(window, dlgTitle, text, nsIPromptService.STD_OK_CANCEL_BUTTONS,
  1376.                          "", "", "", checkBoxLabel, checkObj);
  1377.   },
  1378.   confirmEx : function(dlgTitle, text, btnFlags, btn0Title, btn1Title, btn2Title, checkBoxLabel, checkVal)
  1379.   {
  1380.     var promptServ = GetPromptService();
  1381.     if (!promptServ)
  1382.      return 0;
  1383.  
  1384.     return promptServ.confirmEx(window, dlgTitle, text, btnFlags,
  1385.                         btn0Title, btn1Title, btn2Title,
  1386.                         checkBoxLabel, checkVal);
  1387.   },
  1388.   prompt : function(dlgTitle, text, inoutText, checkBoxLabel, checkObj)
  1389.   {
  1390.     var promptServ = GetPromptService();
  1391.     if (!promptServ)
  1392.      return false;
  1393.  
  1394.     return promptServ.prompt(window, dlgTitle, text, inoutText, checkBoxLabel, checkObj);
  1395.   },
  1396.   promptPassword : function(dlgTitle, text, pwObj, checkBoxLabel, savePWObj)
  1397.   {
  1398.  
  1399.     var promptServ = GetPromptService();
  1400.     if (!promptServ)
  1401.      return false;
  1402.  
  1403.     var ret = false;
  1404.     try {
  1405.       // Note difference with nsIAuthPrompt::promptPassword, which has 
  1406.       // just "in" savePassword param, while nsIPrompt is "inout"
  1407.       // Initialize with user's previous preference for this site
  1408.       if (gPublishData)
  1409.         savePWObj.value = gPublishData.savePassword;
  1410.  
  1411.       ret = promptServ.promptPassword(gProgressDialog ? gProgressDialog : window,
  1412.                                       dlgTitle, text, pwObj, checkBoxLabel, savePWObj);
  1413.  
  1414.       if (!ret)
  1415.         setTimeout(CancelPublishing, 0);
  1416.  
  1417.       if (ret && gPublishData)
  1418.         UpdateUsernamePasswordFromPrompt(gPublishData, gPublishData.username, pwObj.value, savePWObj.value);
  1419.     } catch(e) {}
  1420.  
  1421.     return ret;
  1422.   },
  1423.   promptUsernameAndPassword : function(dlgTitle, text, userObj, pwObj, checkBoxLabel, savePWObj)
  1424.   {
  1425.     var ret = PromptUsernameAndPassword(dlgTitle, text, savePWObj.value, userObj, pwObj);
  1426.     if (!ret)
  1427.       setTimeout(CancelPublishing, 0);
  1428.  
  1429.     return ret;
  1430.   },
  1431.   select : function(dlgTitle, text, count, selectList, outSelection)
  1432.   {
  1433.     var promptServ = GetPromptService();
  1434.     if (!promptServ)
  1435.       return false;
  1436.  
  1437.     return promptServ.select(window, dlgTitle, text, count, selectList, outSelection);
  1438.   },
  1439.  
  1440. // nsIAuthPrompt
  1441.   prompt : function(dlgTitle, text, pwrealm, savePW, defaultText, result)
  1442.   {
  1443.     var promptServ = GetPromptService();
  1444.     if (!promptServ)
  1445.       return false;
  1446.  
  1447.     var savePWObj = {value:savePW};
  1448.     var ret = promptServ.prompt(gProgressDialog ? gProgressDialog : window,
  1449.                                 dlgTitle, text, defaultText, pwrealm, savePWObj);
  1450.     if (!ret)
  1451.       setTimeout(CancelPublishing, 0);
  1452.     return ret;
  1453.   },
  1454.  
  1455.   promptUsernameAndPassword : function(dlgTitle, text, pwrealm, savePW, userObj, pwObj)
  1456.   {
  1457.     var ret = PromptUsernameAndPassword(dlgTitle, text, savePW, userObj, pwObj);
  1458.     if (!ret)
  1459.       setTimeout(CancelPublishing, 0);
  1460.     return ret;
  1461.   },
  1462.  
  1463.   promptPassword : function(dlgTitle, text, pwrealm, savePW, pwObj)
  1464.   {
  1465.     var ret = false;
  1466.     try {
  1467.       var promptServ = GetPromptService();
  1468.       if (!promptServ)
  1469.         return false;
  1470.  
  1471.       // Note difference with nsIPrompt::promptPassword, which has 
  1472.       // "inout" savePassword param, while nsIAuthPrompt is just "in"
  1473.       // Also nsIAuth doesn't supply "checkBoxLabel"
  1474.       // Initialize with user's previous preference for this site
  1475.       var savePWObj = {value:savePW};
  1476.       // Initialize with user's previous preference for this site
  1477.       if (gPublishData)
  1478.         savePWObj.value = gPublishData.savePassword;
  1479.  
  1480.       ret = promptServ.promptPassword(gProgressDialog ? gProgressDialog : window,
  1481.                                       dlgTitle, text, pwObj, GetString("SavePassword"), savePWObj);
  1482.  
  1483.       if (!ret)
  1484.         setTimeout(CancelPublishing, 0);
  1485.  
  1486.       if (ret && gPublishData)
  1487.         UpdateUsernamePasswordFromPrompt(gPublishData, gPublishData.username, pwObj.value, savePWObj.value);
  1488.     } catch(e) {}
  1489.  
  1490.     return ret;
  1491.   }
  1492. }
  1493.  
  1494. function PromptUsernameAndPassword(dlgTitle, text, savePW, userObj, pwObj)
  1495. {
  1496.   // HTTP prompts us twice even if user Cancels from 1st attempt!
  1497.   // So never put up dialog if there's no publish data
  1498.   if (!gPublishData)
  1499.     return false
  1500.  
  1501.   var ret = false;
  1502.   try {
  1503.     var promptServ = GetPromptService();
  1504.     if (!promptServ)
  1505.       return false;
  1506.  
  1507.     var savePWObj = {value:savePW};
  1508.  
  1509.     // Initialize with user's previous preference for this site
  1510.     if (gPublishData)
  1511.     {
  1512.       // HTTP put uses this dialog if either username or password is bad,
  1513.       //   so prefill username input field with the previous value for modification
  1514.       savePWObj.value = gPublishData.savePassword;
  1515.       if (!userObj.value)
  1516.         userObj.value = gPublishData.username;
  1517.     }
  1518.  
  1519.     ret = promptServ.promptUsernameAndPassword(gProgressDialog ? gProgressDialog : window, 
  1520.                                                dlgTitle, text, userObj, pwObj, 
  1521.                                                GetString("SavePassword"), savePWObj);
  1522.     if (ret && gPublishData)
  1523.       UpdateUsernamePasswordFromPrompt(gPublishData, userObj.value, pwObj.value, savePWObj.value);
  1524.  
  1525.   } catch (e) {}
  1526.  
  1527.   return ret;
  1528. }
  1529.  
  1530. function DumpDebugStatus(aStatus)
  1531. {
  1532.   // see nsError.h and netCore.h and ftpCore.h
  1533.  
  1534.   if (aStatus == kErrorBindingAborted)
  1535.     dump("***** status is NS_BINDING_ABORTED\n");
  1536.   else if (aStatus == kErrorBindingRedirected)
  1537.     dump("***** status is NS_BINDING_REDIRECTED\n");
  1538.   else if (aStatus == 2152398859) // in netCore.h 11
  1539.     dump("***** status is ALREADY_CONNECTED\n");
  1540.   else if (aStatus == 2152398860) // in netCore.h 12
  1541.     dump("***** status is NOT_CONNECTED\n");
  1542.   else if (aStatus == 2152398861) //  in nsISocketTransportService.idl 13
  1543.     dump("***** status is CONNECTION_REFUSED\n");
  1544.   else if (aStatus == 2152398862) // in nsISocketTransportService.idl 14
  1545.     dump("***** status is NET_TIMEOUT\n");
  1546.   else if (aStatus == 2152398863) // in netCore.h 15
  1547.     dump("***** status is IN_PROGRESS\n");
  1548.   else if (aStatus == 2152398864) // 0x804b0010 in netCore.h 16
  1549.     dump("***** status is OFFLINE\n");
  1550.   else if (aStatus == 2152398865) // in netCore.h 17
  1551.     dump("***** status is NO_CONTENT\n");
  1552.   else if (aStatus == 2152398866) // in netCore.h 18
  1553.     dump("***** status is UNKNOWN_PROTOCOL\n");
  1554.   else if (aStatus == 2152398867) // in netCore.h 19
  1555.     dump("***** status is PORT_ACCESS_NOT_ALLOWED\n");
  1556.   else if (aStatus == 2152398868) // in nsISocketTransportService.idl 20
  1557.     dump("***** status is NET_RESET\n");
  1558.   else if (aStatus == 2152398869) // in ftpCore.h 21
  1559.     dump("***** status is FTP_LOGIN\n");
  1560.   else if (aStatus == 2152398870) // in ftpCore.h 22
  1561.     dump("***** status is FTP_CWD\n");
  1562.   else if (aStatus == 2152398871) // in ftpCore.h 23
  1563.     dump("***** status is FTP_PASV\n");
  1564.   else if (aStatus == 2152398872) // in ftpCore.h 24
  1565.     dump("***** status is FTP_PWD\n");
  1566.   else if (aStatus == 2152857601)
  1567.     dump("***** status is UNRECOGNIZED_PATH\n");
  1568.   else if (aStatus == 2152857602)
  1569.     dump("***** status is UNRESOLABLE SYMLINK\n");
  1570.   else if (aStatus == 2152857604)
  1571.     dump("***** status is UNKNOWN_TYPE\n");
  1572.   else if (aStatus == 2152857605)
  1573.     dump("***** status is DESTINATION_NOT_DIR\n");
  1574.   else if (aStatus == 2152857606)
  1575.     dump("***** status is TARGET_DOES_NOT_EXIST\n");
  1576.   else if (aStatus == 2152857608)
  1577.     dump("***** status is ALREADY_EXISTS\n");
  1578.   else if (aStatus == 2152857609)
  1579.     dump("***** status is INVALID_PATH\n");
  1580.   else if (aStatus == 2152857610)
  1581.     dump("***** status is DISK_FULL\n");
  1582.   else if (aStatus == 2152857612)
  1583.     dump("***** status is NOT_DIRECTORY\n");
  1584.   else if (aStatus == 2152857613)
  1585.     dump("***** status is IS_DIRECTORY\n");
  1586.   else if (aStatus == 2152857614)
  1587.     dump("***** status is IS_LOCKED\n");
  1588.   else if (aStatus == 2152857615)
  1589.     dump("***** status is TOO_BIG\n");
  1590.   else if (aStatus == 2152857616)
  1591.     dump("***** status is NO_DEVICE_SPACE\n");
  1592.   else if (aStatus == 2152857617)
  1593.     dump("***** status is NAME_TOO_LONG\n");
  1594.   else if (aStatus == 2152857618) // 80520012
  1595.     dump("***** status is FILE_NOT_FOUND\n");
  1596.   else if (aStatus == 2152857619)
  1597.     dump("***** status is READ_ONLY\n");
  1598.   else if (aStatus == 2152857620)
  1599.     dump("***** status is DIR_NOT_EMPTY\n");
  1600.   else if (aStatus == 2152857621)
  1601.     dump("***** status is ACCESS_DENIED\n");
  1602.   else if (aStatus == 2152398878)
  1603.     dump("***** status is ? (No connection or time out?)\n");
  1604.   else
  1605.     dump("***** status is " + aStatus + "\n");
  1606. }
  1607.  
  1608. // Update any data that the user supplied in a prompt dialog
  1609. function UpdateUsernamePasswordFromPrompt(publishData, username, password, savePassword)
  1610. {
  1611.   if (!publishData)
  1612.     return;
  1613.   
  1614.   // Set flag to save publish data after publishing if it changed in dialog 
  1615.   //  and the "SavePassword" checkbox was checked
  1616.   //  or we already had site data for this site
  1617.   // (Thus we don't automatically create a site until user brings up Publish As dialog)
  1618.   publishData.savePublishData = (gPublishData.username != username || gPublishData.password != password)
  1619.                                 && (savePassword || !publishData.notInSiteData);
  1620.  
  1621.   publishData.username = username;
  1622.   publishData.password = password;
  1623.   publishData.savePassword = savePassword;
  1624. }
  1625.  
  1626. const kSupportedTextMimeTypes =
  1627. [
  1628.   "text/plain",
  1629.   "text/css",
  1630.   "text/rdf",
  1631.   "text/xsl",
  1632.   "text/javascript",
  1633.   "application/x-javascript",
  1634.   "text/xul",
  1635.   "application/vnd.mozilla.xul+xml"
  1636. ];
  1637.  
  1638. function IsSupportedTextMimeType(aMimeType)
  1639. {
  1640.   for (var i = 0; i < kSupportedTextMimeTypes.length; i++)
  1641.   {
  1642.     if (kSupportedTextMimeTypes[i] == aMimeType)
  1643.       return true;
  1644.   }
  1645.   return false;
  1646. }
  1647.  
  1648. // throws an error or returns true if user attempted save; false if user canceled save
  1649. function SaveDocument(aSaveAs, aSaveCopy, aMimeType)
  1650. {
  1651.   var editor = GetCurrentEditor();
  1652.   if (!aMimeType || aMimeType == "" || !editor)
  1653.     throw NS_ERROR_NOT_INITIALIZED;
  1654.  
  1655.   var editorDoc = editor.document;
  1656.   if (!editorDoc)
  1657.     throw NS_ERROR_NOT_INITIALIZED;
  1658.  
  1659.   // if we don't have the right editor type bail (we handle text and html)
  1660.   var editorType = GetCurrentEditorType();
  1661.   if (editorType != "text" && editorType != "html" 
  1662.       && editorType != "htmlmail" && editorType != "textmail")
  1663.     throw NS_ERROR_NOT_IMPLEMENTED;
  1664.  
  1665.   var saveAsTextFile = IsSupportedTextMimeType(aMimeType);
  1666.  
  1667.   // check if the file is to be saved is a format we don't understand; if so, bail
  1668.   if (aMimeType != "text/html" && !saveAsTextFile)
  1669.     throw NS_ERROR_NOT_IMPLEMENTED;
  1670.  
  1671.   if (saveAsTextFile)
  1672.     aMimeType = "text/plain";
  1673.  
  1674.   var urlstring = GetDocumentUrl();
  1675.   var mustShowFileDialog = (aSaveAs || IsUrlAboutBlank(urlstring) || (urlstring == ""));
  1676.  
  1677.   // If editing a remote URL, force SaveAs dialog
  1678.   if (!mustShowFileDialog && GetScheme(urlstring) != "file")
  1679.     mustShowFileDialog = true;
  1680.  
  1681.   var replacing = !aSaveAs;
  1682.   var titleChanged = false;
  1683.   var doUpdateURI = false;
  1684.   var tempLocalFile = null;
  1685.  
  1686.   if (mustShowFileDialog)
  1687.   {
  1688.       try {
  1689.         // Prompt for title if we are saving to HTML
  1690.         if (!saveAsTextFile && (editorType == "html"))
  1691.         {
  1692.           var userContinuing = PromptAndSetTitleIfNone(); // not cancel
  1693.           if (!userContinuing)
  1694.             return false;
  1695.         }
  1696.  
  1697.         var dialogResult = PromptForSaveLocation(saveAsTextFile, editorType, aMimeType, urlstring);
  1698.         if (dialogResult.filepickerClick == nsIFilePicker.returnCancel)
  1699.           return false;
  1700.  
  1701.         replacing = (dialogResult.filepickerClick == nsIFilePicker.returnReplace);
  1702.         urlstring = dialogResult.resultingURIString;
  1703.         tempLocalFile = dialogResult.resultingLocalFile;
  1704.  
  1705.       // update the new URL for the webshell unless we are saving a copy
  1706.       if (!aSaveCopy)
  1707.         doUpdateURI = true;
  1708.    } catch (e) {  return false; }
  1709.   } // mustShowFileDialog
  1710.  
  1711.   var success = true;
  1712.   var ioService;
  1713.   try {
  1714.     // if somehow we didn't get a local file but we did get a uri, 
  1715.     // attempt to create the localfile if it's a "file" url
  1716.     var docURI;
  1717.     if (!tempLocalFile)
  1718.     {
  1719.       ioService = GetIOService();
  1720.       docURI = ioService.newURI(urlstring, editor.documentCharacterSet, null);
  1721.       
  1722.       if (docURI.schemeIs("file"))
  1723.       {
  1724.         var fileHandler = GetFileProtocolHandler();
  1725.         tempLocalFile = fileHandler.getFileFromURLSpec(urlstring).QueryInterface(Components.interfaces.nsILocalFile);
  1726.       }
  1727.     }
  1728.  
  1729.     // this is the location where the related files will go
  1730.     var relatedFilesDir = null;
  1731.     
  1732.     // First check pref for saving associated files
  1733.     var saveAssociatedFiles = false;
  1734.     try {
  1735.       var prefs = GetPrefs();
  1736.       saveAssociatedFiles = prefs.getBoolPref("editor.save_associated_files");
  1737.     } catch (e) {}
  1738.  
  1739.     // Only change links or move files if pref is set 
  1740.     //  and we are saving to a new location
  1741.     if (saveAssociatedFiles && aSaveAs)
  1742.     {
  1743.       try {
  1744.         if (tempLocalFile)
  1745.         {
  1746.           // if we are saving to the same parent directory, don't set relatedFilesDir
  1747.           // grab old location, chop off file
  1748.           // grab new location, chop off file, compare
  1749.           var oldLocation = GetDocumentUrl();
  1750.           var oldLocationLastSlash = oldLocation.lastIndexOf("\/");
  1751.           if (oldLocationLastSlash != -1)
  1752.             oldLocation = oldLocation.slice(0, oldLocationLastSlash);
  1753.  
  1754.           var relatedFilesDirStr = urlstring;
  1755.           var newLocationLastSlash = relatedFilesDirStr.lastIndexOf("\/");
  1756.           if (newLocationLastSlash != -1)
  1757.             relatedFilesDirStr = relatedFilesDirStr.slice(0, newLocationLastSlash);
  1758.           if (oldLocation == relatedFilesDirStr || IsUrlAboutBlank(oldLocation))
  1759.             relatedFilesDir = null;
  1760.           else
  1761.             relatedFilesDir = tempLocalFile.parent;
  1762.         }
  1763.         else
  1764.         {
  1765.           var lastSlash = urlstring.lastIndexOf("\/");
  1766.           if (lastSlash != -1)
  1767.           {
  1768.             var relatedFilesDirString = urlstring.slice(0, lastSlash + 1);  // include last slash
  1769.             ioService = GetIOService();
  1770.             relatedFilesDir = ioService.newURI(relatedFilesDirString, editor.documentCharacterSet, null);
  1771.           }
  1772.         }
  1773.       } catch(e) { relatedFilesDir = null; }
  1774.     }
  1775.  
  1776.     var destinationLocation;
  1777.     if (tempLocalFile)
  1778.       destinationLocation = tempLocalFile;
  1779.     else
  1780.       destinationLocation = docURI;
  1781.  
  1782.     success = OutputFileWithPersistAPI(editorDoc, destinationLocation, relatedFilesDir, aMimeType);
  1783.   }
  1784.   catch (e)
  1785.   {
  1786.     success = false;
  1787.   }
  1788.  
  1789.   if (success)
  1790.   {
  1791.     try {
  1792.       if (doUpdateURI)
  1793.       {
  1794.          // If a local file, we must create a new uri from nsILocalFile
  1795.         if (tempLocalFile)
  1796.           docURI = GetFileProtocolHandler().newFileURI(tempLocalFile);
  1797.  
  1798.         // We need to set new document uri before notifying listeners
  1799.         SetDocumentURI(docURI);
  1800.       }
  1801.  
  1802.       // Update window title to show possibly different filename
  1803.       // This also covers problem that after undoing a title change,
  1804.       //   window title loses the extra [filename] part that this adds
  1805.       UpdateWindowTitle();
  1806.  
  1807.       if (!aSaveCopy)
  1808.         editor.resetModificationCount();
  1809.       // this should cause notification to listeners that document has changed
  1810.  
  1811.       // Set UI based on whether we're editing a remote or local url
  1812.       SetSaveAndPublishUI(urlstring);
  1813.     } catch (e) {}
  1814.   }
  1815.   else
  1816.   {
  1817.     var saveDocStr = GetString("SaveDocument");
  1818.     var failedStr = GetString("SaveFileFailed");
  1819.     AlertWithTitle(saveDocStr, failedStr);
  1820.   }
  1821.   return success;
  1822. }
  1823.  
  1824. function SetDocumentURI(uri)
  1825. {
  1826.   try {
  1827.     // XXX WE'LL NEED TO GET "CURRENT" CONTENT FRAME ONCE MULTIPLE EDITORS ARE ALLOWED
  1828.     GetCurrentEditorElement().docShell.setCurrentURI(uri);
  1829.   } catch (e) { dump("SetDocumentURI:\n"+e +"\n"); }
  1830. }
  1831.  
  1832.  
  1833. //-------------------------------  Publishing
  1834. var gPublishData;
  1835. var gProgressDialog;
  1836. var gCommandAfterPublishing = null;
  1837. var gRestoreDocumentSource;
  1838.  
  1839. function Publish(publishData)
  1840. {
  1841.   if (!publishData)
  1842.     return false;
  1843.  
  1844.   // Set data in global for username password requests
  1845.   //  and to do "post saving" actions after monitoring nsIWebProgressListener messages
  1846.   //  and we are sure file transfer was successful
  1847.   gPublishData = publishData;
  1848.  
  1849.   gPublishData.docURI = CreateURIFromPublishData(publishData, true);
  1850.   if (!gPublishData.docURI)
  1851.   {
  1852.     AlertWithTitle(GetString("Publish"), GetString("PublishFailed"));
  1853.     return false;
  1854.   }
  1855.  
  1856.   if (gPublishData.publishOtherFiles)
  1857.     gPublishData.otherFilesURI = CreateURIFromPublishData(publishData, false);
  1858.   else
  1859.     gPublishData.otherFilesURI = null;
  1860.  
  1861.   if (gShowDebugOutputStateChange)
  1862.   {
  1863.     dump("\n *** publishData: PublishUrl="+publishData.publishUrl+", BrowseUrl="+publishData.browseUrl+
  1864.       ", Username="+publishData.username+", Dir="+publishData.docDir+
  1865.       ", Filename="+publishData.filename+"\n");
  1866.     dump(" * gPublishData.docURI.spec w/o pass="+StripPassword(gPublishData.docURI.spec)+", PublishOtherFiles="+gPublishData.publishOtherFiles+"\n");
  1867.   }
  1868.  
  1869.   // XXX Missing username will make FTP fail 
  1870.   // and it won't call us for prompt dialog (bug 132320)
  1871.   // (It does prompt if just password is missing)
  1872.   // So we should do the prompt ourselves before trying to publish
  1873.   if (GetScheme(publishData.publishUrl) == "ftp" && !publishData.username)
  1874.   {
  1875.     var message = GetString("PromptFTPUsernamePassword").replace(/%host%/, GetHost(publishData.publishUrl));
  1876.     var savePWobj = {value:publishData.savePassword};
  1877.     var userObj = {value:publishData.username};
  1878.     var pwObj = {value:publishData.password};
  1879.     if (!PromptUsernameAndPassword(GetString("Prompt"), message, savePWobj, userObj, pwObj))
  1880.       return false; // User canceled out of dialog
  1881.  
  1882.     // Reset data in URI objects
  1883.     gPublishData.docURI.username = publishData.username;
  1884.     gPublishData.docURI.password = publishData.password;
  1885.  
  1886.     if (gPublishData.otherFilesURI)
  1887.     {
  1888.       gPublishData.otherFilesURI.username = publishData.username;
  1889.       gPublishData.otherFilesURI.password = publishData.password;
  1890.     }
  1891.   }
  1892.  
  1893.   try {
  1894.     // We launch dialog as a dependent 
  1895.     // Don't allow editing document!
  1896.     SetDocumentEditable(false);
  1897.  
  1898.     // Start progress monitoring
  1899.     gProgressDialog =
  1900.       window.openDialog("chrome://editor/content/EditorPublishProgress.xul", "_blank",
  1901.                         "chrome,dependent,titlebar", gPublishData, gPersistObj);
  1902.  
  1903.   } catch (e) {}
  1904.  
  1905.   // Network transfer is often too quick for the progress dialog to be initialized
  1906.   //  and we can completely miss messages for quickly-terminated bad URLs,
  1907.   //  so we can't call OutputFileWithPersistAPI right away.
  1908.   // StartPublishing() is called at the end of the dialog's onload method
  1909.   return true;
  1910. }
  1911.  
  1912. function StartPublishing()
  1913. {
  1914.   var editor = GetCurrentEditor();
  1915.   if (editor && gPublishData && gPublishData.docURI && gProgressDialog)
  1916.   {
  1917.     gRestoreDocumentSource = null;
  1918.  
  1919.     // Save backup document since nsIWebBrowserPersist changes image src urls
  1920.     // but we only need to do this if publishing images and other related files
  1921.     if (gPublishData.otherFilesURI)
  1922.     {
  1923.       try {
  1924.         // (256 = Output encoded entities)
  1925.         gRestoreDocumentSource = 
  1926.           editor.outputToString(editor.contentsMIMEType, 256);
  1927.       } catch (e) {}
  1928.     }
  1929.  
  1930.     OutputFileWithPersistAPI(editor.document, 
  1931.                              gPublishData.docURI, gPublishData.otherFilesURI, 
  1932.                              editor.contentsMIMEType);
  1933.     return gPersistObj;
  1934.   }
  1935.   return null;
  1936. }
  1937.  
  1938. function CancelPublishing()
  1939. {
  1940.   try {
  1941.     gPersistObj.cancelSave();
  1942.     gProgressDialog.SetProgressStatusCancel();
  1943.   } catch (e) {}
  1944.  
  1945.   // If canceling publishing do not do any commands after this    
  1946.   gCommandAfterPublishing = null;
  1947.  
  1948.   if (gProgressDialog)
  1949.   {
  1950.     // Close Progress dialog 
  1951.     // (this will call FinishPublishing())
  1952.     gProgressDialog.CloseDialog();
  1953.   }
  1954.   else
  1955.     FinishPublishing();
  1956. }
  1957.  
  1958. function FinishPublishing()
  1959. {
  1960.   SetDocumentEditable(true);
  1961.   gProgressDialog = null;
  1962.   gPublishData = null;
  1963.   gRestoreDocumentSource = null;
  1964.  
  1965.   if (gCommandAfterPublishing)
  1966.   {
  1967.     // Be sure to null out the global now incase of trouble when executing command
  1968.     var command = gCommandAfterPublishing;
  1969.     gCommandAfterPublishing = null;
  1970.     goDoCommand(command);
  1971.   }
  1972. }
  1973.  
  1974. // Create a nsIURI object filled in with all required publishing info
  1975. function CreateURIFromPublishData(publishData, doDocUri)
  1976. {
  1977.   if (!publishData || !publishData.publishUrl)
  1978.     return null;
  1979.  
  1980.   var URI;
  1981.   try {
  1982.     var spec = publishData.publishUrl;
  1983.     if (doDocUri)
  1984.       spec += FormatDirForPublishing(publishData.docDir) + publishData.filename; 
  1985.     else
  1986.       spec += FormatDirForPublishing(publishData.otherDir);
  1987.  
  1988.     var ioService = GetIOService();
  1989.     URI = ioService.newURI(spec, GetCurrentEditor().documentCharacterSet, null);
  1990.  
  1991.     if (publishData.username)
  1992.       URI.username = publishData.username;
  1993.     if (publishData.password)
  1994.       URI.password = publishData.password;
  1995.   }
  1996.   catch (e) {}
  1997.  
  1998.   return URI;
  1999. }
  2000.  
  2001. // Resolve the correct "http:" document URL when publishing via ftp
  2002. function GetDocUrlFromPublishData(publishData)
  2003. {
  2004.   if (!publishData || !publishData.filename || !publishData.publishUrl)
  2005.     return "";
  2006.  
  2007.   // If user was previously editing an "ftp" url, then keep that as the new scheme
  2008.   var url;
  2009.   var docScheme = GetScheme(GetDocumentUrl());
  2010.  
  2011.   // Always use the "HTTP" address if available
  2012.   // XXX Should we do some more validation here for bad urls???
  2013.   // Let's at least check for a scheme!
  2014.   if (!GetScheme(publishData.browseUrl))
  2015.     url = publishData.publishUrl;
  2016.   else
  2017.     url = publishData.browseUrl;
  2018.  
  2019.   url += FormatDirForPublishing(publishData.docDir) + publishData.filename;
  2020.  
  2021.   if (GetScheme(url) == "ftp")
  2022.     url = InsertUsernameIntoUrl(url, publishData.username);
  2023.  
  2024.   return url;
  2025. }
  2026.  
  2027. function SetSaveAndPublishUI(urlstring)
  2028. {
  2029.   // Be sure enabled state of toolbar buttons are correct
  2030.   goUpdateCommand("cmd_save");
  2031.   goUpdateCommand("cmd_publish");
  2032. }
  2033.  
  2034. function SetDocumentEditable(isDocEditable)
  2035. {
  2036.   var editor = GetCurrentEditor();
  2037.   if (editor && editor.document)
  2038.   {
  2039.     try {
  2040.       var flags = editor.flags;
  2041.       editor.flags = isDocEditable ?  
  2042.             flags &= ~nsIPlaintextEditor.eEditorReadonlyMask :
  2043.             flags | nsIPlaintextEditor.eEditorReadonlyMask;
  2044.     } catch(e) {}
  2045.  
  2046.     // update all commands
  2047.     window.updateCommands("create");
  2048.   }  
  2049. }
  2050.  
  2051. // ****** end of save / publish **********//
  2052.  
  2053. //-----------------------------------------------------------------------------------
  2054. var nsPublishSettingsCommand =
  2055. {
  2056.   isCommandEnabled: function(aCommand, dummy)
  2057.   {
  2058.     return (IsDocumentEditable());
  2059.   },
  2060.  
  2061.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2062.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2063.  
  2064.   doCommand: function(aCommand)
  2065.   {
  2066.     if (GetCurrentEditor())
  2067.     {
  2068.       // Launch Publish Settings dialog
  2069.  
  2070.       window.ok = window.openDialog("chrome://editor/content/EditorPublishSettings.xul","_blank", "chrome,close,titlebar,modal", "");
  2071.       window.content.focus();
  2072.       return window.ok;
  2073.     }
  2074.     return false;
  2075.   }
  2076. }
  2077.  
  2078. //-----------------------------------------------------------------------------------
  2079. var nsRevertCommand =
  2080. {
  2081.   isCommandEnabled: function(aCommand, dummy)
  2082.   {
  2083.     return (IsDocumentEditable() &&
  2084.             IsDocumentModified() &&
  2085.             !IsUrlAboutBlank(GetDocumentUrl()));
  2086.   },
  2087.  
  2088.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2089.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2090.  
  2091.   doCommand: function(aCommand)
  2092.   {
  2093.     // Confirm with the user to abandon current changes
  2094.     var promptService = GetPromptService();
  2095.     if (promptService)
  2096.     {
  2097.       // Put the page title in the message string
  2098.       var title = GetDocumentTitle();
  2099.       if (!title)
  2100.         title = GetString("untitled");
  2101.  
  2102.       var msg = GetString("AbandonChanges").replace(/%title%/,title);
  2103.  
  2104.       var result = promptService.confirmEx(window, GetString("RevertCaption"), msg,
  2105.                                 (promptService.BUTTON_TITLE_REVERT * promptService.BUTTON_POS_0) +
  2106.                                 (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
  2107.                                 null, null, null, null, {value:0});
  2108.  
  2109.       // Reload page if first button (Revert) was pressed
  2110.       if(result == 0)
  2111.       {
  2112.         CancelHTMLSource();
  2113.         EditorLoadUrl(GetDocumentUrl());
  2114.       }
  2115.     }
  2116.   }
  2117. };
  2118.  
  2119. //-----------------------------------------------------------------------------------
  2120. var nsCloseCommand =
  2121. {
  2122.   isCommandEnabled: function(aCommand, dummy)
  2123.   {
  2124.     return GetCurrentEditor() != null;
  2125.   },
  2126.   
  2127.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2128.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2129.  
  2130.   doCommand: function(aCommand)
  2131.   {
  2132.     CloseWindow();
  2133.   }
  2134. };
  2135.  
  2136. function CloseWindow()
  2137. {
  2138.   // Check to make sure document is saved. "true" means allow "Don't Save" button,
  2139.   //   so user can choose to close without saving
  2140.   if (CheckAndSaveDocument("cmd_close", true)) 
  2141.   {
  2142.     if (window.InsertCharWindow)
  2143.       SwitchInsertCharToAnotherEditorOrClose();
  2144.  
  2145.     try {
  2146.       var basewin = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  2147.                       .getInterface(Components.interfaces.nsIWebNavigation)
  2148.                       .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
  2149.                       .treeOwner
  2150.                       .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  2151.                       .getInterface(Components.interfaces.nsIBaseWindow);
  2152.       basewin.destroy();
  2153.     } catch (e) {}
  2154.   }
  2155. }
  2156.  
  2157. //-----------------------------------------------------------------------------------
  2158. var nsOpenRemoteCommand =
  2159. {
  2160.   isCommandEnabled: function(aCommand, dummy)
  2161.   {
  2162.     return true;    // we can always do this
  2163.   },
  2164.  
  2165.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2166.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2167.  
  2168.   doCommand: function(aCommand)
  2169.   {
  2170.       /* The last parameter is the current browser window.
  2171.          Use 0 and the default checkbox will be to load into an editor
  2172.          and loading into existing browser option is removed
  2173.        */
  2174.       window.openDialog( "chrome://communicator/content/openLocation.xul", "_blank", "chrome,modal,titlebar", 0);
  2175.     window.content.focus();
  2176.   }
  2177. };
  2178.  
  2179. //-----------------------------------------------------------------------------------
  2180. var nsPreviewCommand =
  2181. {
  2182.   isCommandEnabled: function(aCommand, dummy)
  2183.   {
  2184.     return (IsDocumentEditable() && 
  2185.             IsHTMLEditor() && 
  2186.             (DocumentHasBeenSaved() || IsDocumentModified()));
  2187.   },
  2188.  
  2189.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2190.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2191.  
  2192.   doCommand: function(aCommand)
  2193.   {
  2194.       // Don't continue if user canceled during prompt for saving
  2195.     // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
  2196.     if (!CheckAndSaveDocument("cmd_preview", DocumentHasBeenSaved()))
  2197.         return;
  2198.  
  2199.     // Check if we saved again just in case?
  2200.       if (DocumentHasBeenSaved())
  2201.     {
  2202.       var browser;
  2203.       try {
  2204.         // Find a browser with this URL
  2205.         var windowManager = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
  2206.         var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
  2207.         var enumerator = windowManagerInterface.getEnumerator("navigator:browser");
  2208.  
  2209.         var documentURI = GetDocumentUrl();
  2210.         while ( enumerator.hasMoreElements() )
  2211.         {
  2212.           browser = enumerator.getNext().QueryInterface(Components.interfaces.nsIDOMWindowInternal);
  2213.           if ( browser && (documentURI == browser.getBrowser().currentURI.spec))
  2214.             break;
  2215.  
  2216.           browser = null;
  2217.         }
  2218.       }
  2219.       catch (ex) {}
  2220.  
  2221.       // If none found, open a new browser
  2222.       if (!browser)
  2223.       {
  2224.         browser = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", documentURI);
  2225.       }
  2226.       else
  2227.       {
  2228.         try {
  2229.           browser.BrowserReloadSkipCache();
  2230.           browser.focus();
  2231.         } catch (ex) {}
  2232.       }
  2233.     }
  2234.   }
  2235. };
  2236.  
  2237. //-----------------------------------------------------------------------------------
  2238. var nsSendPageCommand =
  2239. {
  2240.   isCommandEnabled: function(aCommand, dummy)
  2241.   {
  2242.     return (IsDocumentEditable() &&
  2243.             (DocumentHasBeenSaved() || IsDocumentModified()));
  2244.   },
  2245.  
  2246.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2247.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2248.  
  2249.   doCommand: function(aCommand)
  2250.   {
  2251.     // Don't continue if user canceled during prompt for saving
  2252.     // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
  2253.     if (!CheckAndSaveDocument("cmd_editSendPage", DocumentHasBeenSaved()))
  2254.         return;
  2255.  
  2256.     // Check if we saved again just in case?
  2257.     if (DocumentHasBeenSaved())
  2258.     {
  2259.       // Launch Messenger Composer window with current page as contents
  2260.       try
  2261.       {
  2262.         openComposeWindow(GetDocumentUrl(), GetDocumentTitle());        
  2263.       } catch (ex) { dump("Cannot Send Page: " + ex + "\n"); }
  2264.     }
  2265.   }
  2266. };
  2267.  
  2268. //-----------------------------------------------------------------------------------
  2269. var nsPrintCommand =
  2270. {
  2271.   isCommandEnabled: function(aCommand, dummy)
  2272.   {
  2273.     return true;    // we can always do this
  2274.   },
  2275.  
  2276.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2277.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2278.  
  2279.   doCommand: function(aCommand)
  2280.   {
  2281.     // In editor.js
  2282.     FinishHTMLSource();
  2283.     try {
  2284.       NSPrint();
  2285.     } catch (e) {}
  2286.   }
  2287. };
  2288.  
  2289. //-----------------------------------------------------------------------------------
  2290. var nsPrintSetupCommand =
  2291. {
  2292.   isCommandEnabled: function(aCommand, dummy)
  2293.   {
  2294.     return true;    // we can always do this
  2295.   },
  2296.  
  2297.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2298.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2299.  
  2300.   doCommand: function(aCommand)
  2301.   {
  2302.     // In editor.js
  2303.     FinishHTMLSource();
  2304.     NSPrintSetup();
  2305.   }
  2306. };
  2307.  
  2308. //-----------------------------------------------------------------------------------
  2309. var nsQuitCommand =
  2310. {
  2311.   isCommandEnabled: function(aCommand, dummy)
  2312.   {
  2313.     return true;    // we can always do this
  2314.   },
  2315.  
  2316.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2317.   doCommandParams: function(aCommand, aParams, aRefCon) {}
  2318.  
  2319.   /* The doCommand is not used, since cmd_quit's oncommand="goQuitApplication()" in platformCommunicatorOverlay.xul
  2320.   doCommand: function(aCommand)
  2321.   {
  2322.     // In editor.js
  2323.     FinishHTMLSource();
  2324.     goQuitApplication();
  2325.   }
  2326.   */
  2327. };
  2328.  
  2329. //-----------------------------------------------------------------------------------
  2330. var nsFindCommand =
  2331. {
  2332.   isCommandEnabled: function(aCommand, editorElement)
  2333.   {
  2334.     return editorElement.getEditor(editorElement.contentWindow) != null;
  2335.   },
  2336.  
  2337.   getCommandStateParams: function(aCommand, aParams, editorElement) {},
  2338.   doCommandParams: function(aCommand, aParams, editorElement) {},
  2339.  
  2340.   doCommand: function(aCommand, editorElement)
  2341.   {
  2342.     try {
  2343.       window.openDialog("chrome://editor/content/EdReplace.xul", "_blank",
  2344.                         "chrome,modal,titlebar", editorElement);
  2345.     }
  2346.     catch(ex) {
  2347.       dump("*** Exception: couldn't open Replace Dialog\n");
  2348.     }
  2349.     //window.content.focus();
  2350.   }
  2351. };
  2352.  
  2353. //-----------------------------------------------------------------------------------
  2354. var nsFindAgainCommand =
  2355. {
  2356.   isCommandEnabled: function(aCommand, editorElement)
  2357.   {
  2358.     // we can only do this if the search pattern is non-empty. Not sure how
  2359.     // to get that from here
  2360.     return editorElement.getEditor(editorElement.contentWindow) != null;
  2361.   },
  2362.  
  2363.   getCommandStateParams: function(aCommand, aParams, editorElement) {},
  2364.   doCommandParams: function(aCommand, aParams, editorElement) {},
  2365.  
  2366.   doCommand: function(aCommand, editorElement)
  2367.   {
  2368.     try {
  2369.       var findPrev = aCommand == "cmd_findPrev";
  2370.       var findInst = editorElement.webBrowserFind;
  2371.       var findService = Components.classes["@mozilla.org/find/find_service;1"]
  2372.                                   .getService(Components.interfaces.nsIFindService);
  2373.       findInst.findBackwards = findService.findBackwards ^ findPrev;
  2374.       findInst.findNext();
  2375.       // reset to what it was in dialog, otherwise dialog setting can get reversed
  2376.       findInst.findBackwards = findService.findBackwards; 
  2377.     }
  2378.     catch (ex) {}
  2379.   }
  2380. };
  2381.  
  2382. //-----------------------------------------------------------------------------------
  2383. var nsRewrapCommand =
  2384. {
  2385.   isCommandEnabled: function(aCommand, dummy)
  2386.   {
  2387.     return (IsDocumentEditable() && !IsInHTMLSourceMode() &&
  2388.             GetCurrentEditor() instanceof Components.interfaces.nsIEditorMailSupport);
  2389.   },
  2390.  
  2391.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2392.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2393.  
  2394.   doCommand: function(aCommand)
  2395.   {
  2396.     GetCurrentEditor().QueryInterface(Components.interfaces.nsIEditorMailSupport).rewrap(false);
  2397.   }
  2398. };
  2399.  
  2400. //-----------------------------------------------------------------------------------
  2401. var nsSpellingCommand =
  2402. {
  2403.   isCommandEnabled: function(aCommand, dummy)
  2404.   {
  2405.     return (IsDocumentEditable() && 
  2406.             !IsInHTMLSourceMode() && IsSpellCheckerInstalled());
  2407.   },
  2408.  
  2409.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2410.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2411.  
  2412.   doCommand: function(aCommand)
  2413.   {
  2414.     window.cancelSendMessage = false;
  2415.     try {
  2416.       var skipBlockQuotes = (window.document.firstChild.getAttribute("windowtype") == "msgcompose");
  2417.       window.openDialog("chrome://editor/content/EdSpellCheck.xul", "_blank",
  2418.               "chrome,close,titlebar,modal", false, skipBlockQuotes, true);
  2419.     }
  2420.     catch(ex) {}
  2421.     window.content.focus();
  2422.   }
  2423. };
  2424.  
  2425. // Validate using http://validator.w3.org/file-upload.html
  2426. var URL2Validate;
  2427. var nsValidateCommand =
  2428. {
  2429.   isCommandEnabled: function(aCommand, dummy)
  2430.   {
  2431.     return GetCurrentEditor() != null;
  2432.   },
  2433.  
  2434.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2435.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2436.  
  2437.   doCommand: function(aCommand)
  2438.   {
  2439.     // If the document hasn't been modified,
  2440.     // then just validate the current url.
  2441.     if (IsDocumentModified() || IsHTMLSourceChanged())
  2442.     {
  2443.       if (!CheckAndSaveDocument("cmd_validate", false))
  2444.         return;
  2445.  
  2446.       // Check if we saved again just in case?
  2447.       if (!DocumentHasBeenSaved())    // user hit cancel?
  2448.         return;
  2449.     }
  2450.  
  2451.     URL2Validate = GetDocumentUrl();
  2452.     // See if it's a file:
  2453.     var ifile;
  2454.     try {
  2455.       var fileHandler = GetFileProtocolHandler();
  2456.       ifile = fileHandler.getFileFromURLSpec(URL2Validate);
  2457.       // nsIFile throws an exception if it's not a file url
  2458.     } catch (e) { ifile = null; }
  2459.     if (ifile)
  2460.     {
  2461.       URL2Validate = ifile.path;
  2462.       var vwin = window.open("http://validator.w3.org/file-upload.html",
  2463.                              "EditorValidate");
  2464.       // Window loads asynchronously, so pass control to the load listener:
  2465.       vwin.addEventListener("load", this.validateFilePageLoaded, false);
  2466.     }
  2467.     else
  2468.     {
  2469.       var vwin2 = window.open("http://validator.w3.org/check?uri="
  2470.                               + URL2Validate
  2471.                               + "&doctype=Inline",
  2472.                               "EditorValidate");
  2473.       // This does the validation, no need to wait for page loaded.
  2474.     }
  2475.   },
  2476.   validateFilePageLoaded: function(event)
  2477.   {
  2478.     event.target.forms[0].uploaded_file.value = URL2Validate;
  2479.   }
  2480. };
  2481.  
  2482. var nsCheckLinksCommand =
  2483. {
  2484.   isCommandEnabled: function(aCommand, dummy)
  2485.   {
  2486.     return (IsDocumentEditable());
  2487.   },
  2488.  
  2489.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2490.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2491.  
  2492.   doCommand: function(aCommand)
  2493.   {
  2494.     window.openDialog("chrome://editor/content/EdLinkChecker.xul","_blank", "chrome,close,titlebar,modal");
  2495.     window.content.focus();
  2496.   }
  2497. };
  2498.  
  2499. //-----------------------------------------------------------------------------------
  2500. var nsFormCommand =
  2501. {
  2502.   isCommandEnabled: function(aCommand, dummy)
  2503.   {
  2504.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2505.   },
  2506.  
  2507.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2508.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2509.  
  2510.   doCommand: function(aCommand)
  2511.   {
  2512.     window.openDialog("chrome://editor/content/EdFormProps.xul", "_blank", "chrome,close,titlebar,modal");
  2513.     window.content.focus();
  2514.   }
  2515. };
  2516.  
  2517. //-----------------------------------------------------------------------------------
  2518. var nsInputTagCommand =
  2519. {
  2520.   isCommandEnabled: function(aCommand, dummy)
  2521.   {
  2522.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2523.   },
  2524.  
  2525.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2526.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2527.  
  2528.   doCommand: function(aCommand)
  2529.   {
  2530.     window.openDialog("chrome://editor/content/EdInputProps.xul", "_blank", "chrome,close,titlebar,modal");
  2531.     window.content.focus();
  2532.   }
  2533. };
  2534.  
  2535. //-----------------------------------------------------------------------------------
  2536. var nsInputImageCommand =
  2537. {
  2538.   isCommandEnabled: function(aCommand, dummy)
  2539.   {
  2540.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2541.   },
  2542.  
  2543.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2544.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2545.  
  2546.   doCommand: function(aCommand)
  2547.   {
  2548.     window.openDialog("chrome://editor/content/EdInputImage.xul", "_blank", "chrome,close,titlebar,modal");
  2549.     window.content.focus();
  2550.   }
  2551. };
  2552.  
  2553. //-----------------------------------------------------------------------------------
  2554. var nsTextAreaCommand =
  2555. {
  2556.   isCommandEnabled: function(aCommand, dummy)
  2557.   {
  2558.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2559.   },
  2560.  
  2561.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2562.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2563.  
  2564.   doCommand: function(aCommand)
  2565.   {
  2566.     window.openDialog("chrome://editor/content/EdTextAreaProps.xul", "_blank", "chrome,close,titlebar,modal");
  2567.     window.content.focus();
  2568.   }
  2569. };
  2570.  
  2571. //-----------------------------------------------------------------------------------
  2572. var nsSelectCommand =
  2573. {
  2574.   isCommandEnabled: function(aCommand, dummy)
  2575.   {
  2576.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2577.   },
  2578.  
  2579.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2580.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2581.  
  2582.   doCommand: function(aCommand)
  2583.   {
  2584.     window.openDialog("chrome://editor/content/EdSelectProps.xul", "_blank", "chrome,close,titlebar,modal");
  2585.     window.content.focus();
  2586.   }
  2587. };
  2588.  
  2589. //-----------------------------------------------------------------------------------
  2590. var nsButtonCommand =
  2591. {
  2592.   isCommandEnabled: function(aCommand, dummy)
  2593.   {
  2594.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2595.   },
  2596.  
  2597.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2598.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2599.  
  2600.   doCommand: function(aCommand)
  2601.   {
  2602.     window.openDialog("chrome://editor/content/EdButtonProps.xul", "_blank", "chrome,close,titlebar,modal");
  2603.     window.content.focus();
  2604.   }
  2605. };
  2606.  
  2607. //-----------------------------------------------------------------------------------
  2608. var nsLabelCommand =
  2609. {
  2610.   isCommandEnabled: function(aCommand, dummy)
  2611.   {
  2612.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2613.   },
  2614.  
  2615.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2616.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2617.  
  2618.   doCommand: function(aCommand)
  2619.   {
  2620.     var tagName = "label";
  2621.     try {
  2622.       var editor = GetCurrentEditor();
  2623.       // Find selected label or if start/end of selection is in label 
  2624.       var labelElement = editor.getSelectedElement(tagName);
  2625.       if (!labelElement)
  2626.         labelElement = editor.getElementOrParentByTagName(tagName, editor.selection.anchorNode);
  2627.       if (!labelElement)
  2628.         labelElement = editor.getElementOrParentByTagName(tagName, editor.selection.focusNode);
  2629.       if (labelElement) {
  2630.         // We only open the dialog for an existing label
  2631.         window.openDialog("chrome://editor/content/EdLabelProps.xul", "_blank", "chrome,close,titlebar,modal", labelElement);
  2632.         window.content.focus();
  2633.       } else {
  2634.         EditorSetTextProperty(tagName, "", "");
  2635.       }
  2636.     } catch (e) {}
  2637.   }
  2638. };
  2639.  
  2640. //-----------------------------------------------------------------------------------
  2641. var nsFieldSetCommand =
  2642. {
  2643.   isCommandEnabled: function(aCommand, dummy)
  2644.   {
  2645.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2646.   },
  2647.  
  2648.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2649.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2650.  
  2651.   doCommand: function(aCommand)
  2652.   {
  2653.     window.openDialog("chrome://editor/content/EdFieldSetProps.xul", "_blank", "chrome,close,titlebar,modal");
  2654.     window.content.focus();
  2655.   }
  2656. };
  2657.  
  2658. //-----------------------------------------------------------------------------------
  2659. var nsIsIndexCommand =
  2660. {
  2661.   isCommandEnabled: function(aCommand, dummy)
  2662.   {
  2663.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2664.   },
  2665.  
  2666.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2667.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2668.  
  2669.   doCommand: function(aCommand)
  2670.   {
  2671.     try {
  2672.       var editor = GetCurrentEditor();
  2673.       var isindexElement = editor.createElementWithDefaults("isindex");
  2674.       isindexElement.setAttribute("prompt", editor.outputToString("text/plain", 1)); // OutputSelectionOnly
  2675.       editor.insertElementAtSelection(isindexElement, true);
  2676.     } catch (e) {}
  2677.   }
  2678. };
  2679.  
  2680. //-----------------------------------------------------------------------------------
  2681. var nsImageCommand =
  2682. {
  2683.   isCommandEnabled: function(aCommand, dummy)
  2684.   {
  2685.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2686.   },
  2687.  
  2688.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2689.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2690.  
  2691.   doCommand: function(aCommand)
  2692.   {
  2693.     window.openDialog("chrome://editor/content/EdImageProps.xul","_blank", "chrome,close,titlebar,modal");
  2694.     window.content.focus();
  2695.   }
  2696. };
  2697.  
  2698. //-----------------------------------------------------------------------------------
  2699. var nsHLineCommand =
  2700. {
  2701.   isCommandEnabled: function(aCommand, dummy)
  2702.   {
  2703.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2704.   },
  2705.  
  2706.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2707.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2708.  
  2709.   doCommand: function(aCommand)
  2710.   {
  2711.     // Inserting an HLine is different in that we don't use properties dialog
  2712.     //  unless we are editing an existing line's attributes
  2713.     //  We get the last-used attributes from the prefs and insert immediately
  2714.  
  2715.     var tagName = "hr";
  2716.     var editor = GetCurrentEditor();
  2717.       
  2718.     var hLine;
  2719.     try {
  2720.       hLine = editor.getSelectedElement(tagName);
  2721.     } catch (e) {return;}
  2722.  
  2723.     if (hLine)
  2724.     {
  2725.       // We only open the dialog for an existing HRule
  2726.       window.openDialog("chrome://editor/content/EdHLineProps.xul", "_blank", "chrome,close,titlebar,modal");
  2727.       window.content.focus();
  2728.     } 
  2729.     else
  2730.     {
  2731.       try {
  2732.         hLine = editor.createElementWithDefaults(tagName);
  2733.  
  2734.         // We change the default attributes to those saved in the user prefs
  2735.         var prefs = GetPrefs();
  2736.         var align = prefs.getIntPref("editor.hrule.align");
  2737.         if (align == 0)
  2738.           editor.setAttributeOrEquivalent(hLine, "align", "left", true);
  2739.         else if (align == 2)
  2740.           editor.setAttributeOrEquivalent(hLine, "align", "right", true);
  2741.  
  2742.         //Note: Default is center (don't write attribute)
  2743.   
  2744.         var width = prefs.getIntPref("editor.hrule.width");
  2745.         var percent = prefs.getBoolPref("editor.hrule.width_percent");
  2746.         if (percent)
  2747.           width = width +"%";
  2748.  
  2749.         editor.setAttributeOrEquivalent(hLine, "width", width, true);
  2750.  
  2751.         var height = prefs.getIntPref("editor.hrule.height");
  2752.         editor.setAttributeOrEquivalent(hLine, "size", String(height), true);
  2753.  
  2754.         var shading = prefs.getBoolPref("editor.hrule.shading");
  2755.         if (shading)
  2756.           hLine.removeAttribute("noshade");
  2757.         else
  2758.           hLine.setAttribute("noshade", "noshade");
  2759.  
  2760.         editor.insertElementAtSelection(hLine, true);
  2761.  
  2762.       } catch (e) {}
  2763.     }
  2764.   }
  2765. };
  2766.  
  2767. //-----------------------------------------------------------------------------------
  2768. var nsLinkCommand =
  2769. {
  2770.   isCommandEnabled: function(aCommand, dummy)
  2771.   {
  2772.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2773.   },
  2774.  
  2775.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2776.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2777.  
  2778.   doCommand: function(aCommand)
  2779.   {
  2780.     // If selected element is an image, launch that dialog instead 
  2781.     // since last tab panel handles link around an image
  2782.     var element = GetObjectForProperties();
  2783.     if (element && element.nodeName.toLowerCase() == "img")
  2784.       window.openDialog("chrome://editor/content/EdImageProps.xul","_blank", "chrome,close,titlebar,modal", null, true);
  2785.     else
  2786.       window.openDialog("chrome://editor/content/EdLinkProps.xul","_blank", "chrome,close,titlebar,modal");
  2787.     window.content.focus();
  2788.   }
  2789. };
  2790.  
  2791. //-----------------------------------------------------------------------------------
  2792. var nsAnchorCommand =
  2793. {
  2794.   isCommandEnabled: function(aCommand, dummy)
  2795.   {
  2796.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2797.   },
  2798.  
  2799.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2800.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2801.  
  2802.   doCommand: function(aCommand)
  2803.   {
  2804.     window.openDialog("chrome://editor/content/EdNamedAnchorProps.xul", "_blank", "chrome,close,titlebar,modal", "");
  2805.     window.content.focus();
  2806.   }
  2807. };
  2808.  
  2809. //-----------------------------------------------------------------------------------
  2810. var nsInsertHTMLWithDialogCommand =
  2811. {
  2812.   isCommandEnabled: function(aCommand, dummy)
  2813.   {
  2814.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2815.   },
  2816.  
  2817.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2818.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2819.  
  2820.   doCommand: function(aCommand)
  2821.   {
  2822.     window.openDialog("chrome://editor/content/EdInsSrc.xul","_blank", "chrome,close,titlebar,modal,resizable", "");
  2823.     window.content.focus();
  2824.   }
  2825. };
  2826.  
  2827. //-----------------------------------------------------------------------------------
  2828. var nsInsertCharsCommand =
  2829. {
  2830.   isCommandEnabled: function(aCommand, dummy)
  2831.   {
  2832.     return (IsDocumentEditable());
  2833.   },
  2834.  
  2835.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2836.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2837.  
  2838.   doCommand: function(aCommand)
  2839.   {
  2840.     EditorFindOrCreateInsertCharWindow();
  2841.   }
  2842. };
  2843.  
  2844. //-----------------------------------------------------------------------------------
  2845. var nsInsertBreakCommand =
  2846. {
  2847.   isCommandEnabled: function(aCommand, dummy)
  2848.   {
  2849.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2850.   },
  2851.  
  2852.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2853.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2854.  
  2855.   doCommand: function(aCommand)
  2856.   {
  2857.     try {
  2858.       GetCurrentEditor().insertHTML("<br>");
  2859.     } catch (e) {}
  2860.   }
  2861. };
  2862.  
  2863. //-----------------------------------------------------------------------------------
  2864. var nsInsertBreakAllCommand =
  2865. {
  2866.   isCommandEnabled: function(aCommand, dummy)
  2867.   {
  2868.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2869.   },
  2870.  
  2871.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2872.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2873.  
  2874.   doCommand: function(aCommand)
  2875.   {
  2876.     try {
  2877.       GetCurrentEditor().insertHTML("<br clear='all'>");
  2878.     } catch (e) {}
  2879.   }
  2880. };
  2881.  
  2882. //-----------------------------------------------------------------------------------
  2883. var nsGridCommand =
  2884. {
  2885.   isCommandEnabled: function(aCommand, dummy)
  2886.   {
  2887.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2888.   },
  2889.  
  2890.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2891.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2892.  
  2893.   doCommand: function(aCommand)
  2894.   {
  2895.     window.openDialog("chrome://editor/content/EdSnapToGrid.xul","_blank", "chrome,close,titlebar,modal");
  2896.     window.content.focus();
  2897.   }
  2898. };
  2899.  
  2900.  
  2901. //-----------------------------------------------------------------------------------
  2902. var nsListPropertiesCommand =
  2903. {
  2904.   isCommandEnabled: function(aCommand, dummy)
  2905.   {
  2906.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2907.   },
  2908.  
  2909.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2910.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2911.  
  2912.   doCommand: function(aCommand)
  2913.   {
  2914.     window.openDialog("chrome://editor/content/EdListProps.xul","_blank", "chrome,close,titlebar,modal");
  2915.     window.content.focus();
  2916.   }
  2917. };
  2918.  
  2919.  
  2920. //-----------------------------------------------------------------------------------
  2921. var nsPagePropertiesCommand =
  2922. {
  2923.   isCommandEnabled: function(aCommand, dummy)
  2924.   {
  2925.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  2926.   },
  2927.  
  2928.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2929.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2930.  
  2931.   doCommand: function(aCommand)
  2932.   {
  2933.     var oldTitle = GetDocumentTitle();
  2934.     window.openDialog("chrome://editor/content/EdPageProps.xul","_blank", "chrome,close,titlebar,modal", "");
  2935.  
  2936.     // Update main window title and 
  2937.     // recent menu data in prefs if doc title changed
  2938.     if (GetDocumentTitle() != oldTitle)
  2939.       UpdateWindowTitle();
  2940.  
  2941.     window.content.focus();
  2942.   }
  2943. };
  2944.  
  2945. //-----------------------------------------------------------------------------------
  2946. var nsObjectPropertiesCommand =
  2947. {
  2948.   isCommandEnabled: function(aCommand, dummy)
  2949.   {
  2950.     var isEnabled = false;
  2951.     if (IsDocumentEditable() && IsEditingRenderedHTML())
  2952.     {
  2953.       isEnabled = (GetObjectForProperties() != null ||
  2954.                    GetCurrentEditor().getSelectedElement("href") != null);
  2955.     }
  2956.     return isEnabled;
  2957.   },
  2958.  
  2959.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  2960.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  2961.  
  2962.   doCommand: function(aCommand)
  2963.   {
  2964.     // Launch Object properties for appropriate selected element 
  2965.     var element = GetObjectForProperties();
  2966.     if (element)
  2967.     {
  2968.       var name = element.nodeName.toLowerCase();
  2969.       switch (name)
  2970.       {
  2971.         case 'img':
  2972.           goDoCommand("cmd_image");
  2973.           break;
  2974.         case 'hr':
  2975.           goDoCommand("cmd_hline");
  2976.           break;
  2977.         case 'form':
  2978.           goDoCommand("cmd_form");
  2979.           break;
  2980.         case 'input':
  2981.           var type = element.getAttribute("type");
  2982.           if (type && type.toLowerCase() == "image")
  2983.             goDoCommand("cmd_inputimage");
  2984.           else
  2985.             goDoCommand("cmd_inputtag");
  2986.           break;
  2987.         case 'textarea':
  2988.           goDoCommand("cmd_textarea");
  2989.           break;
  2990.         case 'select':
  2991.           goDoCommand("cmd_select");
  2992.           break;
  2993.         case 'button':
  2994.           goDoCommand("cmd_button");
  2995.           break;
  2996.         case 'label':
  2997.           goDoCommand("cmd_label");
  2998.           break;
  2999.         case 'fieldset':
  3000.           goDoCommand("cmd_fieldset");
  3001.           break;
  3002.         case 'table':
  3003.           EditorInsertOrEditTable(false);
  3004.           break;
  3005.         case 'td':
  3006.         case 'th':
  3007.           EditorTableCellProperties();
  3008.           break;
  3009.         case 'ol':
  3010.         case 'ul':
  3011.         case 'dl':
  3012.         case 'li':
  3013.           goDoCommand("cmd_listProperties");
  3014.           break;
  3015.         case 'a':
  3016.           if (element.name)
  3017.           {
  3018.             goDoCommand("cmd_anchor");
  3019.           }
  3020.           else if(element.href)
  3021.           {
  3022.             goDoCommand("cmd_link");
  3023.           }
  3024.           break;
  3025.         default:
  3026.           doAdvancedProperties(element);
  3027.           break;
  3028.       }
  3029.     } else {
  3030.       // We get a partially-selected link if asked for specifically
  3031.       try {
  3032.         element = GetCurrentEditor().getSelectedElement("href");
  3033.       } catch (e) {}
  3034.       if (element)
  3035.         goDoCommand("cmd_link");
  3036.     }
  3037.     window.content.focus();
  3038.   }
  3039. };
  3040.  
  3041.  
  3042. //-----------------------------------------------------------------------------------
  3043. var nsSetSmiley =
  3044. {
  3045.   isCommandEnabled: function(aCommand, dummy)
  3046.   {
  3047.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  3048.   },
  3049.  
  3050.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3051.   doCommandParams: function(aCommand, aParams, aRefCon)
  3052.   {
  3053.     var smileyCode = aParams.getCStringValue("state_attribute");
  3054.     
  3055.     var strSml;
  3056.     switch(smileyCode)
  3057.     {
  3058.         case ":-)": strSml="s1"; 
  3059.         break;
  3060.         case ":-(": strSml="s2";
  3061.         break;
  3062.         case ";-)": strSml="s3";
  3063.         break;
  3064.         case ":-P": strSml="s4";
  3065.         break;
  3066.         case ":-D": strSml="s5";
  3067.         break;
  3068.         case ":-[": strSml="s6";
  3069.         break;
  3070.         case ":-\\": 
  3071.         case ":\\": strSml="s7";
  3072.         break;
  3073.         case "=-O": strSml="s8";
  3074.         break;
  3075.         case ":-*": strSml="s9";
  3076.         break;
  3077.         case ">:o":
  3078.         case ">:-o": strSml="s10";
  3079.         break;
  3080.         case "8-)": strSml="s11";
  3081.         break;
  3082.         case ":-$": strSml="s12";
  3083.         break;
  3084.         case ":-!": strSml="s13";
  3085.         break;
  3086.         case "O:-)": strSml="s14";
  3087.         break;
  3088.         case ":'(": strSml="s15";
  3089.         break;
  3090.         case ":-X": strSml="s16";
  3091.         break;
  3092.         default:    strSml="";
  3093.         break;
  3094.     }
  3095.  
  3096.     try 
  3097.     {
  3098.       var editor = GetCurrentEditor();
  3099.       var selection = editor.selection;
  3100.       var extElement = editor.createElementWithDefaults("span");
  3101.       extElement.setAttribute("class", "moz-smiley-" + strSml);
  3102.  
  3103.       var intElement = editor.createElementWithDefaults("span");
  3104.       if (!intElement)
  3105.         return;
  3106.  
  3107.       //just for mailnews, because of the way it removes HTML
  3108.       var smileButMenu = document.getElementById('smileButtonMenu');      
  3109.       if (smileButMenu.getAttribute("padwithspace"))
  3110.          smileyCode = " " + smileyCode + " ";
  3111.  
  3112.       var txtElement =  editor.document.createTextNode(smileyCode);
  3113.       if (!txtElement)
  3114.         return;
  3115.  
  3116.       intElement.appendChild (txtElement);
  3117.       extElement.appendChild (intElement);
  3118.  
  3119.  
  3120.       editor.insertElementAtSelection(extElement,true);
  3121.       window.content.focus();        
  3122.  
  3123.     } 
  3124.     catch (e) 
  3125.     {
  3126.         dump("Exception occured in smiley InsertElementAtSelection\n");
  3127.     }
  3128.   },
  3129.   // This is now deprecated in favor of "doCommandParams"
  3130.   doCommand: function(aCommand) {}
  3131. };
  3132.  
  3133.  
  3134. function doAdvancedProperties(element)
  3135. {
  3136.   if (element)
  3137.   {
  3138.     window.openDialog("chrome://editor/content/EdAdvancedEdit.xul", "_blank", "chrome,close,titlebar,modal,resizable=yes", "", element);
  3139.     window.content.focus();
  3140.   }
  3141. }
  3142.  
  3143. var nsAdvancedPropertiesCommand =
  3144. {
  3145.   isCommandEnabled: function(aCommand, dummy)
  3146.   {
  3147.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  3148.   },
  3149.  
  3150.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3151.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3152.  
  3153.   doCommand: function(aCommand)
  3154.   {
  3155.     // Launch AdvancedEdit dialog for the selected element
  3156.     try {
  3157.       var element = GetCurrentEditor().getSelectedElement("");
  3158.       doAdvancedProperties(element);
  3159.     } catch (e) {}
  3160.   }
  3161. };
  3162.  
  3163. //-----------------------------------------------------------------------------------
  3164. var nsColorPropertiesCommand =
  3165. {
  3166.   isCommandEnabled: function(aCommand, dummy)
  3167.   {
  3168.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  3169.   },
  3170.  
  3171.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3172.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3173.  
  3174.   doCommand: function(aCommand)
  3175.   {
  3176.     window.openDialog("chrome://editor/content/EdColorProps.xul","_blank", "chrome,close,titlebar,modal", ""); 
  3177.     UpdateDefaultColors(); 
  3178.     window.content.focus();
  3179.   }
  3180. };
  3181.  
  3182. //-----------------------------------------------------------------------------------
  3183. var nsRemoveNamedAnchorsCommand =
  3184. {
  3185.   isCommandEnabled: function(aCommand, dummy)
  3186.   {
  3187.     // We could see if there's any link in selection, but it doesn't seem worth the work!
  3188.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  3189.   },
  3190.  
  3191.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3192.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3193.  
  3194.   doCommand: function(aCommand)
  3195.   {
  3196.     EditorRemoveTextProperty("name", "");
  3197.     window.content.focus();
  3198.   }
  3199. };
  3200.  
  3201.  
  3202. //-----------------------------------------------------------------------------------
  3203. var nsEditLinkCommand =
  3204. {
  3205.   isCommandEnabled: function(aCommand, dummy)
  3206.   {
  3207.     // Not really used -- this command is only in context menu, and we do enabling there
  3208.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  3209.   },
  3210.  
  3211.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3212.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3213.  
  3214.   doCommand: function(aCommand)
  3215.   {
  3216.     try {
  3217.       var element = GetCurrentEditor().getSelectedElement("href");
  3218.       if (element)
  3219.         editPage(element.href, window, false);
  3220.     } catch (e) {}
  3221.     window.content.focus();
  3222.   }
  3223. };
  3224.  
  3225.  
  3226. //-----------------------------------------------------------------------------------
  3227. var nsNormalModeCommand =
  3228. {
  3229.   isCommandEnabled: function(aCommand, dummy)
  3230.   {
  3231.     return IsHTMLEditor() && IsDocumentEditable();
  3232.   },
  3233.  
  3234.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3235.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3236.  
  3237.   doCommand: function(aCommand)
  3238.   {
  3239.     SetEditMode(kDisplayModeNormal);
  3240.   }
  3241. };
  3242.  
  3243. var nsAllTagsModeCommand =
  3244. {
  3245.   isCommandEnabled: function(aCommand, dummy)
  3246.   {
  3247.     return (IsDocumentEditable() && IsHTMLEditor());
  3248.   },
  3249.  
  3250.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3251.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3252.  
  3253.   doCommand: function(aCommand)
  3254.   {
  3255.     SetEditMode(kDisplayModeAllTags);
  3256.   }
  3257. };
  3258.  
  3259. var nsHTMLSourceModeCommand =
  3260. {
  3261.   isCommandEnabled: function(aCommand, dummy)
  3262.   {
  3263.     return (IsDocumentEditable() && IsHTMLEditor());
  3264.   },
  3265.  
  3266.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3267.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3268.  
  3269.   doCommand: function(aCommand)
  3270.   {
  3271.     SetEditMode(kDisplayModeSource);
  3272.   }
  3273. };
  3274.  
  3275. var nsPreviewModeCommand =
  3276. {
  3277.   isCommandEnabled: function(aCommand, dummy)
  3278.   {
  3279.     return (IsDocumentEditable() && IsHTMLEditor());
  3280.   },
  3281.  
  3282.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3283.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3284.  
  3285.   doCommand: function(aCommand)
  3286.   {
  3287.     SetEditMode(kDisplayModePreview);
  3288.   }
  3289. };
  3290.  
  3291. //-----------------------------------------------------------------------------------
  3292. var nsInsertOrEditTableCommand =
  3293. {
  3294.   isCommandEnabled: function(aCommand, dummy)
  3295.   {
  3296.     return (IsDocumentEditable() && IsEditingRenderedHTML());
  3297.   },
  3298.  
  3299.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3300.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3301.  
  3302.   doCommand: function(aCommand)
  3303.   {
  3304.     if (IsInTableCell())
  3305.       EditorTableCellProperties();
  3306.     else
  3307.       EditorInsertOrEditTable(true);
  3308.   }
  3309. };
  3310.  
  3311. //-----------------------------------------------------------------------------------
  3312. var nsEditTableCommand =
  3313. {
  3314.   isCommandEnabled: function(aCommand, dummy)
  3315.   {
  3316.     return IsInTable();
  3317.   },
  3318.  
  3319.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3320.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3321.  
  3322.   doCommand: function(aCommand)
  3323.   {
  3324.     EditorInsertOrEditTable(false);
  3325.   }
  3326. };
  3327.  
  3328. //-----------------------------------------------------------------------------------
  3329. var nsSelectTableCommand =
  3330. {
  3331.   isCommandEnabled: function(aCommand, dummy)
  3332.   {
  3333.     return IsInTable();
  3334.   },
  3335.  
  3336.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3337.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3338.  
  3339.   doCommand: function(aCommand)
  3340.   {
  3341.     try {
  3342.       GetCurrentTableEditor().selectTable();
  3343.     } catch(e) {}
  3344.     window.content.focus();
  3345.   }
  3346. };
  3347.  
  3348. var nsSelectTableRowCommand =
  3349. {
  3350.   isCommandEnabled: function(aCommand, dummy)
  3351.   {
  3352.     return IsInTableCell();
  3353.   },
  3354.  
  3355.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3356.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3357.  
  3358.   doCommand: function(aCommand)
  3359.   {
  3360.     try {
  3361.       GetCurrentTableEditor().selectTableRow();
  3362.     } catch(e) {}
  3363.     window.content.focus();
  3364.   }
  3365. };
  3366.  
  3367. var nsSelectTableColumnCommand =
  3368. {
  3369.   isCommandEnabled: function(aCommand, dummy)
  3370.   {
  3371.     return IsInTableCell();
  3372.   },
  3373.  
  3374.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3375.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3376.  
  3377.   doCommand: function(aCommand)
  3378.   {
  3379.     try {
  3380.       GetCurrentTableEditor().selectTableColumn();
  3381.     } catch(e) {}
  3382.     window.content.focus();
  3383.   }
  3384. };
  3385.  
  3386. var nsSelectTableCellCommand =
  3387. {
  3388.   isCommandEnabled: function(aCommand, dummy)
  3389.   {
  3390.     return IsInTableCell();
  3391.   },
  3392.  
  3393.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3394.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3395.  
  3396.   doCommand: function(aCommand)
  3397.   {
  3398.     try {
  3399.       GetCurrentTableEditor().selectTableCell();
  3400.     } catch(e) {}
  3401.     window.content.focus();
  3402.   }
  3403. };
  3404.  
  3405. var nsSelectAllTableCellsCommand =
  3406. {
  3407.   isCommandEnabled: function(aCommand, dummy)
  3408.   {
  3409.     return IsInTable();
  3410.   },
  3411.  
  3412.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3413.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3414.  
  3415.   doCommand: function(aCommand)
  3416.   {
  3417.     try {
  3418.       GetCurrentTableEditor().selectAllTableCells();
  3419.     } catch(e) {}
  3420.     window.content.focus();
  3421.   }
  3422. };
  3423.  
  3424. //-----------------------------------------------------------------------------------
  3425. var nsInsertTableCommand =
  3426. {
  3427.   isCommandEnabled: function(aCommand, dummy)
  3428.   {
  3429.     return IsDocumentEditable() && IsEditingRenderedHTML();
  3430.   },
  3431.  
  3432.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3433.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3434.  
  3435.   doCommand: function(aCommand)
  3436.   {
  3437.     EditorInsertTable();
  3438.   }
  3439. };
  3440.  
  3441. var nsInsertTableRowAboveCommand =
  3442. {
  3443.   isCommandEnabled: function(aCommand, dummy)
  3444.   {
  3445.     return IsInTableCell();
  3446.   },
  3447.  
  3448.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3449.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3450.  
  3451.   doCommand: function(aCommand)
  3452.   {
  3453.     try {
  3454.       GetCurrentTableEditor().insertTableRow(1, false);
  3455.     } catch(e) {}
  3456.     window.content.focus();
  3457.   }
  3458. };
  3459.  
  3460. var nsInsertTableRowBelowCommand =
  3461. {
  3462.   isCommandEnabled: function(aCommand, dummy)
  3463.   {
  3464.     return IsInTableCell();
  3465.   },
  3466.  
  3467.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3468.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3469.  
  3470.   doCommand: function(aCommand)
  3471.   {
  3472.     try {
  3473.       GetCurrentTableEditor().insertTableRow(1, true);
  3474.     } catch(e) {}
  3475.     window.content.focus();
  3476.   }
  3477. };
  3478.  
  3479. var nsInsertTableColumnBeforeCommand =
  3480. {
  3481.   isCommandEnabled: function(aCommand, dummy)
  3482.   {
  3483.     return IsInTableCell();
  3484.   },
  3485.  
  3486.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3487.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3488.  
  3489.   doCommand: function(aCommand)
  3490.   {
  3491.     try {
  3492.       GetCurrentTableEditor().insertTableColumn(1, false);
  3493.     } catch(e) {}
  3494.     window.content.focus();
  3495.   }
  3496. };
  3497.  
  3498. var nsInsertTableColumnAfterCommand =
  3499. {
  3500.   isCommandEnabled: function(aCommand, dummy)
  3501.   {
  3502.     return IsInTableCell();
  3503.   },
  3504.  
  3505.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3506.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3507.  
  3508.   doCommand: function(aCommand)
  3509.   {
  3510.     try {
  3511.       GetCurrentTableEditor().insertTableColumn(1, true);
  3512.     } catch(e) {}
  3513.     window.content.focus();
  3514.   }
  3515. };
  3516.  
  3517. var nsInsertTableCellBeforeCommand =
  3518. {
  3519.   isCommandEnabled: function(aCommand, dummy)
  3520.   {
  3521.     return IsInTableCell();
  3522.   },
  3523.  
  3524.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3525.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3526.  
  3527.   doCommand: function(aCommand)
  3528.   {
  3529.     try {
  3530.       GetCurrentTableEditor().insertTableCell(1, false);
  3531.     } catch(e) {}
  3532.     window.content.focus();
  3533.   }
  3534. };
  3535.  
  3536. var nsInsertTableCellAfterCommand =
  3537. {
  3538.   isCommandEnabled: function(aCommand, dummy)
  3539.   {
  3540.     return IsInTableCell();
  3541.   },
  3542.  
  3543.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3544.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3545.  
  3546.   doCommand: function(aCommand)
  3547.   {
  3548.     try {
  3549.       GetCurrentTableEditor().insertTableCell(1, true);
  3550.     } catch(e) {}
  3551.     window.content.focus();
  3552.   }
  3553. };
  3554.  
  3555. //-----------------------------------------------------------------------------------
  3556. var nsDeleteTableCommand =
  3557. {
  3558.   isCommandEnabled: function(aCommand, dummy)
  3559.   {
  3560.     return IsInTable();
  3561.   },
  3562.  
  3563.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3564.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3565.  
  3566.   doCommand: function(aCommand)
  3567.   {
  3568.     try {
  3569.       GetCurrentTableEditor().deleteTable();
  3570.     } catch(e) {}
  3571.     window.content.focus();
  3572.   }
  3573. };
  3574.  
  3575. var nsDeleteTableRowCommand =
  3576. {
  3577.   isCommandEnabled: function(aCommand, dummy)
  3578.   {
  3579.     return IsInTableCell();
  3580.   },
  3581.  
  3582.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3583.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3584.  
  3585.   doCommand: function(aCommand)
  3586.   {
  3587.     var rows = GetNumberOfContiguousSelectedRows();
  3588.     // Delete at least one row
  3589.     if (rows == 0)
  3590.       rows = 1;
  3591.  
  3592.     try {
  3593.       var editor = GetCurrentTableEditor();
  3594.       editor.beginTransaction();
  3595.  
  3596.       // Loop to delete all blocks of contiguous, selected rows
  3597.       while (rows)
  3598.       {
  3599.         editor.deleteTableRow(rows);
  3600.         rows = GetNumberOfContiguousSelectedRows();
  3601.       }
  3602.     } finally { editor.endTransaction(); }
  3603.     window.content.focus();
  3604.   }
  3605. };
  3606.  
  3607. var nsDeleteTableColumnCommand =
  3608. {
  3609.   isCommandEnabled: function(aCommand, dummy)
  3610.   {
  3611.     return IsInTableCell();
  3612.   },
  3613.  
  3614.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3615.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3616.  
  3617.   doCommand: function(aCommand)
  3618.   {
  3619.     var columns = GetNumberOfContiguousSelectedColumns();
  3620.     // Delete at least one column
  3621.     if (columns == 0)
  3622.       columns = 1;
  3623.  
  3624.     try {
  3625.       var editor = GetCurrentTableEditor();
  3626.       editor.beginTransaction();
  3627.  
  3628.       // Loop to delete all blocks of contiguous, selected columns
  3629.       while (columns)
  3630.       {
  3631.         editor.deleteTableColumn(columns);
  3632.         columns = GetNumberOfContiguousSelectedColumns();
  3633.       }
  3634.     } finally { editor.endTransaction(); }
  3635.     window.content.focus();
  3636.   }
  3637. };
  3638.  
  3639. var nsDeleteTableCellCommand =
  3640. {
  3641.   isCommandEnabled: function(aCommand, dummy)
  3642.   {
  3643.     return IsInTableCell();
  3644.   },
  3645.  
  3646.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3647.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3648.  
  3649.   doCommand: function(aCommand)
  3650.   {
  3651.     try {
  3652.       GetCurrentTableEditor().deleteTableCell(1);   
  3653.     } catch (e) {}
  3654.     window.content.focus();
  3655.   }
  3656. };
  3657.  
  3658. var nsDeleteTableCellContentsCommand =
  3659. {
  3660.   isCommandEnabled: function(aCommand, dummy)
  3661.   {
  3662.     return IsInTableCell();
  3663.   },
  3664.  
  3665.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3666.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3667.  
  3668.   doCommand: function(aCommand)
  3669.   {
  3670.     try {
  3671.       GetCurrentTableEditor().deleteTableCellContents();   
  3672.     } catch (e) {}
  3673.     window.content.focus();
  3674.   }
  3675. };
  3676.  
  3677.  
  3678. //-----------------------------------------------------------------------------------
  3679. var nsNormalizeTableCommand =
  3680. {
  3681.   isCommandEnabled: function(aCommand, dummy)
  3682.   {
  3683.     return IsInTable();
  3684.   },
  3685.  
  3686.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3687.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3688.  
  3689.   doCommand: function(aCommand)
  3690.   {
  3691.     // Use nsnull to let editor find table enclosing current selection
  3692.     try {
  3693.       GetCurrentTableEditor().normalizeTable(null);   
  3694.     } catch (e) {}
  3695.     window.content.focus();
  3696.   }
  3697. };
  3698.  
  3699. //-----------------------------------------------------------------------------------
  3700. var nsJoinTableCellsCommand =
  3701. {
  3702.   isCommandEnabled: function(aCommand, dummy)
  3703.   {
  3704.     if (IsDocumentEditable() && IsEditingRenderedHTML())
  3705.     {
  3706.       try {
  3707.         var editor = GetCurrentTableEditor();
  3708.         var tagNameObj = { value: "" };
  3709.         var countObj = { value: 0 };
  3710.         var cell = editor.getSelectedOrParentTableElement(tagNameObj, countObj);
  3711.  
  3712.         // We need a cell and either > 1 selected cell or a cell to the right
  3713.         //  (this cell may originate in a row spanned from above current row)
  3714.         // Note that editor returns "td" for "th" also.
  3715.         // (this is a pain! Editor and gecko use lowercase tagNames, JS uses uppercase!)
  3716.         if( cell && (tagNameObj.value == "td"))
  3717.         {
  3718.           // Selected cells
  3719.           if (countObj.value > 1) return true;
  3720.  
  3721.           var colSpan = cell.getAttribute("colspan");
  3722.  
  3723.           // getAttribute returns string, we need number
  3724.           // no attribute means colspan = 1
  3725.           if (!colSpan)
  3726.             colSpan = Number(1);
  3727.           else
  3728.             colSpan = Number(colSpan);
  3729.  
  3730.           var rowObj = { value: 0 };
  3731.           var colObj = { value: 0 };
  3732.           editor.getCellIndexes(cell, rowObj, colObj);
  3733.  
  3734.           // Test if cell exists to the right of current cell
  3735.           // (cells with 0 span should never have cells to the right
  3736.           //  if there is, user can select the 2 cells to join them)
  3737.           return (colSpan && editor.getCellAt(null, rowObj.value,
  3738.                                               colObj.value + colSpan));
  3739.         }
  3740.       } catch (e) {}
  3741.     }
  3742.     return false;
  3743.   },
  3744.  
  3745.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3746.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3747.  
  3748.   doCommand: function(aCommand)
  3749.   {
  3750.     // Param: Don't merge non-contiguous cells
  3751.     try {
  3752.       GetCurrentTableEditor().joinTableCells(false);
  3753.     } catch (e) {}
  3754.     window.content.focus();
  3755.   }
  3756. };
  3757.  
  3758. //-----------------------------------------------------------------------------------
  3759. var nsSplitTableCellCommand =
  3760. {
  3761.   isCommandEnabled: function(aCommand, dummy)
  3762.   {
  3763.     if (IsDocumentEditable() && IsEditingRenderedHTML())
  3764.     {
  3765.       var tagNameObj = { value: "" };
  3766.       var countObj = { value: 0 };
  3767.       var cell;
  3768.       try {
  3769.         cell = GetCurrentTableEditor().getSelectedOrParentTableElement(tagNameObj, countObj);
  3770.       } catch (e) {}
  3771.  
  3772.       // We need a cell parent and there's just 1 selected cell 
  3773.       // or selection is entirely inside 1 cell
  3774.       if ( cell && (tagNameObj.value == "td") && 
  3775.            countObj.value <= 1 &&
  3776.            IsSelectionInOneCell() )
  3777.       {
  3778.         var colSpan = cell.getAttribute("colspan");
  3779.         var rowSpan = cell.getAttribute("rowspan");
  3780.         if (!colSpan) colSpan = 1;
  3781.         if (!rowSpan) rowSpan = 1;
  3782.         return (colSpan > 1  || rowSpan > 1 ||
  3783.                 colSpan == 0 || rowSpan == 0);
  3784.       }
  3785.     }
  3786.     return false;
  3787.   },
  3788.  
  3789.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3790.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3791.  
  3792.   doCommand: function(aCommand)
  3793.   {
  3794.     try {
  3795.       GetCurrentTableEditor().splitTableCell();
  3796.     } catch (e) {}
  3797.     window.content.focus();
  3798.   }
  3799. };
  3800.  
  3801. //-----------------------------------------------------------------------------------
  3802. var nsTableOrCellColorCommand =
  3803. {
  3804.   isCommandEnabled: function(aCommand, dummy)
  3805.   {
  3806.     return IsInTable();
  3807.   },
  3808.  
  3809.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3810.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3811.  
  3812.   doCommand: function(aCommand)
  3813.   {
  3814.     EditorSelectColor("TableOrCell");
  3815.   }
  3816. };
  3817.  
  3818. //-----------------------------------------------------------------------------------
  3819. var nsPreferencesCommand =
  3820. {
  3821.   isCommandEnabled: function(aCommand, dummy)
  3822.   {
  3823.     return true;
  3824.   },
  3825.  
  3826.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3827.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3828.  
  3829.   doCommand: function(aCommand)
  3830.   {
  3831.     goPreferences('editor', 'chrome://editor/content/pref-composer.xul','editor');
  3832.     window.content.focus();
  3833.   }
  3834. };
  3835.  
  3836.  
  3837. var nsFinishHTMLSource =
  3838. {
  3839.   isCommandEnabled: function(aCommand, dummy)
  3840.   {
  3841.     return true;
  3842.   },
  3843.  
  3844.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3845.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3846.  
  3847.   doCommand: function(aCommand)
  3848.   {
  3849.     // In editor.js
  3850.     FinishHTMLSource();
  3851.   }
  3852. };
  3853.  
  3854. var nsCancelHTMLSource =
  3855. {
  3856.   isCommandEnabled: function(aCommand, dummy)
  3857.   {
  3858.     return true;
  3859.   },
  3860.  
  3861.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3862.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3863.  
  3864.   doCommand: function(aCommand)
  3865.   {
  3866.     // In editor.js
  3867.     CancelHTMLSource();
  3868.   }
  3869. };
  3870.  
  3871. var nsConvertToTable =
  3872. {
  3873.   isCommandEnabled: function(aCommand, dummy)
  3874.   {
  3875.     if (IsDocumentEditable() && IsEditingRenderedHTML())
  3876.     {
  3877.       var selection;
  3878.       try {
  3879.         selection = GetCurrentEditor().selection;
  3880.       } catch (e) {}
  3881.  
  3882.       if (selection && !selection.isCollapsed)
  3883.       {
  3884.         // Don't allow if table or cell is the selection
  3885.         var element;
  3886.         try {
  3887.           element = GetCurrentEditor().getSelectedElement("");
  3888.         } catch (e) {}
  3889.         if (element)
  3890.         {
  3891.           var name = element.nodeName.toLowerCase();
  3892.           if (name == "td" ||
  3893.               name == "th" ||
  3894.               name == "caption" ||
  3895.               name == "table")
  3896.             return false;
  3897.         }
  3898.  
  3899.         // Selection start and end must be in the same cell
  3900.         //   in same cell or both are NOT in a cell
  3901.         if ( GetParentTableCell(selection.focusNode) !=
  3902.              GetParentTableCell(selection.anchorNode) )
  3903.           return false
  3904.       
  3905.         return true;
  3906.       }
  3907.     }
  3908.     return false;
  3909.   },
  3910.  
  3911.   getCommandStateParams: function(aCommand, aParams, aRefCon) {},
  3912.   doCommandParams: function(aCommand, aParams, aRefCon) {},
  3913.  
  3914.   doCommand: function(aCommand)
  3915.   {
  3916.     if (this.isCommandEnabled())
  3917.     {
  3918.       window.openDialog("chrome://editor/content/EdConvertToTable.xul","_blank", "chrome,close,titlebar,modal")
  3919.     }
  3920.     window.content.focus();
  3921.   }
  3922. };
  3923.  
  3924.