home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / comm.jar / content / editor / ComposerCommands.js next >
Encoding:
JavaScript  |  2001-10-16  |  51.3 KB  |  1,745 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * The Original Code is mozilla.org code.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are
  17.  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  * Contributor(s): 
  21.  *    Simon Fraser (sfraser@netscape.com)
  22.  *    Ryan Cassin (rcassin@supernova.org)
  23.  */
  24.  
  25. /* Implementations of nsIControllerCommand for composer commands */
  26.  
  27.  
  28. //-----------------------------------------------------------------------------------
  29. function SetupHTMLEditorCommands()
  30. {
  31.   var controller = GetEditorController();
  32.   if (!controller)
  33.     return;
  34.   
  35.  
  36.   // Include everthing a text editor does
  37.   SetupTextEditorCommands();
  38.  
  39.   //dump("Registering HTML editor commands\n");
  40.  
  41.   controller.registerCommand("cmd_renderedHTMLEnabler",           nsDummyHTMLCommand);
  42.  
  43.   controller.registerCommand("cmd_listProperties",  nsListPropertiesCommand);
  44.   controller.registerCommand("cmd_pageProperties",  nsPagePropertiesCommand);
  45.   controller.registerCommand("cmd_colorProperties", nsColorPropertiesCommand);
  46.   controller.registerCommand("cmd_advancedProperties", nsAdvancedPropertiesCommand);
  47.   controller.registerCommand("cmd_objectProperties",   nsObjectPropertiesCommand);
  48.   controller.registerCommand("cmd_removeLinks",        nsRemoveLinksCommand);
  49.   
  50.   controller.registerCommand("cmd_image",         nsImageCommand);
  51.   controller.registerCommand("cmd_hline",         nsHLineCommand);
  52.   controller.registerCommand("cmd_link",          nsLinkCommand);
  53.   controller.registerCommand("cmd_anchor",        nsAnchorCommand);
  54.   controller.registerCommand("cmd_insertHTML",    nsInsertHTMLCommand);
  55.   controller.registerCommand("cmd_insertBreak",   nsInsertBreakCommand);
  56.   controller.registerCommand("cmd_insertBreakAll",nsInsertBreakAllCommand);
  57.  
  58.   controller.registerCommand("cmd_table",              nsInsertOrEditTableCommand);
  59.   controller.registerCommand("cmd_editTable",          nsEditTableCommand);
  60.   controller.registerCommand("cmd_SelectTable",        nsSelectTableCommand);
  61.   controller.registerCommand("cmd_SelectRow",          nsSelectTableRowCommand);
  62.   controller.registerCommand("cmd_SelectColumn",       nsSelectTableColumnCommand);
  63.   controller.registerCommand("cmd_SelectCell",         nsSelectTableCellCommand);
  64.   controller.registerCommand("cmd_SelectAllCells",     nsSelectAllTableCellsCommand);
  65.   controller.registerCommand("cmd_InsertTable",        nsInsertTableCommand);
  66.   controller.registerCommand("cmd_InsertRowAbove",     nsInsertTableRowAboveCommand);
  67.   controller.registerCommand("cmd_InsertRowBelow",     nsInsertTableRowBelowCommand);
  68.   controller.registerCommand("cmd_InsertColumnBefore", nsInsertTableColumnBeforeCommand);
  69.   controller.registerCommand("cmd_InsertColumnAfter",  nsInsertTableColumnAfterCommand);
  70.   controller.registerCommand("cmd_InsertCellBefore",   nsInsertTableCellBeforeCommand);
  71.   controller.registerCommand("cmd_InsertCellAfter",    nsInsertTableCellAfterCommand);
  72.   controller.registerCommand("cmd_DeleteTable",        nsDeleteTableCommand);
  73.   controller.registerCommand("cmd_DeleteRow",          nsDeleteTableRowCommand);
  74.   controller.registerCommand("cmd_DeleteColumn",       nsDeleteTableColumnCommand);
  75.   controller.registerCommand("cmd_DeleteCell",         nsDeleteTableCellCommand);
  76.   controller.registerCommand("cmd_DeleteCellContents", nsDeleteTableCellContentsCommand);
  77.   controller.registerCommand("cmd_JoinTableCells",     nsJoinTableCellsCommand);
  78.   controller.registerCommand("cmd_SplitTableCell",     nsSplitTableCellCommand);
  79.   controller.registerCommand("cmd_TableOrCellColor",   nsTableOrCellColorCommand);
  80.   controller.registerCommand("cmd_NormalizeTable",     nsNormalizeTableCommand);
  81.   controller.registerCommand("cmd_FinishHTMLSource",   nsFinishHTMLSource);
  82.   controller.registerCommand("cmd_CancelHTMLSource",   nsCancelHTMLSource);
  83.   controller.registerCommand("cmd_smiley",             nsSetSmiley);
  84.   controller.registerCommand("cmd_buildRecentPagesMenu", nsBuildRecentPagesMenu);
  85.   controller.registerCommand("cmd_ConvertToTable",     nsConvertToTable);
  86. }
  87.  
  88. function SetupTextEditorCommands()
  89. {
  90.   var controller = GetEditorController();
  91.   if (!controller)
  92.     return;
  93.   
  94.   //dump("Registering plain text editor commands\n");
  95.   
  96.   controller.registerCommand("cmd_find",       nsFindCommand);
  97.   controller.registerCommand("cmd_findNext",   nsFindNextCommand);
  98.   controller.registerCommand("cmd_spelling",   nsSpellingCommand);
  99.   controller.registerCommand("cmd_validate",   nsValidateCommand);
  100.   controller.registerCommand("cmd_checkLinks", nsCheckLinksCommand);
  101.   controller.registerCommand("cmd_insertChars", nsInsertCharsCommand);
  102. }
  103.  
  104. function SetupComposerWindowCommands()
  105. {
  106.   // Create a command controller and register commands
  107.   //   specific to Web Composer window (file-related commands, HTML Source...)
  108.   // IMPORTANT: For each of these commands, the doCommand method 
  109.   //            must first call FinishHTMLSource() 
  110.   //            to go from HTML Source mode to any other edit mode
  111.  
  112.   var windowCommandManager = window.controllers;
  113.  
  114.   if (!windowCommandManager) return;
  115.  
  116.   var composerController = Components.classes["@mozilla.org/editor/composercontroller;1"].createInstance();
  117.   if (!composerController)
  118.   {
  119.     dump("Failed to create composerController\n");
  120.     return;
  121.   }
  122.  
  123.   var editorController = composerController.QueryInterface(Components.interfaces.nsIEditorController);
  124.   if (!editorController)
  125.   {
  126.     dump("Failed to get interface for nsIEditorController\n");
  127.     return;
  128.   }
  129.  
  130.   // Note: We init with the editorShell for the main composer window, not the HTML Source textfield?
  131.   editorController.Init(window.editorShell);
  132.  
  133.   var interfaceRequestor = composerController.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  134.   if (!interfaceRequestor)
  135.   {
  136.     dump("Failed to get iterfaceRequestor for composerController\n");
  137.     return;
  138.   }
  139.     
  140.  
  141.   // Get the nsIControllerCommandManager interface we need to register more commands
  142.   var commandManager = interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandManager);
  143.   if (!commandManager)
  144.   {
  145.     dump("Failed to get interface for nsIControllerCommandManager\n");
  146.     return;
  147.   }
  148.  
  149.   // File-related commands
  150.   commandManager.registerCommand("cmd_newEditor",      nsNewEditorCommand);
  151.   commandManager.registerCommand("cmd_open",           nsOpenCommand);
  152.   commandManager.registerCommand("cmd_save",           nsSaveCommand);
  153.   commandManager.registerCommand("cmd_saveAs",         nsSaveAsCommand);
  154.   commandManager.registerCommand("cmd_exportToText",   nsExportToTextCommand);
  155.   commandManager.registerCommand("cmd_saveAsCharset",  nsSaveAsCharsetCommand);
  156.   commandManager.registerCommand("cmd_revert",         nsRevertCommand);
  157.   commandManager.registerCommand("cmd_openRemote",     nsOpenRemoteCommand);
  158.   commandManager.registerCommand("cmd_preview",        nsPreviewCommand);
  159.   commandManager.registerCommand("cmd_editSendPage",   nsSendPageCommand);
  160.   commandManager.registerCommand("cmd_print",          nsPrintCommand);
  161.   commandManager.registerCommand("cmd_printSetup",     nsPrintSetupCommand);
  162.   commandManager.registerCommand("cmd_quit",           nsQuitCommand);
  163.   commandManager.registerCommand("cmd_close",          nsCloseCommand);
  164.   commandManager.registerCommand("cmd_preferences",    nsPreferencesCommand);
  165.  
  166.   // Edit Mode commands
  167.   if (window.editorShell.editorType == "html")
  168.   {
  169.     commandManager.registerCommand("cmd_NormalMode",         nsNormalModeCommand);
  170.     commandManager.registerCommand("cmd_AllTagsMode",        nsAllTagsModeCommand);
  171.     commandManager.registerCommand("cmd_HTMLSourceMode",     nsHTMLSourceModeCommand);
  172.     commandManager.registerCommand("cmd_PreviewMode",        nsPreviewModeCommand);
  173.     commandManager.registerCommand("cmd_FinishHTMLSource",   nsFinishHTMLSource);
  174.     commandManager.registerCommand("cmd_CancelHTMLSource",   nsCancelHTMLSource);
  175.   }
  176.  
  177.   windowCommandManager.insertControllerAt(0, editorController);
  178. }
  179.  
  180. //-----------------------------------------------------------------------------------
  181. function GetEditorController()
  182. {
  183.   var numControllers = window._content.controllers.getControllerCount();
  184.     
  185.   // count down to find a controller that supplies a nsIControllerCommandManager interface
  186.   for (var i = numControllers-1; i >= 0 ; i --)
  187.   {
  188.     var commandManager = null;
  189.     
  190.     try { 
  191.       var controller = window._content.controllers.getControllerAt(i);
  192.       
  193.       var interfaceRequestor = controller.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  194.       if (!interfaceRequestor) continue;
  195.     
  196.       commandManager = interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandManager);
  197.     }
  198.     catch(ex)
  199.     {
  200.         //dump(ex + "\n");
  201.     }
  202.  
  203.     if (commandManager)
  204.       return commandManager;
  205.   }
  206.  
  207.   dump("Failed to find a controller to register commands with\n");
  208.   return null;
  209. }
  210.  
  211. //-----------------------------------------------------------------------------------
  212. function goUpdateComposerMenuItems(commandset)
  213. {
  214.   // dump("Updating commands for " + commandset.id + "\n");
  215.   
  216.   for (var i = 0; i < commandset.childNodes.length; i++)
  217.   {
  218.     var commandID = commandset.childNodes[i].getAttribute("id");
  219.     if (commandID)
  220.     {
  221.       goUpdateCommand(commandID);
  222.     }
  223.   }
  224. }
  225.  
  226. //-----------------------------------------------------------------------------------
  227. function PrintObject(obj)
  228. {
  229.   dump("-----" + obj + "------\n");
  230.   var names = "";
  231.   for (var i in obj)
  232.   {
  233.     if (i == "value")
  234.       names += i + ": " + obj.value + "\n";
  235.     else if (i == "id")
  236.       names += i + ": " + obj.id + "\n";
  237.     else
  238.       names += i + "\n";
  239.   }
  240.   
  241.   dump(names + "-----------\n");
  242. }
  243.  
  244. //-----------------------------------------------------------------------------------
  245. function PrintNodeID(id)
  246. {
  247.   PrintObject(document.getElementById(id));
  248. }
  249.  
  250. //-----------------------------------------------------------------------------------
  251. var nsDummyHTMLCommand =
  252. {
  253.   isCommandEnabled: function(aCommand, dummy)
  254.   {
  255.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  256.   },
  257.  
  258.   doCommand: function(aCommand)
  259.   {
  260.     // do nothing
  261.     dump("Hey, who's calling the dummy command?\n");
  262.   }
  263.  
  264. };
  265.  
  266. //-----------------------------------------------------------------------------------
  267. var nsOpenCommand =
  268. {
  269.   isCommandEnabled: function(aCommand, dummy)
  270.   {
  271.     return true;    // we can always do this
  272.   },
  273.  
  274.   doCommand: function(aCommand)
  275.   {
  276.     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  277.     fp.init(window, window.editorShell.GetString("OpenHTMLFile"), nsIFilePicker.modeOpen);
  278.   
  279.     // When loading into Composer, direct user to prefer HTML files and text files,
  280.     //   so we call separately to control the order of the filter list
  281.     fp.appendFilters(nsIFilePicker.filterHTML);
  282.     fp.appendFilters(nsIFilePicker.filterText);
  283.     fp.appendFilters(nsIFilePicker.filterAll);
  284.  
  285.     /* doesn't handle *.shtml files */
  286.     try {
  287.       fp.show();
  288.       /* need to handle cancel (uncaught exception at present) */
  289.     }
  290.     catch (ex) {
  291.       dump("filePicker.chooseInputFile threw an exception\n");
  292.     }
  293.   
  294.     /* This checks for already open window and activates it... 
  295.      * note that we have to test the native path length
  296.      *  since fileURL.spec will be "file:///" if no filename picked (Cancel button used)
  297.      */
  298.     if (fp.file && fp.file.path.length > 0) {
  299.       EditorOpenUrl(fp.fileURL.spec);
  300.     }
  301.   }
  302. };
  303.  
  304. //-----------------------------------------------------------------------------------
  305. var nsSaveCommand =
  306. {
  307.   isCommandEnabled: function(aCommand, dummy)
  308.   {
  309.     return window.editorShell && 
  310.       (window.editorShell.documentModified || 
  311.        window.editorShell.editorDocument.location == "about:blank" ||
  312.        window.gHTMLSourceChanged);
  313.   },
  314.   
  315.   doCommand: function(aCommand)
  316.   {
  317.     if (window.editorShell)
  318.     {
  319.       FinishHTMLSource(); // In editor.js
  320.       var doSaveAs = window.editorShell.editorDocument.location == "about:blank";
  321.       var result = window.editorShell.saveDocument(doSaveAs, false, editorShell.contentsMIMEType);
  322.       window._content.focus();
  323.       return result;
  324.     }
  325.     return false;
  326.   }
  327. }
  328.  
  329. var nsSaveAsCommand =
  330. {
  331.   isCommandEnabled: function(aCommand, dummy)
  332.   {
  333.     return (window.editorShell && window.editorShell.documentEditable);
  334.   },
  335.  
  336.   doCommand: function(aCommand)
  337.   {
  338.     if (window.editorShell)
  339.     {
  340.       FinishHTMLSource();
  341.       var result = window.editorShell.saveDocument(true, false, editorShell.contentsMIMEType);
  342.       window._content.focus();
  343.       return result;
  344.     }
  345.     return false;
  346.   }
  347. }
  348.  
  349. var nsExportToTextCommand =
  350. {
  351.   isCommandEnabled: function(aCommand, dummy)
  352.   {
  353.     return (window.editorShell && window.editorShell.documentEditable);
  354.   },
  355.  
  356.   doCommand: function(aCommand)
  357.   {
  358.     if (window.editorShell)
  359.     {
  360.       FinishHTMLSource();
  361.       var result = window.editorShell.saveDocument(true, true, "text/plain");
  362.       window._content.focus();
  363.       return result;
  364.     }
  365.     return false;
  366.   }
  367. }
  368.  
  369. var nsSaveAsCharsetCommand =
  370. {
  371.   isCommandEnabled: function(aCommand, dummy)
  372.   {
  373.     return (window.editorShell && window.editorShell.documentEditable);
  374.   },
  375.   doCommand: function(aCommand)
  376.   {    
  377.     FinishHTMLSource();
  378.     window.ok = false;
  379.     window.exportToText = false;
  380.     window.openDialog("chrome://editor/content/EditorSaveAsCharset.xul","_blank", "chrome,close,titlebar,modal,resizable=yes");
  381.  
  382.     if (window.newTitle != null) {
  383.       try {
  384.         editorShell.SetDocumentTitle(window.newTitle);
  385.       } 
  386.       catch (ex) {}
  387.     }    
  388.  
  389.     if (window.ok)
  390.     {
  391.       if (window.exportToText)
  392.       {
  393.         window.ok = window.editorShell.saveDocument(true, true, "text/plain");
  394.       }
  395.       else
  396.       {
  397.         window.ok = window.editorShell.saveDocument(true, false, editorShell.contentsMIMEType);
  398.       }
  399.     }
  400.  
  401.     window._content.focus();
  402.     return window.ok;
  403.   }
  404. };
  405.  
  406. //-----------------------------------------------------------------------------------
  407. var nsRevertCommand =
  408. {
  409.   isCommandEnabled: function(aCommand, dummy)
  410.   {
  411.     return (window.editorShell && 
  412.             window.editorShell.documentModified &&
  413.             window.editorShell.editorDocument.location != "about:blank");
  414.   },
  415.  
  416.   doCommand: function(aCommand)
  417.   {
  418.     // Confirm with the user to abandon current changes
  419.     var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  420.     promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
  421.  
  422.     if (promptService)
  423.     {
  424.       var result = {value:0};
  425.  
  426.       // Put the page title in the message string
  427.       var title = window.editorShell.GetDocumentTitle();
  428.       if (!title)
  429.         title = window.editorShell.GetString("untitled");
  430.  
  431.       var msg = window.editorShell.GetString("AbandonChanges").replace(/%title%/,title);
  432.  
  433.       promptService.confirmEx(window, window.editorShell.GetString("RevertCaption"), msg,
  434.                                 (promptService.BUTTON_TITLE_REVERT * promptService.BUTTON_POS_0) +
  435.                                 (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
  436.                                 null, null, null, null, {value:0}, result);
  437.  
  438.       // Reload page if first button (Revert) was pressed
  439.       if(result.value == 0)
  440.       {
  441.         FinishHTMLSource();
  442.         window.editorShell.LoadUrl(editorShell.editorDocument.location);
  443.       }
  444.     }
  445.   }
  446. };
  447.  
  448. //-----------------------------------------------------------------------------------
  449. var nsCloseCommand =
  450. {
  451.   isCommandEnabled: function(aCommand, dummy)
  452.   {
  453.     return window.editorShell;
  454.   },
  455.   
  456.   doCommand: function(aCommand)
  457.   {
  458.     CloseWindow();
  459.   }
  460. };
  461.  
  462. function CloseWindow()
  463. {
  464.   // Check to make sure document is saved. "true" means allow "Don't Save" button,
  465.   //   so user can choose to close without saving
  466.   if (CheckAndSaveDocument(window.editorShell.GetString("BeforeClosing"), true)) 
  467.   {
  468.     if (window.InsertCharWindow)
  469.       SwitchInsertCharToAnotherEditorOrClose();
  470.  
  471.     window.editorShell.CloseWindowWithoutSaving();
  472.   }
  473. }
  474.  
  475. //-----------------------------------------------------------------------------------
  476. var nsNewEditorCommand =
  477. {
  478.   isCommandEnabled: function(aCommand, dummy)
  479.   {
  480.     return true;    // we can always do this
  481.   },
  482.  
  483.   doCommand: function(aCommand)
  484.   {
  485.     NewEditorWindow();
  486.   }
  487. };
  488.  
  489. //-----------------------------------------------------------------------------------
  490. var nsOpenRemoteCommand =
  491. {
  492.   isCommandEnabled: function(aCommand, dummy)
  493.   {
  494.     return true;    // we can always do this
  495.   },
  496.  
  497.   doCommand: function(aCommand)
  498.   {
  499.       /* The last parameter is the current browser window.
  500.          Use 0 and the default checkbox will be to load into an editor
  501.          and loading into existing browser option is removed
  502.        */
  503.       window.openDialog( "chrome://communicator/content/openLocation.xul", "_blank", "chrome,modal,titlebar", 0);
  504.     window._content.focus();
  505.   }
  506. };
  507.  
  508. //-----------------------------------------------------------------------------------
  509. var nsPreviewCommand =
  510. {
  511.   isCommandEnabled: function(aCommand, dummy)
  512.   {
  513.     return (window.editorShell && IsEditorContentHTML() && (DocumentHasBeenSaved() || window.editorShell.documentModified));
  514.   },
  515.  
  516.   doCommand: function(aCommand)
  517.   {
  518.       // Don't continue if user canceled during prompt for saving
  519.     // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
  520.     if (!CheckAndSaveDocument(window.editorShell.GetString("BeforePreview"), DocumentHasBeenSaved()))
  521.         return;
  522.  
  523.     // Check if we saved again just in case?
  524.       if (DocumentHasBeenSaved())
  525.         window.openDialog(getBrowserURL(), "EditorPreview", "chrome,all,dialog=no", window._content.location);
  526.   }
  527. };
  528.  
  529. //-----------------------------------------------------------------------------------
  530. var nsSendPageCommand =
  531. {
  532.   isCommandEnabled: function(aCommand, dummy)
  533.   {
  534.     return (window.editorShell != null && (DocumentHasBeenSaved() || window.editorShell.documentModified));
  535.   },
  536.  
  537.   doCommand: function(aCommand)
  538.   {
  539.       // Don't continue if user canceled during prompt for saving
  540.     // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
  541.     if (!CheckAndSaveDocument(window.editorShell.GetString("SendPageReason"), DocumentHasBeenSaved()))
  542.         return;
  543.  
  544.     // Check if we saved again just in case?
  545.       if (DocumentHasBeenSaved())
  546.     {
  547.       // Launch Messenger Composer window with current page as contents
  548.       var pageTitle = window.editorShell.editorDocument.title;
  549.       var pageUrl = window.editorShell.editorDocument.location.href;
  550.       window.openDialog( "chrome://messenger/content/messengercompose/messengercompose.xul", "_blank", 
  551.                          "chrome,all,dialog=no", 
  552.                          "attachment='" + pageUrl.replace(/\,/g, "%2C") + "',body='" + pageUrl +
  553.                          "',subject='" + pageTitle + "',bodyislink=true");
  554.     }
  555.   }
  556. };
  557.  
  558. //-----------------------------------------------------------------------------------
  559. var nsPrintCommand =
  560. {
  561.   isCommandEnabled: function(aCommand, dummy)
  562.   {
  563.     return true;    // we can always do this
  564.   },
  565.  
  566.   doCommand: function(aCommand)
  567.   {
  568.     // In editor.js
  569.     FinishHTMLSource();
  570.     window.editorShell.Print();
  571.   }
  572. };
  573.  
  574. //-----------------------------------------------------------------------------------
  575. var nsPrintSetupCommand =
  576. {
  577.   isCommandEnabled: function(aCommand, dummy)
  578.   {
  579.     return true;    // we can always do this
  580.   },
  581.  
  582.   doCommand: function(aCommand)
  583.   {
  584.     // In editor.js
  585.     FinishHTMLSource();
  586.     goPageSetup();
  587.   }
  588. };
  589.  
  590. //-----------------------------------------------------------------------------------
  591. var nsQuitCommand =
  592. {
  593.   isCommandEnabled: function(aCommand, dummy)
  594.   {
  595.     return true;    // we can always do this
  596.   },
  597.  
  598.   doCommand: function(aCommand)
  599.   {
  600.     // In editor.js
  601.     FinishHTMLSource();
  602.     goQuitApplication();
  603.   }
  604. };
  605.  
  606. //-----------------------------------------------------------------------------------
  607. var nsFindCommand =
  608. {
  609.   isCommandEnabled: function(aCommand, dummy)
  610.   {
  611.     return (window.editorShell && !IsInHTMLSourceMode());
  612.   },
  613.  
  614.   doCommand: function(aCommand)
  615.   {
  616.     window.editorShell.Replace();
  617.   }
  618. };
  619.  
  620. //-----------------------------------------------------------------------------------
  621. var nsFindNextCommand =
  622. {
  623.   isCommandEnabled: function(aCommand, dummy)
  624.   {
  625.     // we can only do this if the search pattern is non-empty. Not sure how
  626.     // to get that from here
  627.     return (window.editorShell && !IsInHTMLSourceMode());
  628.   },
  629.  
  630.   doCommand: function(aCommand)
  631.   {
  632.     window.editorShell.FindNext();
  633.   }
  634. };
  635.  
  636. //-----------------------------------------------------------------------------------
  637. var nsSpellingCommand =
  638. {
  639.   isCommandEnabled: function(aCommand, dummy)
  640.   {
  641.     return (window.editorShell != null) && !IsInHTMLSourceMode() && IsSpellCheckerInstalled();
  642.   },
  643.  
  644.   doCommand: function(aCommand)
  645.   {
  646.     try {
  647.       window.openDialog("chrome://editor/content/EdSpellCheck.xul", "_blank",
  648.               "chrome,close,titlebar,modal", "");
  649.     }
  650.     catch(ex) {
  651.       dump("*** Exception error: SpellChecker Dialog Closing\n");
  652.     }
  653.     window._content.focus();
  654.   }
  655. };
  656.  
  657. // Validate using http://validator.w3.org/file-upload.html
  658. var URL2Validate;
  659. var nsValidateCommand =
  660. {
  661.   isCommandEnabled: function(aCommand, dummy)
  662.   {
  663.     return (window.editorShell != null);
  664.   },
  665.  
  666.   doCommand: function(aCommand)
  667.   {
  668.     // If the document hasn't been modified,
  669.     // then just validate the current url.
  670.     if (editorShell.documentModified || gHTMLSourceChanged)
  671.     {
  672.       if (!CheckAndSaveDocument(window.editorShell.GetString("BeforeValidate"),
  673.                                 false))
  674.         return;
  675.  
  676.       // Check if we saved again just in case?
  677.       if (!DocumentHasBeenSaved())    // user hit cancel?
  678.         return;
  679.     }
  680.  
  681.     URL2Validate = window.editorShell.editorDocument.location;
  682.     // See if it's a file:
  683.     var ifile = Components.classes["@mozilla.org/file/local;1"].createInstance().QueryInterface(Components.interfaces.nsIFile);
  684.     try {
  685.       ifile.URL = URL2Validate;
  686.       // nsIFile throws an exception if it's not a file url
  687.     } catch (e) { ifile = null; }
  688.     if (ifile)
  689.     {
  690.       URL2Validate = ifile.path;
  691.       var vwin = window.open("http://validator.w3.org/file-upload.html",
  692.                              "EditorValidate");
  693.       // Window loads asynchronously, so pass control to the load listener:
  694.       vwin.addEventListener("load", this.validateFilePageLoaded, false);
  695.     }
  696.     else
  697.     {
  698.       var vwin = window.open("http://validator.w3.org/",
  699.                              "EditorValidate");
  700.       // Window loads asynchronously, so pass control to the load listener:
  701.       vwin.addEventListener("load", this.validateWebPageLoaded, false);
  702.     }
  703.   },
  704.   validateFilePageLoaded: function(event)
  705.   {
  706.     event.target.forms[0].uploaded_file.value = URL2Validate;
  707.   },
  708.   validateWebPageLoaded: function(event)
  709.   {
  710.     event.target.forms[0].uri.value = URL2Validate;
  711.   }
  712. };
  713.  
  714. // Link checking.
  715. // XXX THIS CODE IS WORK IN PROGRESS (only exposed in the debug menu).
  716.  
  717. const kIOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
  718. const nsIIOService = Components.interfaces['nsIIOService'];
  719.  
  720. var nsLinkChecker =
  721. {
  722.   uri : null,
  723.   linkCheckDone : true,
  724.   ios : Components.classes[kIOSERVICE_CONTRACTID].getService(nsIIOService),
  725.   linkCheckURI : "",
  726.  
  727.   LoadFromURI: function(aURI, ioService) {
  728.     this.done = false;
  729.     this.uri = aURI;
  730.     dump("LoadFromURI(" + this.uri + ")\n");
  731.     var theURI = this.ios.newURI(this.uri, null);
  732.     //pacURL = uri.spec;
  733.  
  734.     var channel = this.ios.newChannelFromURI(theURI);
  735.     // Don't load for cache, that would be cheating:
  736.     //channel.loadFlags |= nsIRequest::LOAD_BYPASS_CACHE;
  737.     try {
  738.     var httpChannel = channel.QueryInterface(Components.interfaces.nsIHttpChannel);
  739.     if (httpChannel) {
  740.       httpChannel.requestMethod = "HEAD";
  741.     }
  742.     } catch(e) { }
  743.     try {
  744.       channel.asyncOpen(this, null);
  745.     }
  746.     catch (ex) {
  747.       dump("asyncOpen failed for " + this.uri + "\n");
  748.     }
  749.   },
  750.  
  751.   // nsIStreamListener interface
  752.   onStartRequest: function(request, ctxt) { 
  753.     dump("onStartRequest(" + this.uri + ", status = " + request.status
  754.          + ")\n");
  755.     try {
  756.     var httpChannel = request.QueryInterface(Components.interfaces.nsIHttpChannel);
  757.     if (httpChannel) {
  758.       var stat = httpChannel.responseStatus/100;
  759.       dump("Response status was " + stat + "\n");
  760.     }
  761.     } catch(e) { }
  762.     // Probably don't actually need this stream if we're not going to read:
  763.     this.sis = 
  764.       Components.Constructor('@mozilla.org/scriptableinputstream;1',
  765.                              'nsIScriptableInputStream', 
  766.                              'init');
  767.     throw(Components.results.NS_ERROR_FAILURE);
  768.   },
  769.  
  770.   onStopRequest: function(request, ctxt, status, errorMsg) {
  771.     dump("onStopRequest(" + this.uri + ", status = " + status + ")\n");
  772.     this.done = true;
  773.   },
  774.  
  775.   onDataAvailable: function(request, ctxt, inStream, sourceOffset, count) {
  776.     dump("onDataAvailable(" + this.uri + ")\n");
  777.     var ins = new this.sis(inStream);
  778.     pac += ins.read(count);
  779.  
  780.     // Now check the error code and cancel the request.
  781.     // This should pass NS_BINDING_ABORTED, according to nsIRequest.idl,
  782.     // but it doesn't seem to be available from JS.
  783.     // ((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_ERROR)<<31) | ((PRUint32)(module+
  784.     //     NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))
  785.     //request.cancel(0x80000001);
  786.   }
  787. };
  788.  
  789. var nsCheckLinksCommand =
  790. {
  791.   isCommandEnabled: function(aCommand, dummy)
  792.   {
  793.     return (window.editorShell != null);
  794.   },
  795.  
  796.   doCommand: function(aCommand)
  797.   {
  798.     objects = window.editorShell.GetLinkedObjects();
  799.     // Objects is an nsISupportsArray.
  800.     var uri;
  801.     dump("Checking links in " + objects.Count() + " items ...\n");
  802.     for (var i = 0; i < objects.Count(); ++i)
  803.     {
  804.       var refobj = objects.GetElementAt(i).QueryInterface(Components.interfaces.nsIURIRefObject);
  805.       uri = refobj.GetNextURI();
  806.       dump(i + ": '" + uri + "'\n");
  807.     }
  808.     // Check only the last link, for now:
  809.     nsLinkChecker.LoadFromURI(uri);
  810.   }
  811. };
  812.  
  813. //-----------------------------------------------------------------------------------
  814. var nsImageCommand =
  815. {
  816.   isCommandEnabled: function(aCommand, dummy)
  817.   {
  818.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  819.   },
  820.   doCommand: function(aCommand)
  821.   {
  822.     window.openDialog("chrome://editor/content/EdImageProps.xul","_blank", "chrome,close,titlebar,modal");
  823.     window._content.focus();
  824.   }
  825. };
  826.  
  827. //-----------------------------------------------------------------------------------
  828. var nsHLineCommand =
  829. {
  830.   isCommandEnabled: function(aCommand, dummy)
  831.   {
  832.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  833.   },
  834.   doCommand: function(aCommand)
  835.   {
  836.     // Inserting an HLine is different in that we don't use properties dialog
  837.     //  unless we are editing an existing line's attributes
  838.     //  We get the last-used attributes from the prefs and insert immediately
  839.  
  840.     var tagName = "hr";
  841.     var hLine = window.editorShell.GetSelectedElement(tagName);
  842.  
  843.     if (hLine) {
  844.       // We only open the dialog for an existing HRule
  845.       window.openDialog("chrome://editor/content/EdHLineProps.xul", "_blank", "chrome,close,titlebar,modal");
  846.       window._content.focus();
  847.     } else {
  848.       hLine = window.editorShell.CreateElementWithDefaults(tagName);
  849.  
  850.       if (hLine) {
  851.         // We change the default attributes to those saved in the user prefs
  852.  
  853.         if (gPrefs) {
  854.           try {
  855.             var align = gPrefs.GetIntPref("editor.hrule.align");
  856.             if (align == 0 ) {
  857.               hLine.setAttribute("align", "left");
  858.             } else if (align == 2) {
  859.               hLine.setAttribute("align", "right");
  860.             }
  861.  
  862.             //Note: Default is center (don't write attribute)
  863.         
  864.             var width = gPrefs.GetIntPref("editor.hrule.width");
  865.             var percent = gPrefs.GetBoolPref("editor.hrule.width_percent");
  866.             if (percent)
  867.               width = width +"%";
  868.  
  869.             hLine.setAttribute("width", width);
  870.  
  871.             var height = gPrefs.GetIntPref("editor.hrule.height");
  872.             hLine.setAttribute("size", String(height));
  873.  
  874.             var shading = gPrefs.GetBoolPref("editor.hrule.shading");
  875.             if (shading) {
  876.               hLine.removeAttribute("noshade");
  877.             } else {
  878.               hLine.setAttribute("noshade", "noshade");
  879.             }
  880.           }
  881.           catch (ex) {
  882.             dump("failed to get HLine prefs\n");
  883.           }
  884.         }
  885.         try {
  886.           window.editorShell.InsertElementAtSelection(hLine, true);
  887.         } catch (e) {
  888.           dump("Exception occured in InsertElementAtSelection\n");
  889.         }
  890.       }
  891.     }
  892.   }
  893. };
  894.  
  895. //-----------------------------------------------------------------------------------
  896. var nsLinkCommand =
  897. {
  898.   isCommandEnabled: function(aCommand, dummy)
  899.   {
  900.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  901.   },
  902.   doCommand: function(aCommand)
  903.   {
  904.     window.openDialog("chrome://editor/content/EdLinkProps.xul","_blank", "chrome,close,titlebar,modal");
  905.     window._content.focus();
  906.   }
  907. };
  908.  
  909. //-----------------------------------------------------------------------------------
  910. var nsAnchorCommand =
  911. {
  912.   isCommandEnabled: function(aCommand, dummy)
  913.   {
  914.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  915.   },
  916.   doCommand: function(aCommand)
  917.   {
  918.     window.openDialog("chrome://editor/content/EdNamedAnchorProps.xul", "_blank", "chrome,close,titlebar,modal", "");
  919.     window._content.focus();
  920.   }
  921. };
  922.  
  923. //-----------------------------------------------------------------------------------
  924. var nsInsertHTMLCommand =
  925. {
  926.   isCommandEnabled: function(aCommand, dummy)
  927.   {
  928.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  929.   },
  930.   doCommand: function(aCommand)
  931.   {
  932.     window.openDialog("chrome://editor/content/EdInsSrc.xul","_blank", "chrome,close,titlebar,modal,resizable", "");
  933.     window._content.focus();
  934.   }
  935. };
  936.  
  937. //-----------------------------------------------------------------------------------
  938. var nsInsertCharsCommand =
  939. {
  940.   isCommandEnabled: function(aCommand, dummy)
  941.   {
  942.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  943.   },
  944.   doCommand: function(aCommand)
  945.   {
  946.     EditorFindOrCreateInsertCharWindow();
  947.   }
  948. };
  949.  
  950. //-----------------------------------------------------------------------------------
  951. var nsInsertBreakCommand =
  952. {
  953.   isCommandEnabled: function(aCommand, dummy)
  954.   {
  955.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  956.   },
  957.   doCommand: function(aCommand)
  958.   {
  959.     window.editorShell.InsertSource("<br>");
  960.   }
  961. };
  962.  
  963. //-----------------------------------------------------------------------------------
  964. var nsInsertBreakAllCommand =
  965. {
  966.   isCommandEnabled: function(aCommand, dummy)
  967.   {
  968.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  969.   },
  970.   doCommand: function(aCommand)
  971.   {
  972.     window.editorShell.InsertSource("<br clear='all'>");
  973.   }
  974. };
  975.  
  976. //-----------------------------------------------------------------------------------
  977. var nsListPropertiesCommand =
  978. {
  979.   isCommandEnabled: function(aCommand, dummy)
  980.   {
  981.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  982.   },
  983.   doCommand: function(aCommand)
  984.   {
  985.     window.openDialog("chrome://editor/content/EdListProps.xul","_blank", "chrome,close,titlebar,modal");
  986.     window._content.focus();
  987.   }
  988. };
  989.  
  990.  
  991. //-----------------------------------------------------------------------------------
  992. var nsPagePropertiesCommand =
  993. {
  994.   isCommandEnabled: function(aCommand, dummy)
  995.   {
  996.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  997.   },
  998.   doCommand: function(aCommand)
  999.   {
  1000.     window.openDialog("chrome://editor/content/EdPageProps.xul","_blank", "chrome,close,titlebar,modal", "");
  1001.     window._content.focus();
  1002.   }
  1003. };
  1004.  
  1005. //-----------------------------------------------------------------------------------
  1006. var nsObjectPropertiesCommand =
  1007. {
  1008.   isCommandEnabled: function(aCommand, dummy)
  1009.   {
  1010.     var isEnabled = false;
  1011.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  1012.     {
  1013.       isEnabled = (GetObjectForProperties() != null ||
  1014.                    window.editorShell.GetSelectedElement("href") != null);
  1015.     }
  1016.     return isEnabled;
  1017.   },
  1018.   doCommand: function(aCommand)
  1019.   {
  1020.     // Launch Object properties for appropriate selected element 
  1021.     var element = GetObjectForProperties();
  1022.     if (element)
  1023.     {
  1024.       var name = element.nodeName.toLowerCase();
  1025.       switch (name)
  1026.       {
  1027.         case 'img':
  1028.           goDoCommand("cmd_image");
  1029.           break;
  1030.         case 'hr':
  1031.           goDoCommand("cmd_hline");
  1032.           break;
  1033.         case 'table':
  1034.           EditorInsertOrEditTable(false);
  1035.           break;
  1036.         case 'td':
  1037.         case 'th':
  1038.           EditorTableCellProperties();
  1039.           break;
  1040.         case 'ol':
  1041.         case 'ul':
  1042.         case 'dl':
  1043.           goDoCommand("cmd_listProperties");
  1044.           break;
  1045.         case 'a':
  1046.           if (element.name)
  1047.           {
  1048.             goDoCommand("cmd_anchor");
  1049.           }
  1050.           else if(element.href)
  1051.           {
  1052.             goDoCommand("cmd_link");
  1053.           }
  1054.           break;
  1055.         default:
  1056.           doAdvancedProperties(element);
  1057.           break;
  1058.       }
  1059.     } else {
  1060.       // We get a partially-selected link if asked for specifically
  1061.       element = window.editorShell.GetSelectedElement("href");
  1062.       if (element)
  1063.         goDoCommand("cmd_link");
  1064.     }
  1065.     window._content.focus();
  1066.   }
  1067. };
  1068.  
  1069.  
  1070. //-----------------------------------------------------------------------------------
  1071. var nsSetSmiley =
  1072. {
  1073.   isCommandEnabled: function(aCommand, dummy)
  1074.   {
  1075.     return ( window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  1076.  
  1077.   },
  1078.  
  1079.   doCommand: function(aCommand)
  1080.   {
  1081.     
  1082.     var commandNode = document.getElementById(aCommand);
  1083.     var smileyCode = commandNode.getAttribute("state");
  1084.  
  1085.     var strSml;
  1086.     switch(smileyCode)
  1087.     {
  1088.         case ":-)": strSml="s1"; 
  1089.         break;
  1090.         case ":-(": strSml="s2";
  1091.         break;
  1092.         case ";-)": strSml="s3";
  1093.         break;
  1094.         case ":-P": strSml="s4";
  1095.         break;
  1096.         case ":-D": strSml="s5";
  1097.         break;
  1098.         case ":-[": strSml="s6";
  1099.         break;
  1100.         case ":-\\": strSml="s7";
  1101.         break;
  1102.         default:    strSml="";
  1103.         break;
  1104.     }
  1105.  
  1106.     try 
  1107.     {
  1108.       var selection = window.editorShell.editorSelection;
  1109.  
  1110.       if (!selection)
  1111.         return;
  1112.     
  1113.       var extElement = editorShell.CreateElementWithDefaults("span");
  1114.       if (!extElement)
  1115.         return;
  1116.     
  1117.       extElement.setAttribute("-moz-smiley", strSml);
  1118.  
  1119.     
  1120.       var intElement = editorShell.CreateElementWithDefaults("span");
  1121.       if (!intElement)
  1122.         return;
  1123.  
  1124.       //just for mailnews, because of the way it removes HTML
  1125.       var smileButMenu = document.getElementById('smileButtonMenu');      
  1126.       if (smileButMenu.getAttribute("padwithspace"))
  1127.          smileyCode = " " + smileyCode + " ";
  1128.  
  1129.       var txtElement =  document.createTextNode(smileyCode);
  1130.       if (!txtElement)
  1131.         return;
  1132.  
  1133.       intElement.appendChild (txtElement);
  1134.       extElement.appendChild (intElement);
  1135.  
  1136.  
  1137.       editorShell.InsertElementAtSelection(extElement,true);
  1138.       window._content.focus();        
  1139.  
  1140.     } 
  1141.     catch (e) 
  1142.     {
  1143.         dump("Exception occured in smiley InsertElementAtSelection\n");
  1144.     }
  1145.     
  1146.   }
  1147.  
  1148. };
  1149.  
  1150.  
  1151. function doAdvancedProperties(element)
  1152. {
  1153.   if (element)
  1154.   {
  1155.     window.openDialog("chrome://editor/content/EdAdvancedEdit.xul", "_blank", "chrome,close,titlebar,modal,resizable=yes", "", element);
  1156.     window._content.focus();
  1157.   }
  1158. }
  1159.  
  1160. var nsAdvancedPropertiesCommand =
  1161. {
  1162.   isCommandEnabled: function(aCommand, dummy)
  1163.   {
  1164.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  1165.   },
  1166.   doCommand: function(aCommand)
  1167.   {
  1168.     // Launch AdvancedEdit dialog for the selected element
  1169.     var element = window.editorShell.GetSelectedElement("");
  1170.     doAdvancedProperties(element);
  1171.   }
  1172. };
  1173.  
  1174. //-----------------------------------------------------------------------------------
  1175. var nsColorPropertiesCommand =
  1176. {
  1177.   isCommandEnabled: function(aCommand, dummy)
  1178.   {
  1179.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  1180.   },
  1181.   doCommand: function(aCommand)
  1182.   {
  1183.     window.openDialog("chrome://editor/content/EdColorProps.xul","_blank", "chrome,close,titlebar,modal", ""); 
  1184.     window._content.focus();
  1185.   }
  1186. };
  1187.  
  1188. //-----------------------------------------------------------------------------------
  1189. var nsRemoveLinksCommand =
  1190. {
  1191.   isCommandEnabled: function(aCommand, dummy)
  1192.   {
  1193.     // We could see if there's any link in selection, but it doesn't seem worth the work!
  1194.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  1195.   },
  1196.   doCommand: function(aCommand)
  1197.   {
  1198.     window.editorShell.RemoveTextProperty("href", "");
  1199.     window._content.focus();
  1200.   }
  1201. };
  1202.  
  1203.  
  1204. //-----------------------------------------------------------------------------------
  1205. var nsNormalModeCommand =
  1206. {
  1207.   isCommandEnabled: function(aCommand, dummy)
  1208.   {
  1209.     return IsEditorContentHTML(); //(window.editorShell && window.editorShell.documentEditable);
  1210.   },
  1211.   doCommand: function(aCommand)
  1212.   {
  1213.     if (gEditorDisplayMode != DisplayModeNormal)
  1214.       SetEditMode(DisplayModeNormal);
  1215.   }
  1216. };
  1217.  
  1218. var nsAllTagsModeCommand =
  1219. {
  1220.   isCommandEnabled: function(aCommand, dummy)
  1221.   {
  1222.     return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML());
  1223.   },
  1224.   doCommand: function(aCommand)
  1225.   {
  1226.     if (gEditorDisplayMode != DisplayModeAllTags)
  1227.       SetEditMode(DisplayModeAllTags);
  1228.   }
  1229. };
  1230.  
  1231. var nsHTMLSourceModeCommand =
  1232. {
  1233.   isCommandEnabled: function(aCommand, dummy)
  1234.   {
  1235.     return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML());
  1236.   },
  1237.   doCommand: function(aCommand)
  1238.   {
  1239.     if (gEditorDisplayMode != DisplayModeSource)
  1240.       SetEditMode(DisplayModeSource);
  1241.   }
  1242. };
  1243.  
  1244. var nsPreviewModeCommand =
  1245. {
  1246.   isCommandEnabled: function(aCommand, dummy)
  1247.   {
  1248.     return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML());
  1249.   },
  1250.   doCommand: function(aCommand)
  1251.   {
  1252.     FinishHTMLSource();
  1253.     if (gEditorDisplayMode != DisplayModePreview)
  1254.       SetEditMode(DisplayModePreview);
  1255.   }
  1256. };
  1257.  
  1258. //-----------------------------------------------------------------------------------
  1259. var nsInsertOrEditTableCommand =
  1260. {
  1261.   isCommandEnabled: function(aCommand, dummy)
  1262.   {
  1263.     return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML());
  1264.   },
  1265.   doCommand: function(aCommand)
  1266.   {
  1267.     if (IsInTableCell())
  1268.       EditorTableCellProperties();
  1269.     else
  1270.       EditorInsertOrEditTable(true);
  1271.   }
  1272. };
  1273.  
  1274. //-----------------------------------------------------------------------------------
  1275. var nsEditTableCommand =
  1276. {
  1277.   isCommandEnabled: function(aCommand, dummy)
  1278.   {
  1279.     return IsInTable();
  1280.   },
  1281.   doCommand: function(aCommand)
  1282.   {
  1283.     EditorInsertOrEditTable(false);
  1284.   }
  1285. };
  1286.  
  1287. //-----------------------------------------------------------------------------------
  1288. var nsSelectTableCommand =
  1289. {
  1290.   isCommandEnabled: function(aCommand, dummy)
  1291.   {
  1292.     return IsInTable();
  1293.   },
  1294.   doCommand: function(aCommand)
  1295.   {
  1296.     window.editorShell.SelectTable();
  1297.     window._content.focus();
  1298.   }
  1299. };
  1300.  
  1301. var nsSelectTableRowCommand =
  1302. {
  1303.   isCommandEnabled: function(aCommand, dummy)
  1304.   {
  1305.     return IsInTableCell();
  1306.   },
  1307.   doCommand: function(aCommand)
  1308.   {
  1309.     window.editorShell.SelectTableRow();
  1310.     window._content.focus();
  1311.   }
  1312. };
  1313.  
  1314. var nsSelectTableColumnCommand =
  1315. {
  1316.   isCommandEnabled: function(aCommand, dummy)
  1317.   {
  1318.     return IsInTableCell();
  1319.   },
  1320.   doCommand: function(aCommand)
  1321.   {
  1322.     window.editorShell.SelectTableColumn();
  1323.     window._content.focus();
  1324.   }
  1325. };
  1326.  
  1327. var nsSelectTableCellCommand =
  1328. {
  1329.   isCommandEnabled: function(aCommand, dummy)
  1330.   {
  1331.     return IsInTableCell();
  1332.   },
  1333.   doCommand: function(aCommand)
  1334.   {
  1335.     window.editorShell.SelectTableCell();
  1336.     window._content.focus();
  1337.   }
  1338. };
  1339.  
  1340. var nsSelectAllTableCellsCommand =
  1341. {
  1342.   isCommandEnabled: function(aCommand, dummy)
  1343.   {
  1344.     return IsInTable();
  1345.   },
  1346.   doCommand: function(aCommand)
  1347.   {
  1348.     window.editorShell.SelectAllTableCells();
  1349.     window._content.focus();
  1350.   }
  1351. };
  1352.  
  1353. //-----------------------------------------------------------------------------------
  1354. var nsInsertTableCommand =
  1355. {
  1356.   isCommandEnabled: function(aCommand, dummy)
  1357.   {
  1358.     return window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML();
  1359.   },
  1360.   doCommand: function(aCommand)
  1361.   {
  1362.     EditorInsertTable();
  1363.   }
  1364. };
  1365.  
  1366. var nsInsertTableRowAboveCommand =
  1367. {
  1368.   isCommandEnabled: function(aCommand, dummy)
  1369.   {
  1370.     return IsInTableCell();
  1371.   },
  1372.   doCommand: function(aCommand)
  1373.   {
  1374.     window.editorShell.InsertTableRow(1, false);
  1375.     window._content.focus();
  1376.   }
  1377. };
  1378.  
  1379. var nsInsertTableRowBelowCommand =
  1380. {
  1381.   isCommandEnabled: function(aCommand, dummy)
  1382.   {
  1383.     return IsInTableCell();
  1384.   },
  1385.   doCommand: function(aCommand)
  1386.   {
  1387.     window.editorShell.InsertTableRow(1,true);
  1388.     window._content.focus();
  1389.   }
  1390. };
  1391.  
  1392. var nsInsertTableColumnBeforeCommand =
  1393. {
  1394.   isCommandEnabled: function(aCommand, dummy)
  1395.   {
  1396.     return IsInTableCell();
  1397.   },
  1398.   doCommand: function(aCommand)
  1399.   {
  1400.     window.editorShell.InsertTableColumn(1, false);
  1401.     window._content.focus();
  1402.   }
  1403. };
  1404.  
  1405. var nsInsertTableColumnAfterCommand =
  1406. {
  1407.   isCommandEnabled: function(aCommand, dummy)
  1408.   {
  1409.     return IsInTableCell();
  1410.   },
  1411.   doCommand: function(aCommand)
  1412.   {
  1413.     window.editorShell.InsertTableColumn(1, true);
  1414.     window._content.focus();
  1415.   }
  1416. };
  1417.  
  1418. var nsInsertTableCellBeforeCommand =
  1419. {
  1420.   isCommandEnabled: function(aCommand, dummy)
  1421.   {
  1422.     return IsInTableCell();
  1423.   },
  1424.   doCommand: function(aCommand)
  1425.   {
  1426.     window.editorShell.InsertTableCell(1, false);
  1427.   }
  1428. };
  1429.  
  1430. var nsInsertTableCellAfterCommand =
  1431. {
  1432.   isCommandEnabled: function(aCommand, dummy)
  1433.   {
  1434.     return IsInTableCell();
  1435.   },
  1436.   doCommand: function(aCommand)
  1437.   {
  1438.     window.editorShell.InsertTableCell(1, true);
  1439.     window._content.focus();
  1440.   }
  1441. };
  1442.  
  1443. //-----------------------------------------------------------------------------------
  1444. var nsDeleteTableCommand =
  1445. {
  1446.   isCommandEnabled: function(aCommand, dummy)
  1447.   {
  1448.     return IsInTable();
  1449.   },
  1450.   doCommand: function(aCommand)
  1451.   {
  1452.     window.editorShell.DeleteTable();        
  1453.     window._content.focus();
  1454.   }
  1455. };
  1456.  
  1457. var nsDeleteTableRowCommand =
  1458. {
  1459.   isCommandEnabled: function(aCommand, dummy)
  1460.   {
  1461.     return IsInTableCell();
  1462.   },
  1463.   doCommand: function(aCommand)
  1464.   {
  1465.     var rows = GetNumberOfContiguousSelectedRows();
  1466.     // Delete at least one row
  1467.     if (rows == 0)
  1468.       rows = 1;
  1469.  
  1470.     try {
  1471.       window.editorShell.BeginBatchChanges();
  1472.  
  1473.       // Loop to delete all blocks of contiguous, selected rows
  1474.       while (rows)
  1475.       {
  1476.         window.editorShell.DeleteTableRow(rows);
  1477.         rows = GetNumberOfContiguousSelectedRows();
  1478.       }
  1479.       window.editorShell.EndBatchChanges();
  1480.     } catch(ex) {
  1481.       window.editorShell.EndBatchChanges();
  1482.     }
  1483.     window._content.focus();
  1484.   }
  1485. };
  1486.  
  1487. var nsDeleteTableColumnCommand =
  1488. {
  1489.   isCommandEnabled: function(aCommand, dummy)
  1490.   {
  1491.     return IsInTableCell();
  1492.   },
  1493.   doCommand: function(aCommand)
  1494.   {
  1495.     var columns = GetNumberOfContiguousSelectedColumns();
  1496.     // Delete at least one column
  1497.     if (columns == 0)
  1498.       columns = 1;
  1499.  
  1500.     try {
  1501.       window.editorShell.BeginBatchChanges();
  1502.  
  1503.       // Loop to delete all blocks of contiguous, selected columns
  1504.       while (columns)
  1505.       {
  1506.         window.editorShell.DeleteTableColumn(columns);
  1507.         columns = GetNumberOfContiguousSelectedColumns();
  1508.       }
  1509.       window.editorShell.EndBatchChanges();
  1510.     } catch(ex) {
  1511.       window.editorShell.EndBatchChanges();
  1512.     }
  1513.     window._content.focus();
  1514.   }
  1515. };
  1516.  
  1517. var nsDeleteTableCellCommand =
  1518. {
  1519.   isCommandEnabled: function(aCommand, dummy)
  1520.   {
  1521.     return IsInTableCell();
  1522.   },
  1523.   doCommand: function(aCommand)
  1524.   {
  1525.     window.editorShell.DeleteTableCell(1);   
  1526.     window._content.focus();
  1527.   }
  1528. };
  1529.  
  1530. var nsDeleteTableCellContentsCommand =
  1531. {
  1532.   isCommandEnabled: function(aCommand, dummy)
  1533.   {
  1534.     return IsInTableCell();
  1535.   },
  1536.   doCommand: function(aCommand)
  1537.   {
  1538.     window.editorShell.DeleteTableCellContents();
  1539.     window._content.focus();
  1540.   }
  1541. };
  1542.  
  1543.  
  1544. //-----------------------------------------------------------------------------------
  1545. var nsNormalizeTableCommand =
  1546. {
  1547.   isCommandEnabled: function(aCommand, dummy)
  1548.   {
  1549.     return IsInTable();
  1550.   },
  1551.   doCommand: function(aCommand)
  1552.   {
  1553.     // Use nsnull to let editor find table enclosing current selection
  1554.     window.editorShell.NormalizeTable(null);
  1555.     window._content.focus();
  1556.   }
  1557. };
  1558.  
  1559. //-----------------------------------------------------------------------------------
  1560. var nsJoinTableCellsCommand =
  1561. {
  1562.   isCommandEnabled: function(aCommand, dummy)
  1563.   {
  1564.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  1565.     {
  1566.       var tagNameObj = new Object;
  1567.       var countObj = new Object;
  1568.       var cell = window.editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  1569.  
  1570.       // We need a cell and either > 1 selected cell or a cell to the right
  1571.       //  (this cell may originate in a row spanned from above current row)
  1572.       // Note that editorShell returns "td" for "th" also.
  1573.       // (this is a pain! Editor and gecko use lowercase tagNames, JS uses uppercase!)
  1574.       if( cell && (tagNameObj.value == "td"))
  1575.       {
  1576.         // Selected cells
  1577.         if (countObj.value > 1) return true;
  1578.  
  1579.         var colSpan = cell.getAttribute("colspan");
  1580.  
  1581.         // getAttribute returns string, we need number
  1582.         // no attribute means colspan = 1
  1583.         if (!colSpan)
  1584.           colSpan = Number(1);
  1585.         else
  1586.           colSpan = Number(colSpan);
  1587.  
  1588.         // Test if cell exists to the right of current cell
  1589.         // (cells with 0 span should never have cells to the right
  1590.         //  if there is, user can select the 2 cells to join them)
  1591.         return (colSpan != 0 &&
  1592.                 window.editorShell.GetCellAt(null, 
  1593.                                    window.editorShell.GetRowIndex(cell), 
  1594.                                    window.editorShell.GetColumnIndex(cell) + colSpan));
  1595.       }
  1596.     }
  1597.     return false;
  1598.   },
  1599.   doCommand: function(aCommand)
  1600.   {
  1601.     // Param: Don't merge non-contiguous cells
  1602.     window.editorShell.JoinTableCells(false);
  1603.     window._content.focus();
  1604.   }
  1605. };
  1606.  
  1607. //-----------------------------------------------------------------------------------
  1608. var nsSplitTableCellCommand =
  1609. {
  1610.   isCommandEnabled: function(aCommand, dummy)
  1611.   {
  1612.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  1613.     {
  1614.       var tagNameObj = new Object;
  1615.       var countObj = new Object;
  1616.       var cell = window.editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  1617.       // We need a cell parent and there's just 1 selected cell 
  1618.       // or selection is entirely inside 1 cell
  1619.       if ( cell && (tagNameObj.value == "td") && 
  1620.            countObj.value <= 1 &&
  1621.            IsSelectionInOneCell() )
  1622.       {
  1623.         var colSpan = cell.getAttribute("colspan");
  1624.         var rowSpan = cell.getAttribute("rowspan");
  1625.         if (!colSpan) colSpan = 1;
  1626.         if (!rowSpan) rowSpan = 1;
  1627.         return (colSpan > 1  || rowSpan > 1 ||
  1628.                 colSpan == 0 || rowSpan == 0);
  1629.       }
  1630.     }
  1631.     return false;
  1632.   },
  1633.   doCommand: function(aCommand)
  1634.   {
  1635.     window.editorShell.SplitTableCell();
  1636.     window._content.focus();
  1637.   }
  1638. };
  1639.  
  1640. //-----------------------------------------------------------------------------------
  1641. var nsTableOrCellColorCommand =
  1642. {
  1643.   isCommandEnabled: function(aCommand, dummy)
  1644.   {
  1645.     return IsInTable();
  1646.   },
  1647.   doCommand: function(aCommand)
  1648.   {
  1649.     EditorSelectColor("TableOrCell");
  1650.   }
  1651. };
  1652.  
  1653. //-----------------------------------------------------------------------------------
  1654. var nsPreferencesCommand =
  1655. {
  1656.   isCommandEnabled: function(aCommand, dummy)
  1657.   {
  1658.     return true;
  1659.   },
  1660.   doCommand: function(aCommand)
  1661.   {
  1662.     goPreferences('navigator.xul', 'chrome://editor/content/pref-composer.xul','editor');
  1663.     window._content.focus();
  1664.   }
  1665. };
  1666.  
  1667.  
  1668. var nsFinishHTMLSource =
  1669. {
  1670.   isCommandEnabled: function(aCommand, dummy)
  1671.   {
  1672.     return true;
  1673.   },
  1674.   doCommand: function(aCommand)
  1675.   {
  1676.     // In editor.js
  1677.     FinishHTMLSource();
  1678.   }
  1679. };
  1680.  
  1681. var nsCancelHTMLSource =
  1682. {
  1683.   isCommandEnabled: function(aCommand, dummy)
  1684.   {
  1685.     return true;
  1686.   },
  1687.   doCommand: function(aCommand)
  1688.   {
  1689.     // In editor.js
  1690.     CancelHTMLSource();
  1691.   }
  1692. };
  1693.  
  1694. var nsBuildRecentPagesMenu =
  1695. {
  1696.   isCommandEnabled: function(aCommand, dummy)
  1697.   {
  1698.     return true;
  1699.   },
  1700.   doCommand: function(aCommand)
  1701.   {
  1702.     // In editor.js. True means save menu to prefs
  1703.     BuildRecentMenu(true);
  1704.   }
  1705. };
  1706.  
  1707. var nsConvertToTable =
  1708. {
  1709.   isCommandEnabled: function(aCommand, dummy)
  1710.   {
  1711.     if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML())
  1712.     {
  1713.     var selection = window.editorShell.editorSelection;
  1714.  
  1715.     if (selection && !selection.isCollapsed)
  1716.     {
  1717.       // Don't allow if table or cell is the selection
  1718.       var element = window.editorShell.GetSelectedElement("");
  1719.  
  1720.       if (element && (element.nodeName == "td" ||
  1721.                       element.nodeName == "table"))
  1722.         return false;
  1723.  
  1724.       // Selection start and end must be in the same cell
  1725.       //   in same cell or both are NOT in a cell
  1726.       if ( GetParentTableCell(selection.focusNode) !=
  1727.            GetParentTableCell(selection.anchorNode) )
  1728.         return false
  1729.       
  1730.       return true;
  1731.       }
  1732.     }
  1733.     return false;
  1734.   },
  1735.   doCommand: function(aCommand)
  1736.   {
  1737.     if (this.isCommandEnabled())
  1738.     {
  1739.       window.openDialog("chrome://editor/content/EdConvertToTable.xul","_blank", "chrome,close,titlebar,modal")
  1740.     }
  1741.     window._content.focus();
  1742.   }
  1743. };
  1744.  
  1745.