home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / comm.jar / content / editor / EdTableProps.js < prev    next >
Encoding:
JavaScript  |  2001-08-28  |  37.2 KB  |  1,271 lines

  1. /*
  2.  * The contents of this file are subject to the Netscape Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/NPL/
  6.  *
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  *
  12.  * The Original Code is Mozilla Communicator client code, released
  13.  * March 31, 1998.
  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.  *    Ben Goodger
  22.  */
  23.  
  24. //Cancel() is in EdDialogCommon.js
  25. var tagname = "table"
  26. var TableElement;
  27. var CellElement;
  28. var TableCaptionElement;
  29. var TabPanels;
  30. var dialog;
  31. var globalCellElement;
  32. var globalTableElement
  33. var TablePanel = 0;
  34. var CellPanel = 1;
  35. var currentPanel = TablePanel;
  36. var validatePanel;
  37. var defHAlign =   "left";
  38. var centerStr =   "center";  //Index=1
  39. var rightStr =    "right";   // 2
  40. var justifyStr =  "justify"; // 3
  41. var charStr =     "char";    // 4
  42. var defVAlign =   "middle";
  43. var topStr =      "top";
  44. var bottomStr =   "bottom";
  45. var bgcolor = "bgcolor";
  46. var TableColor;
  47. var CellColor;
  48.  
  49. var rowCount = 1;
  50. var colCount = 1;
  51. var lastRowIndex;
  52. var lastColIndex;
  53. var newRowCount;
  54. var newColCount;
  55. var curRowIndex;
  56. var curColIndex;
  57. var curColSpan;
  58. var SelectedCellsType = 1;
  59. var SELECT_CELL = 1;
  60. var SELECT_ROW = 2;
  61. var SELECT_COLUMN = 3;
  62. var RESET_SELECTION = 0;
  63. var cellData = new Object;
  64. var AdvancedEditUsed;
  65. var alignWasChar = false;
  66.  
  67. /*
  68. From C++:
  69.  0 TABLESELECTION_TABLE
  70.  1 TABLESELECTION_CELL   There are 1 or more cells selected
  71.                           but complete rows or columns are not selected
  72.  2 TABLESELECTION_ROW    All cells are in 1 or more rows
  73.                           and in each row, all cells selected
  74.                           Note: This is the value if all rows (thus all cells) are selected
  75.  3 TABLESELECTION_COLUMN All cells are in 1 or more columns
  76. */
  77.  
  78. var gSelectedCellCount = 0;
  79. var ApplyUsed = false;
  80. // What should these be?
  81. var maxRows    = 1000; // This is the value gecko code uses for maximum rowspan, colspan
  82. var maxColumns = 1000;
  83. var selection;
  84. var CellDataChanged = false;
  85. var canDelete = false;
  86.  
  87. // dialog initialization code
  88. function Startup()
  89. {
  90.   if (!InitEditorShell()) return;
  91.  
  92.   selection = editorShell.editorSelection;
  93.   if (!selection) return;
  94.  
  95.   dialog = new Object;
  96.   if (!dialog)
  97.   {
  98.     window.close();
  99.     return;
  100.   }
  101.   // Get dialog widgets - Table Panel
  102.   dialog.TableRowsInput = document.getElementById("TableRowsInput");
  103.   dialog.TableColumnsInput = document.getElementById("TableColumnsInput");
  104.   dialog.TableWidthInput = document.getElementById("TableWidthInput");
  105.   dialog.TableWidthUnits = document.getElementById("TableWidthUnits");
  106.   dialog.BorderWidthInput = document.getElementById("BorderWidthInput");
  107.   dialog.SpacingInput = document.getElementById("SpacingInput");
  108.   dialog.PaddingInput = document.getElementById("PaddingInput");
  109.   dialog.TableAlignList = document.getElementById("TableAlignList");
  110.   dialog.TableCaptionList = document.getElementById("TableCaptionList");
  111.   dialog.TableInheritColor = document.getElementById("TableInheritColor");
  112.  
  113.   // Cell Panel
  114.   dialog.SelectionList = document.getElementById("SelectionList");
  115.   dialog.PreviousButton = document.getElementById("PreviousButton");
  116.   dialog.NextButton = document.getElementById("NextButton");
  117.   // Currently, we always apply changes and load new attributes when changing selection
  118.   // (Let's keep this for possible future use)
  119.   //dialog.ApplyBeforeMove =  document.getElementById("ApplyBeforeMove");
  120.   //dialog.KeepCurrentData = document.getElementById("KeepCurrentData");
  121.  
  122.   dialog.CellHeightInput = document.getElementById("CellHeightInput");
  123.   dialog.CellHeightUnits = document.getElementById("CellHeightUnits");
  124.   dialog.CellWidthInput = document.getElementById("CellWidthInput");
  125.   dialog.CellWidthUnits = document.getElementById("CellWidthUnits");
  126.   dialog.CellHAlignList = document.getElementById("CellHAlignList");
  127.   dialog.CellVAlignList = document.getElementById("CellVAlignList");
  128.   dialog.CellInheritColor = document.getElementById("CellInheritColor");
  129.   dialog.CellStyleList = document.getElementById("CellStyleList");
  130.   dialog.TextWrapList = document.getElementById("TextWrapList");
  131.  
  132.   // In cell panel, user must tell us which attributes to apply via checkboxes,
  133.   //  else we would apply values from one cell to ALL in selection
  134.   //  and that's probably not what they expect!
  135.   dialog.CellHeightCheckbox = document.getElementById("CellHeightCheckbox");
  136.   dialog.CellWidthCheckbox = document.getElementById("CellWidthCheckbox");
  137.   dialog.CellHAlignCheckbox = document.getElementById("CellHAlignCheckbox");
  138.   dialog.CellVAlignCheckbox = document.getElementById("CellVAlignCheckbox");
  139.   dialog.CellStyleCheckbox = document.getElementById("CellStyleCheckbox");
  140.   dialog.TextWrapCheckbox = document.getElementById("TextWrapCheckbox");
  141.   dialog.CellColorCheckbox = document.getElementById("CellColorCheckbox");
  142.  
  143.   TabPanels = document.getElementById("TabPanels");
  144.   var TableTab = document.getElementById("TableTab");
  145.   var CellTab = document.getElementById("CellTab");
  146.  
  147.   TableElement = editorShell.GetElementOrParentByTagName("table", null);
  148.   if(!TableElement)
  149.   {
  150.     dump("Failed to get table element!\n");
  151.     window.close();
  152.     return;
  153.   }
  154.   globalTableElement = TableElement.cloneNode(false);
  155.  
  156.   var tagNameObj = new Object;
  157.   var countObj = new Object;
  158.   var tableOrCellElement = editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  159.   gSelectedCellCount = countObj.value;
  160.  
  161.   if (tagNameObj.value == "td")
  162.   {
  163.     // We are in a cell
  164.     CellElement = tableOrCellElement;
  165.     globalCellElement = CellElement.cloneNode(false);
  166.  
  167.     // Tells us whether cell, row, or column is selected
  168.     SelectedCellsType = editorShell.GetSelectedCellsType(TableElement);
  169.  
  170.     // Ignore types except Cell, Row, and Column
  171.     if (SelectedCellsType < SELECT_CELL || SelectedCellsType > SELECT_COLUMN)
  172.       SelectedCellsType = SELECT_CELL;
  173.  
  174.     // Be sure at least 1 cell is selected.
  175.     // (If the count is 0, then we were inside the cell.)
  176.     if (gSelectedCellCount == 0)
  177.       DoCellSelection();
  178.  
  179.     // Get location in the cell map
  180.     curRowIndex = editorShell.GetRowIndex(CellElement);
  181.     curColIndex = editorShell.GetColumnIndex(CellElement);
  182.  
  183.     // We save the current colspan to quickly
  184.     //  move selection from from cell to cell
  185.     if (GetCellData(curRowIndex, curColIndex))
  186.       curColSpan = cellData.colSpan;
  187.  
  188.     // Starting TabPanel name is passed in
  189.     if (window.arguments[1] == "CellPanel")
  190.     {
  191.       currentPanel = CellPanel;
  192.  
  193.       //Set index for starting panel on the <tabpanels> element
  194.       TabPanels.setAttribute("index", CellPanel);
  195.  
  196.       // Trigger setting of style for the tab widgets
  197.       CellTab.setAttribute("selected", "true");
  198.       TableTab.removeAttribute("selected");
  199.  
  200.       // Use cell element for Advanced Edit dialog
  201.       globalElement = globalCellElement;
  202.     }
  203.   }
  204.  
  205.   if (currentPanel == TablePanel)
  206.   {
  207.     // Use table element for Advanced Edit dialog
  208.     globalElement = globalTableElement;
  209.  
  210.     // We may call this with table selected, but no cell,
  211.     //  so disable the Cell Properties tab
  212.     if(!CellElement)
  213.     {
  214.       // XXX: Disabling of tabs is currently broken, so for
  215.       //      now we'll just remove the tab completely.
  216.       //CellTab.setAttribute("disabled", "true");
  217.       CellTab.parentNode.removeChild(CellTab);
  218.     }
  219.   }
  220.  
  221.   doSetOKCancel(onOK, onCancel, 0, onApply);
  222.  
  223.   // Note: we must use TableElement, not globalTableElement for these,
  224.   //  thus we should not put this in InitDialog.
  225.   // Instead, monitor desired counts with separate globals
  226.   rowCount = editorShell.GetTableRowCount(TableElement);
  227.   lastRowIndex = rowCount-1;
  228.   colCount = editorShell.GetTableColumnCount(TableElement);
  229.   lastColIndex = colCount-1;
  230.  
  231.  
  232.   // Set appropriate icons and enable state for the Previous/Next buttons
  233.   SetSelectionButtons();
  234.  
  235.   // If only one cell in table, disable change-selection widgets
  236.   if (rowCount == 1 && colCount == 1)
  237.     dialog.SelectionList.setAttribute("disabled", "true");
  238.  
  239.   // User can change these via textboxes
  240.   newRowCount = rowCount;
  241.   newColCount = colCount;
  242.  
  243.   // This flag is used to control whether set check state
  244.   //  on "set attribute" checkboxes
  245.   // (Advanced Edit dialog use calls  InitDialog when done)
  246.   AdvancedEditUsed = false;
  247.   InitDialog();
  248.   AdvancedEditUsed = true;
  249.  
  250.   // If first initializing, we really aren't changing anything
  251.   CellDataChanged = false;
  252.  
  253.   if (currentPanel == CellPanel)
  254.     dialog.SelectionList.focus();
  255.   else
  256.     SetTextboxFocus(dialog.TableRowsInput);
  257.  
  258.   SetWindowLocation();
  259. }
  260.  
  261.  
  262. function InitDialog()
  263. {
  264. // turn on Button3 to be "apply"
  265.   var applyButton = document.getElementById("Button3");
  266.   if (applyButton)
  267.   {
  268.     applyButton.label = GetString("Apply");
  269.     applyButton.removeAttribute("collapsed");
  270.   }
  271.   
  272.   // Get Table attributes
  273.   dialog.TableRowsInput.value = rowCount;
  274.   dialog.TableColumnsInput.value = colCount;
  275.   dialog.TableWidthInput.value = InitPixelOrPercentMenulist(globalTableElement, TableElement, "width", "TableWidthUnits", gPercent);
  276.   dialog.BorderWidthInput.value = globalTableElement.border;
  277.   dialog.SpacingInput.value = globalTableElement.cellSpacing;
  278.   dialog.PaddingInput.value = globalTableElement.cellPadding;
  279.  
  280.   //BUG: The align strings are converted: e.g., "center" becomes "Center";
  281.   var halign = globalTableElement.align.toLowerCase();
  282.   if (halign == centerStr)
  283.     dialog.TableAlignList.selectedIndex = 1;
  284.   else if (halign == rightStr)
  285.     dialog.TableAlignList.selectedIndex = 2;
  286.   else // Default = left
  287.     dialog.TableAlignList.selectedIndex = 0;
  288.  
  289.   // Be sure to get caption from table in doc, not the copied "globalTableElement"
  290.   TableCaptionElement = TableElement.caption;
  291.   var index = 0;
  292.   if (TableCaptionElement)
  293.   {
  294.     // Note: Other possible values are "left" and "right",
  295.     //  but "align" is deprecated, so should we even support "botton"?
  296.     if (TableCaptionElement.vAlign == "bottom")
  297.       index = 2;
  298.     else
  299.       index = 1;
  300.   }
  301.   dialog.TableCaptionList.selectedIndex = index;
  302.  
  303.   TableColor = globalTableElement.bgColor;
  304.   SetColor("tableBackgroundCW", TableColor);
  305.  
  306.   InitCellPanel();
  307. }
  308.  
  309. function InitCellPanel()
  310. {
  311.   // Get cell attributes
  312.   if (globalCellElement)
  313.   {
  314.     // This assumes order of items is Cell, Row, Column
  315.     dialog.SelectionList.selectedIndex = SelectedCellsType-1;
  316.  
  317.     var previousValue = dialog.CellHeightInput.value;
  318.     dialog.CellHeightInput.value = InitPixelOrPercentMenulist(globalCellElement, CellElement, "height", "CellHeightUnits", gPixel);
  319.     dialog.CellHeightCheckbox.checked = AdvancedEditUsed && previousValue != dialog.CellHeightInput.value;
  320.  
  321.     previousValue= dialog.CellWidthInput.value;
  322.     dialog.CellWidthInput.value = InitPixelOrPercentMenulist(globalCellElement, CellElement, "width", "CellWidthUnits", gPixel);
  323.     dialog.CellWidthCheckbox.checked = AdvancedEditUsed && previousValue != dialog.CellWidthInput.value;
  324.  
  325.     var previousIndex = dialog.CellVAlignList.selectedIndex;
  326.     var valign = globalCellElement.vAlign.toLowerCase();
  327.     if (valign == topStr)
  328.       dialog.CellVAlignList.selectedIndex = 0;
  329.     else if (valign == bottomStr)
  330.       dialog.CellVAlignList.selectedIndex = 2;
  331.     else // Default = middle
  332.       dialog.CellVAlignList.selectedIndex = 1;
  333.  
  334.     dialog.CellVAlignCheckbox.checked = AdvancedEditUsed && previousValue != dialog.CellVAlignList.selectedIndex;
  335.  
  336.  
  337.     previousIndex = dialog.CellHAlignList.selectedIndex;
  338.  
  339.     alignWasChar = false;
  340.  
  341.     var halign = globalCellElement.align.toLowerCase();
  342.     switch (halign)
  343.     {
  344.       case centerStr:
  345.         dialog.CellHAlignList.selectedIndex = 1;
  346.         break;
  347.       case rightStr:
  348.         dialog.CellHAlignList.selectedIndex = 2;
  349.         break;
  350.       case justifyStr:
  351.         dialog.CellHAlignList.selectedIndex = 3;
  352.         break;
  353.       case charStr:
  354.         // We don't support UI for this because layout doesn't work: bug 2212.
  355.         // Remember that's what they had so we don't change it
  356.         //  unless they change the alignment by using the menulist
  357.         alignWasChar = true;
  358.         // Fall through to use show default alignment in menu
  359.       default:
  360.         // Default depends on cell type (TH is "center", TD is "left")
  361.         dialog.CellHAlignList.selectedIndex =
  362.           (globalCellElement.nodeName.toLowerCase() == "th") ? 1 : 0;
  363.         break;
  364.     }
  365.  
  366.     dialog.CellHAlignCheckbox.checked = AdvancedEditUsed &&
  367.       previousIndex != dialog.CellHAlignList.selectedIndex;
  368.  
  369.     previousIndex = dialog.CellStyleList.selectedIndex;
  370.     dialog.CellStyleList.selectedIndex = (globalCellElement.nodeName.toLowerCase() == "th") ? 1 : 0;
  371.     dialog.CellStyleCheckbox.checked = AdvancedEditUsed && previousIndex != dialog.CellStyleList.selectedIndex;
  372.  
  373.     previousIndex = dialog.TextWrapList.selectedIndex;
  374.     dialog.TextWrapList.selectedIndex = globalCellElement.noWrap ? 1 : 0;
  375.     dialog.TextWrapCheckbox.checked = AdvancedEditUsed && previousIndex != dialog.TextWrapList.selectedIndex;
  376.  
  377.     previousValue = CellColor;
  378.     SetColor("cellBackgroundCW", globalCellElement.bgColor);
  379.     dialog.CellColorCheckbox.checked = AdvancedEditUsed && CellColor != globalCellElement.bgColor;
  380.     CellColor = globalCellElement.bgColor;
  381.  
  382.     // We want to set this true in case changes came
  383.     //   from Advanced Edit dialog session (must assume something changed)
  384.     CellDataChanged = true;
  385.   }
  386. }
  387.  
  388. function GetCellData(rowIndex, colIndex)
  389. {
  390.   // Get actual rowspan and colspan
  391.   var startRowIndexObj = new Object;
  392.   var startColIndexObj = new Object;
  393.   var rowSpanObj = new Object;
  394.   var colSpanObj = new Object;
  395.   var actualRowSpanObj = new Object;
  396.   var actualColSpanObj = new Object;
  397.   var isSelectedObj = new Object;
  398.   if (!cellData)
  399.     cellData = new Object;
  400.  
  401.   try {
  402.     cellData.cell =
  403.       editorShell.GetCellDataAt(TableElement, rowIndex, colIndex,
  404.                                 startRowIndexObj, startColIndexObj,
  405.                                 rowSpanObj, colSpanObj,
  406.                                 actualRowSpanObj, actualColSpanObj, isSelectedObj);
  407.     // We didn't find a cell
  408.     if (!cellData.cell) return false;
  409.   }
  410.   catch(ex) {
  411.     return false;
  412.   }
  413.  
  414.   cellData.startRowIndex = startRowIndexObj.value;
  415.   cellData.startColIndex = startColIndexObj.value;
  416.   cellData.rowSpan = rowSpanObj.value;
  417.   cellData.colSpan = colSpanObj.value;
  418.   cellData.actualRowSpan = actualRowSpanObj.value;
  419.   cellData.actualColSpan = actualColSpanObj.value;
  420.   cellData.isSelected = isSelectedObj.value;
  421.   return true;
  422. }
  423.  
  424. function SelectTableTab()
  425. {
  426.   globalElement = globalTableElement;
  427.   currentPanel = TablePanel;
  428. }
  429.  
  430. function SelectCellTab()
  431. {
  432.   globalElement = globalCellElement;
  433.   currentPanel = CellPanel;
  434. }
  435.  
  436. function SelectCellHAlign()
  437. {
  438.   SetCheckbox("CellHAlignCheckbox");
  439.   // Once user changes the alignment,
  440.   //  we loose their original "CharAt" alignment"
  441.   alignWasChar = false;
  442. }
  443.  
  444. function GetColorAndUpdate(ColorWellID)
  445. {
  446.   var colorWell = document.getElementById(ColorWellID);
  447.   if (!colorWell) return;
  448.  
  449.   var colorObj = new Object;
  450.  
  451.   switch( ColorWellID )
  452.   {
  453.     case "tableBackgroundCW":
  454.       colorObj.Type = "Table";
  455.       colorObj.TableColor = TableColor;
  456.       break;
  457.     case "cellBackgroundCW":
  458.       colorObj.Type = "Cell";
  459.       colorObj.CellColor = CellColor;
  460.       break;
  461.   }
  462.   // Avoid the JS warning
  463.   colorObj.NoDefault = false;
  464.   window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", colorObj);
  465.  
  466.   // User canceled the dialog
  467.   if (colorObj.Cancel)
  468.     return;
  469.  
  470.   switch( ColorWellID )
  471.   {
  472.     case "tableBackgroundCW":
  473.       TableColor = colorObj.BackgroundColor;
  474.       SetColor(ColorWellID, TableColor);
  475.       break;
  476.     case "cellBackgroundCW":
  477.       CellColor = colorObj.BackgroundColor;
  478.       SetColor(ColorWellID, CellColor);
  479.       SetCheckbox('CellColorCheckbox');
  480.       break;
  481.   }
  482. }
  483.  
  484. function SetColor(ColorWellID, color)
  485. {
  486.   // Save the color
  487.   if (ColorWellID == "cellBackgroundCW")
  488.   {
  489.     if (color)
  490.     {
  491.       globalCellElement.setAttribute(bgcolor, color);
  492.       dialog.CellInheritColor.setAttribute("collapsed","true");
  493.     }
  494.     else
  495.     {
  496.       globalCellElement.removeAttribute(bgcolor);
  497.       // Reveal addition message explaining "default" color
  498.       dialog.CellInheritColor.removeAttribute("collapsed");
  499.     }
  500.   }
  501.   else
  502.   {
  503.     if (color)
  504.     {
  505.       globalTableElement.setAttribute(bgcolor, color);
  506.       dialog.TableInheritColor.setAttribute("collapsed","true");
  507.     }
  508.     else
  509.     {
  510.       globalTableElement.removeAttribute(bgcolor);
  511.       dialog.TableInheritColor.removeAttribute("collapsed");
  512.     }
  513.     SetCheckbox('CellColorCheckbox');
  514.   }
  515.  
  516.   setColorWell(ColorWellID, color);
  517. }
  518.  
  519. function ChangeSelectionToFirstCell()
  520. {
  521.   if (!GetCellData(0,0))
  522.   {
  523.     dump("Can't find first cell in table!\n");
  524.     return;
  525.   }
  526.   CellElement = cellData.cell;
  527.   globalCellElement = CellElement;
  528.   globalElement = CellElement;
  529.  
  530.   curRowIndex = 0;
  531.   curColIndex = 0;
  532.   ChangeSelection(RESET_SELECTION);
  533. }
  534.  
  535. function ChangeSelection(newType)
  536. {
  537.   newType = Number(newType);
  538.  
  539.   if (SelectedCellsType == newType)
  540.     return;
  541.  
  542.   if (newType == RESET_SELECTION)
  543.     // Restore selection to existing focus cell
  544.     selection.collapse(CellElement,0);
  545.   else
  546.     SelectedCellsType = newType;
  547.  
  548.   // Keep the same focus CellElement, just change the type
  549.   DoCellSelection();
  550.   SetSelectionButtons();
  551.  
  552.   // Note: globalCellElement should still be a clone of CellElement
  553. }
  554.  
  555. function MoveSelection(forward)
  556. {
  557.   var newRowIndex = curRowIndex;
  558.   var newColIndex = curColIndex;
  559.   var focusCell;
  560.   var inRow = false;
  561.  
  562.   if (SelectedCellsType == SELECT_ROW)
  563.   {
  564.     newRowIndex += (forward ? 1 : -1);
  565.  
  566.     // Wrap around if before first or after last row
  567.     if (newRowIndex < 0)
  568.       newRowIndex = lastRowIndex;
  569.     else if (newRowIndex > lastRowIndex)
  570.       newRowIndex = 0;
  571.     inRow = true;
  572.  
  573.     // Use first cell in row for focus cell
  574.     newColIndex = 0;
  575.   }
  576.   else
  577.   {
  578.     // Cell or column:
  579.     if (!forward)
  580.       newColIndex--;
  581.  
  582.     if (SelectedCellsType == SELECT_CELL)
  583.     {
  584.       // Skip to next cell
  585.       if (forward)
  586.         newColIndex += curColSpan;
  587.     }
  588.     else  // SELECT_COLUMN
  589.     {
  590.       // Use first cell in column for focus cell
  591.       newRowIndex = 0;
  592.  
  593.       // Don't skip by colspan,
  594.       //  but find first cell in next cellmap column
  595.       if (forward)
  596.         newColIndex++;
  597.     }
  598.  
  599.     if (newColIndex < 0)
  600.     {
  601.       // Request is before the first cell in column
  602.  
  603.       // Wrap to last cell in column
  604.       newColIndex = lastColIndex;
  605.  
  606.       if (SelectedCellsType == SELECT_CELL)
  607.       {
  608.         // If moving by cell, also wrap to previous...
  609.         if (newRowIndex > 0)
  610.           newRowIndex -= 1;
  611.         else
  612.           // ...or the last row
  613.           newRowIndex = lastRowIndex;
  614.  
  615.         inRow = true;
  616.       }
  617.     }
  618.     else if (newColIndex > lastColIndex)
  619.     {
  620.       // Request is after the last cell in column
  621.  
  622.       // Wrap to first cell in column
  623.       newColIndex = 0;
  624.  
  625.       if (SelectedCellsType == SELECT_CELL)
  626.       {
  627.         // If moving by cell, also wrap to next...
  628.         if (newRowIndex < lastRowIndex)
  629.           newRowIndex++;
  630.         else
  631.           // ...or the first row
  632.           newRowIndex = 0;
  633.  
  634.         inRow = true;
  635.       }
  636.     }
  637.   }
  638.  
  639.   // Get the cell at the new location
  640.   do {
  641.     if (!GetCellData(newRowIndex, newColIndex))
  642.     {
  643.       dump("MoveSelection: CELL NOT FOUND\n");
  644.       return;
  645.     }
  646.     if (inRow)
  647.     {
  648.       if (cellData.startRowIndex == newRowIndex)
  649.         break;
  650.       else
  651.         // Cell spans from a row above, look for the next cell in row
  652.         newRowIndex += cellData.actualRowSpan;
  653.     }
  654.     else
  655.     {
  656.       if (cellData.startColIndex == newColIndex)
  657.         break;
  658.       else
  659.         // Cell spans from a Col above, look for the next cell in column
  660.         newColIndex += cellData.actualColSpan;
  661.     }
  662.   }
  663.   while(true);
  664.  
  665.   // Save data for current selection before changing
  666.   if (CellDataChanged) // && dialog.ApplyBeforeMove.checked)
  667.   {
  668.     if (!ValidateCellData())
  669.       return;
  670.  
  671.     editorShell.BeginBatchChanges();
  672.     // Apply changes to all selected cells
  673.     ApplyCellAttributes();
  674.     editorShell.EndBatchChanges();
  675.  
  676.     SetCloseButton();
  677.   }
  678.  
  679.   // Set cell and other data for new selection
  680.   CellElement = cellData.cell;
  681.  
  682.   // Save globals for new current cell
  683.   curRowIndex = cellData.startRowIndex;
  684.   curColIndex = cellData.startColIndex;
  685.   curColSpan = cellData.actualColSpan;
  686.  
  687.   // Copy for new global cell
  688.   globalCellElement = CellElement.cloneNode(false);
  689.   globalElement = globalCellElement;
  690.  
  691.   // Change the selection
  692.   DoCellSelection();
  693.  
  694.   // Reinitialize dialog using new cell
  695. //  if (!dialog.KeepCurrentData.checked)
  696.   // Setting this false unchecks all "set attributes" checkboxes
  697.   AdvancedEditUsed = false;
  698.   InitCellPanel();
  699.   AdvancedEditUsed = true;
  700. }
  701.  
  702.  
  703. function DoCellSelection()
  704. {
  705.   // Collapse selection into to the focus cell
  706.   //  so editor uses that as start cell
  707.   selection.collapse(CellElement, 0);
  708.  
  709.   switch (SelectedCellsType)
  710.   {
  711.     case SELECT_CELL:
  712.       editorShell.SelectTableCell();
  713.       break
  714.     case SELECT_ROW:
  715.       editorShell.SelectTableRow();
  716.       break;
  717.     default:
  718.       editorShell.SelectTableColumn();
  719.       break;
  720.   }
  721.   // Get number of cells selected
  722.   var tagNameObj = new Object;
  723.   var countObj = new Object;
  724.   tagNameObj.value = "";
  725.   var tableOrCellElement = editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  726.   if (tagNameObj.value == "td")
  727.     gSelectedCellCount = countObj.value;
  728.   else
  729.     gSelectedCellCount = 0;
  730.  
  731.   // Currently, we can only allow advanced editing on ONE cell element at a time
  732.   //   else we ignore CSS, JS, and HTML attributes not already in dialog
  733.   SetElementEnabledById("AdvancedEditButton2", gSelectedCellCount == 1);
  734. }
  735.  
  736. function SetSelectionButtons()
  737. {
  738.   if (SelectedCellsType == SELECT_ROW)
  739.   {
  740.     // Trigger CSS to set images of up and down arrows
  741.     dialog.PreviousButton.setAttribute("type","row");
  742.     dialog.NextButton.setAttribute("type","row");
  743.   }
  744.   else
  745.   {
  746.     // or images of left and right arrows
  747.     dialog.PreviousButton.setAttribute("type","col");
  748.     dialog.NextButton.setAttribute("type","col");
  749.   }
  750.   DisableSelectionButtons((SelectedCellsType == SELECT_ROW && rowCount == 1) ||
  751.                           (SelectedCellsType == SELECT_COLUMN && colCount == 1) ||
  752.                           (rowCount == 1 && colCount == 1));
  753. }
  754.  
  755. function DisableSelectionButtons( disable )
  756. {
  757.   dialog.PreviousButton.setAttribute("disabled", disable ? "true" : "false");
  758.   dialog.NextButton.setAttribute("disabled", disable ? "true" : "false");
  759. }
  760.  
  761. function SwitchToValidatePanel()
  762. {
  763.   if (currentPanel != validatePanel)
  764.   {
  765.     //Set index for starting panel on the <tabpanels> element
  766.     TabPanels.setAttribute("index", validatePanel);
  767.     if (validatePanel == CellPanel)
  768.     {
  769.       // Trigger setting of style for the tab widgets
  770.       CellTab.setAttribute("selected", "true");
  771.       TableTab.removeAttribute("selected");
  772.     } else {
  773.       TableTab.setAttribute("selected", "true");
  774.       CellTab.removeAttribute("selected");
  775.     }
  776.     currentPanel = validatePanel;
  777.   }
  778. }
  779.  
  780. function SetAlign(listID, defaultValue, element, attName)
  781. {
  782.   var value = document.getElementById(listID).selectedItem.value;
  783.   if (value == defaultValue)
  784.     element.removeAttribute(attName);
  785.   else
  786.     element.setAttribute(attName, value);
  787. }
  788.  
  789. function ValidateTableData()
  790. {
  791.   validatePanel = TablePanel;
  792.   newRowCount = Number(ValidateNumber(dialog.TableRowsInput, null, 1, maxRows, null, null, true));
  793.   if (gValidationError) return false;
  794.  
  795.   newColCount = Number(ValidateNumber(dialog.TableColumnsInput, null, 1, maxColumns, null, null, true));
  796.   if (gValidationError) return false;
  797.  
  798.   // If user is deleting any cells, get confirmation
  799.   // (This is a global to the dialog and we ask only once per dialog session)
  800.   if ( !canDelete &&
  801.         (newRowCount < rowCount ||
  802.          newColCount < colCount) ) 
  803.   {
  804.     if (ConfirmWithTitle(GetString("DeleteTableTitle"), 
  805.                          GetString("DeleteTableMsg"),
  806.                          GetString("DeleteCells")) )
  807.     {
  808.       canDelete = true;
  809.     }
  810.     else
  811.     {
  812.       SetTextboxFocus(newRowCount < rowCount ? dialog.TableRowsInput : dialog.TableColumnsInput);
  813.       return false;
  814.     }
  815.   }
  816.  
  817.   ValidateNumber(dialog.TableWidthInput, dialog.TableWidthUnits,
  818.                  1, maxPixels, globalTableElement, "width");
  819.   if (gValidationError) return false;
  820.  
  821.   var border = ValidateNumber(dialog.BorderWidthInput, null, 0, maxPixels, globalTableElement, "border");
  822.   // TODO: Deal with "BORDER" without value issue
  823.   if (gValidationError) return false;
  824.  
  825.   ValidateNumber(dialog.SpacingInput, null, 0, maxPixels, globalTableElement, "cellspacing");
  826.   if (gValidationError) return false;
  827.  
  828.   ValidateNumber(dialog.PaddingInput, null, 0, maxPixels, globalTableElement, "cellpadding");
  829.   if (gValidationError) return false;
  830.  
  831.   SetAlign("TableAlignList", defHAlign, globalTableElement, "align");
  832.  
  833.   // Color is set on globalCellElement immediately
  834.   return true;
  835. }
  836.  
  837. function ValidateCellData()
  838. {
  839.  
  840.   validatePanel = CellPanel;
  841.  
  842.   if (dialog.CellHeightCheckbox.checked)
  843.   {
  844.     ValidateNumber(dialog.CellHeightInput, dialog.CellHeightUnits,
  845.                     1, maxPixels, globalCellElement, "height");
  846.     if (gValidationError) return false;
  847.   }
  848.  
  849.   if (dialog.CellWidthCheckbox.checked)
  850.   {
  851.     ValidateNumber(dialog.CellWidthInput, dialog.CellWidthUnits,
  852.                    1, maxPixels, globalCellElement, "width");
  853.     if (gValidationError) return false;
  854.   }
  855.  
  856.   if (dialog.CellHAlignCheckbox.checked)
  857.   {
  858.     var hAlign = dialog.CellHAlignList.selectedItem.value;
  859.  
  860.     // Horizontal alignment is complicated by "char" type
  861.     // We don't change current values if user didn't edit alignment
  862.     if (!alignWasChar)
  863.     {
  864.       globalCellElement.removeAttribute(charStr);
  865.  
  866.       // Always set "align" attribute,
  867.       //  so the default "left" is effective in a cell
  868.       //  when parent row has align set.
  869.       globalCellElement.setAttribute("align", hAlign);
  870.     }
  871.   }
  872.  
  873.   if (dialog.CellVAlignCheckbox.checked)
  874.   {
  875.     // Always set valign (no default in 2nd param) so
  876.     //  the default "middle" is effective in a cell
  877.     //  when parent row has valign set.
  878.     SetAlign("CellVAlignList", "", globalCellElement, "valign");
  879.   }
  880.  
  881.   if (dialog.TextWrapCheckbox.checked)
  882.   {
  883.     if (dialog.TextWrapList.selectedIndex == 1)
  884.       globalCellElement.setAttribute("nowrap","true");
  885.     else
  886.       globalCellElement.removeAttribute("nowrap");
  887.   }
  888.  
  889.   return true;
  890. }
  891.  
  892. function ValidateData()
  893. {
  894.   var result;
  895.   var savePanel = currentPanel;
  896.  
  897.   // Validate current panel first
  898.   if (currentPanel == TablePanel)
  899.   {
  900.     result = ValidateTableData();
  901.     if (result)
  902.       result = ValidateCellData();
  903.   } else {
  904.     result = ValidateCellData();
  905.     if (result)
  906.       result = ValidateTableData();
  907.   }
  908.   if(!result) return false;
  909.  
  910.   // If we passed, restore former currentPanel
  911.   currentPanel = savePanel;
  912.  
  913.   // Set global element for AdvancedEdit
  914.   if(currentPanel == TablePanel)
  915.     globalElement = globalTableElement;
  916.   else
  917.     globalElement = globalCellElement;
  918.  
  919.   return true;
  920. }
  921.  
  922. function ChangeCellTextbox(textboxID)
  923. {
  924.   // Filter input for just integers
  925.   forceInteger(textboxID);
  926.  
  927.   if (currentPanel == CellPanel)
  928.     CellDataChanged = true;
  929. }
  930.  
  931. // Call this when a textbox or menulist is changed
  932. //   so the checkbox is automatically set
  933. function SetCheckbox(checkboxID)
  934. {
  935.   if (checkboxID && checkboxID.length > 0)
  936.   {
  937.     // Set associated checkbox
  938.     document.getElementById(checkboxID).checked = true;
  939.   }
  940.   CellDataChanged = true;
  941. }
  942.  
  943. function ChangeIntTextbox(textboxID, checkboxID)
  944. {
  945.   // Filter input for just integers
  946.   forceInteger(textboxID);
  947.  
  948.   // Set associated checkbox
  949.   SetCheckbox(checkboxID);
  950. }
  951.  
  952. function CloneAttribute(destElement, srcElement, attr)
  953. {
  954.   var value = srcElement.getAttribute(attr);
  955.  
  956.   // Use editorShell methods since we are always
  957.   //  modifying a table in the document and
  958.   //  we need transaction system for undo
  959.   if (!value || value.length == 0)
  960.     editorShell.RemoveAttribute(destElement, attr);
  961.   else
  962.     editorShell.SetAttribute(destElement, attr, value);
  963. }
  964.  
  965. function ApplyTableAttributes()
  966. {
  967.   var newAlign = dialog.TableCaptionList.selectedItem.value;
  968.   if (!newAlign) newAlign = "";
  969.  
  970.   if (TableCaptionElement)
  971.   {
  972.     // Get current alignment
  973.     var align = TableCaptionElement.align.toLowerCase();
  974.     // This is the default
  975.     if (!align) align = "top";
  976.  
  977.     if (newAlign == "")
  978.     {
  979.       // Remove existing caption
  980.       editorShell.DeleteElement(TableCaptionElement);
  981.       TableCaptionElement = null;
  982.     }
  983.     else if( align != newAlign)
  984.     {
  985.       if (align == "top") // This is default, so don't explicitly set it
  986.         editorShell.RemoveAttribute(TableCaptionElement, "align");
  987.       else
  988.         editorShell.SetAttribute(TableCaptionElement, "align", newAlign);
  989.     }
  990.   }
  991.   else if (newAlign != "")
  992.   {
  993.     // Create and insert a caption:
  994.     TableCaptionElement = editorShell.CreateElementWithDefaults("caption");
  995.     if (TableCaptionElement)
  996.     {
  997.       if (newAlign != "top")
  998.         TableCaptionElement.setAttribute("align", newAlign);
  999.  
  1000.       // Insert it into the table - caption is always inserted as first child
  1001.       editorShell.InsertElement(TableCaptionElement, TableElement, 0, true);
  1002.  
  1003.       // Put selecton back where it was
  1004.       ChangeSelection(RESET_SELECTION);
  1005.     }
  1006.   }
  1007.  
  1008.   var countDelta;
  1009.   var foundcell;
  1010.   var i;
  1011.  
  1012.   if (newRowCount != rowCount)
  1013.   {
  1014.     countDelta = newRowCount - rowCount;
  1015.     if (newRowCount > rowCount)
  1016.     {
  1017.       // Append new rows
  1018.       // Find first cell in last row
  1019.       if(GetCellData(lastRowIndex, 0))
  1020.       {
  1021.         try {
  1022.           // Move selection to the last cell
  1023.           selection.collapse(cellData.cell,0);
  1024.           // Insert new rows after it
  1025.           editorShell.InsertTableRow(countDelta, true);
  1026.           rowCount = newRowCount;
  1027.           lastRowIndex = rowCount - 1;
  1028.           // Put selecton back where it was
  1029.           ChangeSelection(RESET_SELECTION);
  1030.         }
  1031.         catch(ex) {
  1032.           dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
  1033.         }
  1034.       }
  1035.     }
  1036.     else
  1037.     {
  1038.       // Delete rows
  1039.       if (canDelete)
  1040.       {
  1041.         // Find first cell starting in first row we delete
  1042.         var firstDeleteRow = rowCount + countDelta;
  1043.         foundCell = false;
  1044.         for ( i = 0; i <= lastColIndex; i++)
  1045.         {
  1046.           if (!GetCellData(firstDeleteRow, i))
  1047.             break; // We failed to find a cell
  1048.  
  1049.           if (cellData.startRowIndex == firstDeleteRow)
  1050.           {
  1051.             foundCell = true;
  1052.             break;
  1053.           }
  1054.         };
  1055.         if (foundCell)
  1056.         {
  1057.           try {
  1058.             // Move selection to the cell we found
  1059.             selection.collapse(cellData.cell, 0);
  1060.             editorShell.DeleteTableRow(-countDelta);
  1061.             rowCount = newRowCount;
  1062.             lastRowIndex = rowCount - 1;
  1063.             if (curRowIndex > lastRowIndex)
  1064.               // We are deleting our selection
  1065.               // move it to start of table
  1066.               ChangeSelectionToFirstCell()
  1067.             else
  1068.               // Put selecton back where it was
  1069.               ChangeSelection(RESET_SELECTION);
  1070.           }
  1071.           catch(ex) {
  1072.             dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
  1073.           }
  1074.         }
  1075.       }
  1076.     }
  1077.   }
  1078.  
  1079.   if (newColCount != colCount)
  1080.   {
  1081.     countDelta = newColCount - colCount;
  1082.  
  1083.     if (newColCount > colCount)
  1084.     {
  1085.       // Append new columns
  1086.       // Find last cell in first column
  1087.       if(GetCellData(0, lastColIndex))
  1088.       {
  1089.         try {
  1090.           // Move selection to the last cell
  1091.           selection.collapse(cellData.cell,0);
  1092.           editorShell.InsertTableColumn(countDelta, true);
  1093.           colCount = newColCount;
  1094.           lastColIndex = colCount-1;
  1095.           // Restore selection
  1096.           ChangeSelection(RESET_SELECTION);
  1097.         }
  1098.         catch(ex) {
  1099.           dump("FAILED TO FIND FIRST CELL IN LAST COLUMN\n");
  1100.         }
  1101.       }
  1102.     }
  1103.     else
  1104.     {
  1105.       // Delete columns
  1106.       if (canDelete)
  1107.       {
  1108.         var firstDeleteCol = colCount + countDelta;
  1109.         foundCell = false;
  1110.         for ( i = 0; i <= lastRowIndex; i++)
  1111.         {
  1112.           // Find first cell starting in first column we delete
  1113.           if (!GetCellData(i, firstDeleteCol))
  1114.             break; // We failed to find a cell
  1115.  
  1116.           if (cellData.startColIndex == firstDeleteCol)
  1117.           {
  1118.             foundCell = true;
  1119.             break;
  1120.           }
  1121.         };
  1122.         if (foundCell)
  1123.         {
  1124.           try {
  1125.             // Move selection to the cell we found
  1126.             selection.collapse(cellData.cell, 0);
  1127.             editorShell.DeleteTableColumn(-countDelta);
  1128.             colCount = newColCount;
  1129.             lastColIndex = colCount-1;
  1130.             if (curColIndex > lastColIndex)
  1131.               ChangeSelectionToFirstCell()
  1132.             else
  1133.               ChangeSelection(RESET_SELECTION);
  1134.           }
  1135.           catch(ex) {
  1136.             dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
  1137.           }
  1138.         }
  1139.       }
  1140.     }
  1141.   }
  1142.  
  1143.   // Clone all remaining attributes to pick up
  1144.   //  anything changed by Advanced Edit Dialog
  1145.   editorShell.CloneAttributes(TableElement, globalTableElement);
  1146. }
  1147.  
  1148. function ApplyCellAttributes()
  1149. {
  1150.   var selectedCell = editorShell.GetFirstSelectedCell();
  1151.   if (!selectedCell)
  1152.     return;
  1153.  
  1154.   if (gSelectedCellCount == 1)
  1155.   {
  1156.     // When only one cell is selected, simply clone entire element,
  1157.     //  thus CSS and JS from Advanced edit is copied
  1158.     editorShell.CloneAttributes(selectedCell, globalCellElement);
  1159.  
  1160.     if (dialog.CellStyleCheckbox.checked)
  1161.     {
  1162.       var currentStyleIndex = (selectedCell.nodeName.toLowerCase() == "th") ? 1 : 0;
  1163.       if (dialog.CellStyleList.selectedIndex != currentStyleIndex)
  1164.       {
  1165.         // Switch cell types
  1166.         // (replaces with new cell and copies attributes and contents)
  1167.         selectedCell = editorShell.SwitchTableCellHeaderType(selectedCell);
  1168.       }
  1169.     }
  1170.   }
  1171.   else
  1172.   {
  1173.     // Apply changes to all selected cells
  1174.     //XXX THIS DOESN'T COPY ADVANCED EDIT CHANGES!
  1175.     while (selectedCell)
  1176.     {
  1177.       ApplyAttributesToOneCell(selectedCell);
  1178.       selectedCell = editorShell.GetNextSelectedCell();
  1179.     }
  1180.   }
  1181.   CellDataChanged = false;
  1182. }
  1183.  
  1184. function ApplyAttributesToOneCell(destElement)
  1185. {
  1186.   if (dialog.CellHeightCheckbox.checked)
  1187.     CloneAttribute(destElement, globalCellElement, "height");
  1188.  
  1189.   if (dialog.CellWidthCheckbox.checked)
  1190.     CloneAttribute(destElement, globalCellElement, "width");
  1191.  
  1192.   if (dialog.CellHAlignCheckbox.checked)
  1193.   {
  1194.     CloneAttribute(destElement, globalCellElement, "align");
  1195.     CloneAttribute(destElement, globalCellElement, charStr);
  1196.   }
  1197.  
  1198.   if (dialog.CellVAlignCheckbox.checked)
  1199.     CloneAttribute(destElement, globalCellElement, "valign");
  1200.  
  1201.   if (dialog.TextWrapCheckbox.checked)
  1202.     CloneAttribute(destElement, globalCellElement, "nowrap");
  1203.  
  1204.   if (dialog.CellStyleCheckbox.checked)
  1205.   {
  1206.     var newStyleIndex = dialog.CellStyleList.selectedIndex;
  1207.     var currentStyleIndex = (destElement.nodeName.toLowerCase() == "th") ? 1 : 0;
  1208.  
  1209.     if (newStyleIndex != currentStyleIndex)
  1210.     {
  1211.       // Switch cell types
  1212.       // (replaces with new cell and copies attributes and contents)
  1213.       destElement = editorShell.SwitchTableCellHeaderType(destElement);
  1214.     }
  1215.   }
  1216.  
  1217.   if (dialog.CellColorCheckbox.checked)
  1218.     CloneAttribute(destElement, globalCellElement, "bgcolor");
  1219. }
  1220.  
  1221. function SetCloseButton()
  1222. {
  1223.   // Change text on "Cancel" button after Apply is used
  1224.   if (!ApplyUsed)
  1225.   {
  1226.     document.getElementById("cancel").setAttribute("label",GetString("Close"));
  1227.     ApplyUsed = true;
  1228.   }
  1229. }
  1230.  
  1231. function onApply()
  1232. {
  1233.   Apply();
  1234.   return false; // don't close window
  1235. }
  1236.  
  1237. function Apply()
  1238. {
  1239.   if (ValidateData())
  1240.   {
  1241.     editorShell.BeginBatchChanges();
  1242.  
  1243.     ApplyTableAttributes();
  1244.  
  1245.     // We may have just a table, so check for cell element
  1246.     if (globalCellElement)
  1247.       ApplyCellAttributes();
  1248.  
  1249.     editorShell.EndBatchChanges();
  1250.  
  1251.     SetCloseButton();
  1252.     return true;
  1253.   }
  1254.   return false;
  1255. }
  1256.  
  1257. function doHelpButton()
  1258. {
  1259.   openHelp("chrome://help/content/help.xul?table_properties");
  1260. }
  1261.  
  1262. function onOK()
  1263. {
  1264.   // Do same as Apply and close window if ValidateData succeeded
  1265.   var retVal = Apply();
  1266.   if (retVal)
  1267.     SaveWindowLocation();
  1268.  
  1269.   return retVal;
  1270. }
  1271.