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