summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/compose/content/dialogs/EdTableProps.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/compose/content/dialogs/EdTableProps.js')
-rw-r--r--comm/mail/components/compose/content/dialogs/EdTableProps.js1426
1 files changed, 1426 insertions, 0 deletions
diff --git a/comm/mail/components/compose/content/dialogs/EdTableProps.js b/comm/mail/components/compose/content/dialogs/EdTableProps.js
new file mode 100644
index 0000000000..fd4ab40f3a
--- /dev/null
+++ b/comm/mail/components/compose/content/dialogs/EdTableProps.js
@@ -0,0 +1,1426 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Cancel() is in EdDialogCommon.js
+
+var gTableElement;
+var gCellElement;
+var gTableCaptionElement;
+var globalCellElement;
+var globalTableElement;
+var gValidateTab;
+const defHAlign = "left";
+const centerStr = "center"; // Index=1
+const rightStr = "right"; // 2
+const justifyStr = "justify"; // 3
+const charStr = "char"; // 4
+const defVAlign = "middle";
+const topStr = "top";
+const bottomStr = "bottom";
+const bgcolor = "bgcolor";
+var gTableColor;
+var gCellColor;
+
+const cssBackgroundColorStr = "background-color";
+
+var gRowCount = 1;
+var gColCount = 1;
+var gLastRowIndex;
+var gLastColIndex;
+var gNewRowCount;
+var gNewColCount;
+var gCurRowIndex;
+var gCurColIndex;
+var gCurColSpan;
+var gSelectedCellsType = 1;
+const SELECT_CELL = 1;
+const SELECT_ROW = 2;
+const SELECT_COLUMN = 3;
+const RESET_SELECTION = 0;
+var gCellData = {
+ value: null,
+ startRowIndex: 0,
+ startColIndex: 0,
+ rowSpan: 0,
+ colSpan: 0,
+ actualRowSpan: 0,
+ actualColSpan: 0,
+ isSelected: false,
+};
+var gAdvancedEditUsed;
+var gAlignWasChar = false;
+
+/*
+From C++:
+ 0 TABLESELECTION_TABLE
+ 1 TABLESELECTION_CELL There are 1 or more cells selected
+ but complete rows or columns are not selected
+ 2 TABLESELECTION_ROW All cells are in 1 or more rows
+ and in each row, all cells selected
+ Note: This is the value if all rows (thus all cells) are selected
+ 3 TABLESELECTION_COLUMN All cells are in 1 or more columns
+*/
+
+var gSelectedCellCount = 0;
+var gApplyUsed = false;
+var gSelection;
+var gCellDataChanged = false;
+var gCanDelete = false;
+var gUseCSS = true;
+var gActiveEditor;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogextra1", Apply);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ gActiveEditor = GetCurrentTableEditor();
+ if (!gActiveEditor) {
+ window.close();
+ return;
+ }
+
+ try {
+ gSelection = gActiveEditor.selection;
+ } catch (e) {}
+ if (!gSelection) {
+ return;
+ }
+
+ // Get dialog widgets - Table Panel
+ gDialog.TableRowsInput = document.getElementById("TableRowsInput");
+ gDialog.TableColumnsInput = document.getElementById("TableColumnsInput");
+ gDialog.TableWidthInput = document.getElementById("TableWidthInput");
+ gDialog.TableWidthUnits = document.getElementById("TableWidthUnits");
+ gDialog.TableHeightInput = document.getElementById("TableHeightInput");
+ gDialog.TableHeightUnits = document.getElementById("TableHeightUnits");
+ try {
+ if (
+ !Services.prefs.getBoolPref("editor.use_css") ||
+ gActiveEditor.flags & 1
+ ) {
+ gUseCSS = false;
+ var tableHeightLabel = document.getElementById("TableHeightLabel");
+ tableHeightLabel.remove();
+ gDialog.TableHeightInput.remove();
+ gDialog.TableHeightUnits.remove();
+ }
+ } catch (e) {}
+ gDialog.BorderWidthInput = document.getElementById("BorderWidthInput");
+ gDialog.SpacingInput = document.getElementById("SpacingInput");
+ gDialog.PaddingInput = document.getElementById("PaddingInput");
+ gDialog.TableAlignList = document.getElementById("TableAlignList");
+ gDialog.TableCaptionList = document.getElementById("TableCaptionList");
+ gDialog.TableInheritColor = document.getElementById("TableInheritColor");
+ gDialog.TabBox = document.getElementById("TabBox");
+
+ // Cell Panel
+ gDialog.SelectionList = document.getElementById("SelectionList");
+ gDialog.PreviousButton = document.getElementById("PreviousButton");
+ gDialog.NextButton = document.getElementById("NextButton");
+ // Currently, we always apply changes and load new attributes when changing selection
+ // (Let's keep this for possible future use)
+ // gDialog.ApplyBeforeMove = document.getElementById("ApplyBeforeMove");
+ // gDialog.KeepCurrentData = document.getElementById("KeepCurrentData");
+
+ gDialog.CellHeightInput = document.getElementById("CellHeightInput");
+ gDialog.CellHeightUnits = document.getElementById("CellHeightUnits");
+ gDialog.CellWidthInput = document.getElementById("CellWidthInput");
+ gDialog.CellWidthUnits = document.getElementById("CellWidthUnits");
+ gDialog.CellHAlignList = document.getElementById("CellHAlignList");
+ gDialog.CellVAlignList = document.getElementById("CellVAlignList");
+ gDialog.CellInheritColor = document.getElementById("CellInheritColor");
+ gDialog.CellStyleList = document.getElementById("CellStyleList");
+ gDialog.TextWrapList = document.getElementById("TextWrapList");
+
+ // In cell panel, user must tell us which attributes to apply via checkboxes,
+ // else we would apply values from one cell to ALL in selection
+ // and that's probably not what they expect!
+ gDialog.CellHeightCheckbox = document.getElementById("CellHeightCheckbox");
+ gDialog.CellWidthCheckbox = document.getElementById("CellWidthCheckbox");
+ gDialog.CellHAlignCheckbox = document.getElementById("CellHAlignCheckbox");
+ gDialog.CellVAlignCheckbox = document.getElementById("CellVAlignCheckbox");
+ gDialog.CellStyleCheckbox = document.getElementById("CellStyleCheckbox");
+ gDialog.TextWrapCheckbox = document.getElementById("TextWrapCheckbox");
+ gDialog.CellColorCheckbox = document.getElementById("CellColorCheckbox");
+ gDialog.TableTab = document.getElementById("TableTab");
+ gDialog.CellTab = document.getElementById("CellTab");
+ gDialog.AdvancedEditCell = document.getElementById("AdvancedEditButton2");
+ // Save "normal" tooltip message for Advanced Edit button
+ gDialog.AdvancedEditCellToolTipText =
+ gDialog.AdvancedEditCell.getAttribute("tooltiptext");
+
+ try {
+ gTableElement = gActiveEditor.getElementOrParentByTagName("table", null);
+ } catch (e) {}
+ if (!gTableElement) {
+ dump("Failed to get table element!\n");
+ window.close();
+ return;
+ }
+ globalTableElement = gTableElement.cloneNode(false);
+
+ var tagNameObj = { value: "" };
+ var countObj = { value: 0 };
+ var tableOrCellElement;
+ try {
+ tableOrCellElement = gActiveEditor.getSelectedOrParentTableElement(
+ tagNameObj,
+ countObj
+ );
+ } catch (e) {}
+
+ if (tagNameObj.value == "td") {
+ // We are in a cell
+ gSelectedCellCount = countObj.value;
+ gCellElement = tableOrCellElement;
+ globalCellElement = gCellElement.cloneNode(false);
+
+ // Tells us whether cell, row, or column is selected
+ try {
+ gSelectedCellsType = gActiveEditor.getSelectedCellsType(gTableElement);
+ } catch (e) {}
+
+ // Ignore types except Cell, Row, and Column
+ if (
+ gSelectedCellsType < SELECT_CELL ||
+ gSelectedCellsType > SELECT_COLUMN
+ ) {
+ gSelectedCellsType = SELECT_CELL;
+ }
+
+ // Be sure at least 1 cell is selected.
+ // (If the count is 0, then we were inside the cell.)
+ if (gSelectedCellCount == 0) {
+ DoCellSelection();
+ }
+
+ // Get location in the cell map
+ var rowIndexObj = { value: 0 };
+ var colIndexObj = { value: 0 };
+ try {
+ gActiveEditor.getCellIndexes(gCellElement, rowIndexObj, colIndexObj);
+ } catch (e) {}
+ gCurRowIndex = rowIndexObj.value;
+ gCurColIndex = colIndexObj.value;
+
+ // We save the current colspan to quickly
+ // move selection from from cell to cell
+ if (GetCellData(gCurRowIndex, gCurColIndex)) {
+ gCurColSpan = gCellData.colSpan;
+ }
+
+ // Starting TabPanel name is passed in
+ if (window.arguments[1] == "CellPanel") {
+ gDialog.TabBox.selectedTab = gDialog.CellTab;
+ }
+ }
+
+ if (gDialog.TabBox.selectedTab == gDialog.TableTab) {
+ // We may call this with table selected, but no cell,
+ // so disable the Cell Properties tab
+ if (!gCellElement) {
+ // XXX: Disabling of tabs is currently broken, so for
+ // now we'll just remove the tab completely.
+ // gDialog.CellTab.disabled = true;
+ gDialog.CellTab.remove();
+ }
+ }
+
+ // Note: we must use gTableElement, not globalTableElement for these,
+ // thus we should not put this in InitDialog.
+ // Instead, monitor desired counts with separate globals
+ var rowCountObj = { value: 0 };
+ var colCountObj = { value: 0 };
+ try {
+ gActiveEditor.getTableSize(gTableElement, rowCountObj, colCountObj);
+ } catch (e) {}
+
+ gRowCount = rowCountObj.value;
+ gLastRowIndex = gRowCount - 1;
+ gColCount = colCountObj.value;
+ gLastColIndex = gColCount - 1;
+
+ // Set appropriate icons and enable state for the Previous/Next buttons
+ SetSelectionButtons();
+
+ // If only one cell in table, disable change-selection widgets
+ if (gRowCount == 1 && gColCount == 1) {
+ gDialog.SelectionList.setAttribute("disabled", "true");
+ }
+
+ // User can change these via textboxes
+ gNewRowCount = gRowCount;
+ gNewColCount = gColCount;
+
+ // This flag is used to control whether set check state
+ // on "set attribute" checkboxes
+ // (Advanced Edit dialog use calls InitDialog when done)
+ gAdvancedEditUsed = false;
+ InitDialog();
+ gAdvancedEditUsed = true;
+
+ // If first initializing, we really aren't changing anything
+ gCellDataChanged = false;
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ // Get Table attributes
+ gDialog.TableRowsInput.value = gRowCount;
+ gDialog.TableColumnsInput.value = gColCount;
+ gDialog.TableWidthInput.value = InitPixelOrPercentMenulist(
+ globalTableElement,
+ gTableElement,
+ "width",
+ "TableWidthUnits",
+ gPercent
+ );
+ if (gUseCSS) {
+ gDialog.TableHeightInput.value = InitPixelOrPercentMenulist(
+ globalTableElement,
+ gTableElement,
+ "height",
+ "TableHeightUnits",
+ gPercent
+ );
+ }
+ gDialog.BorderWidthInput.value = globalTableElement.border;
+ gDialog.SpacingInput.value = globalTableElement.cellSpacing;
+ gDialog.PaddingInput.value = globalTableElement.cellPadding;
+
+ var marginLeft = GetHTMLOrCSSStyleValue(
+ globalTableElement,
+ "align",
+ "margin-left"
+ );
+ var marginRight = GetHTMLOrCSSStyleValue(
+ globalTableElement,
+ "align",
+ "margin-right"
+ );
+ var halign = marginLeft.toLowerCase() + " " + marginRight.toLowerCase();
+ if (halign == "center center" || halign == "auto auto") {
+ gDialog.TableAlignList.value = "center";
+ } else if (halign == "right right" || halign == "auto 0px") {
+ gDialog.TableAlignList.value = "right";
+ } else {
+ // Default is left.
+ gDialog.TableAlignList.value = "left";
+ }
+
+ // Be sure to get caption from table in doc, not the copied "globalTableElement"
+ gTableCaptionElement = gTableElement.caption;
+ if (gTableCaptionElement) {
+ var align = GetHTMLOrCSSStyleValue(
+ gTableCaptionElement,
+ "align",
+ "caption-side"
+ );
+ if (align != "bottom" && align != "left" && align != "right") {
+ align = "top";
+ }
+ gDialog.TableCaptionList.value = align;
+ }
+
+ gTableColor = GetHTMLOrCSSStyleValue(
+ globalTableElement,
+ bgcolor,
+ cssBackgroundColorStr
+ );
+ gTableColor = ConvertRGBColorIntoHEXColor(gTableColor);
+ SetColor("tableBackgroundCW", gTableColor);
+
+ InitCellPanel();
+}
+
+function InitCellPanel() {
+ // Get cell attributes
+ if (globalCellElement) {
+ // This assumes order of items is Cell, Row, Column
+ gDialog.SelectionList.value = gSelectedCellsType;
+
+ var previousValue = gDialog.CellHeightInput.value;
+ gDialog.CellHeightInput.value = InitPixelOrPercentMenulist(
+ globalCellElement,
+ gCellElement,
+ "height",
+ "CellHeightUnits",
+ gPixel
+ );
+ gDialog.CellHeightCheckbox.checked =
+ gAdvancedEditUsed && previousValue != gDialog.CellHeightInput.value;
+
+ previousValue = gDialog.CellWidthInput.value;
+ gDialog.CellWidthInput.value = InitPixelOrPercentMenulist(
+ globalCellElement,
+ gCellElement,
+ "width",
+ "CellWidthUnits",
+ gPixel
+ );
+ gDialog.CellWidthCheckbox.checked =
+ gAdvancedEditUsed && previousValue != gDialog.CellWidthInput.value;
+
+ var previousIndex = gDialog.CellVAlignList.selectedIndex;
+ var valign = GetHTMLOrCSSStyleValue(
+ globalCellElement,
+ "valign",
+ "vertical-align"
+ ).toLowerCase();
+ if (valign == topStr || valign == bottomStr) {
+ gDialog.CellVAlignList.value = valign;
+ } else {
+ // Default is middle.
+ gDialog.CellVAlignList.value = defVAlign;
+ }
+
+ gDialog.CellVAlignCheckbox.checked =
+ gAdvancedEditUsed &&
+ previousIndex != gDialog.CellVAlignList.selectedIndex;
+
+ previousIndex = gDialog.CellHAlignList.selectedIndex;
+
+ gAlignWasChar = false;
+
+ var halign = GetHTMLOrCSSStyleValue(
+ globalCellElement,
+ "align",
+ "text-align"
+ ).toLowerCase();
+ switch (halign) {
+ case centerStr:
+ case rightStr:
+ case justifyStr:
+ gDialog.CellHAlignList.value = halign;
+ break;
+ case charStr:
+ // We don't support UI for this because layout doesn't work: bug 2212.
+ // Remember that's what they had so we don't change it
+ // unless they change the alignment by using the menulist
+ gAlignWasChar = true;
+ // Fall through to use show default alignment in menu
+ default:
+ // Default depends on cell type (TH is "center", TD is "left")
+ gDialog.CellHAlignList.value =
+ globalCellElement.nodeName.toLowerCase() == "th" ? "center" : "left";
+ break;
+ }
+
+ gDialog.CellHAlignCheckbox.checked =
+ gAdvancedEditUsed &&
+ previousIndex != gDialog.CellHAlignList.selectedIndex;
+
+ previousIndex = gDialog.CellStyleList.selectedIndex;
+ gDialog.CellStyleList.value = globalCellElement.nodeName.toLowerCase();
+ gDialog.CellStyleCheckbox.checked =
+ gAdvancedEditUsed && previousIndex != gDialog.CellStyleList.selectedIndex;
+
+ previousIndex = gDialog.TextWrapList.selectedIndex;
+ if (
+ GetHTMLOrCSSStyleValue(globalCellElement, "nowrap", "white-space") ==
+ "nowrap"
+ ) {
+ gDialog.TextWrapList.value = "nowrap";
+ } else {
+ gDialog.TextWrapList.value = "wrap";
+ }
+ gDialog.TextWrapCheckbox.checked =
+ gAdvancedEditUsed && previousIndex != gDialog.TextWrapList.selectedIndex;
+
+ previousValue = gCellColor;
+ gCellColor = GetHTMLOrCSSStyleValue(
+ globalCellElement,
+ bgcolor,
+ cssBackgroundColorStr
+ );
+ gCellColor = ConvertRGBColorIntoHEXColor(gCellColor);
+ SetColor("cellBackgroundCW", gCellColor);
+ gDialog.CellColorCheckbox.checked =
+ gAdvancedEditUsed && previousValue != gCellColor;
+
+ // We want to set this true in case changes came
+ // from Advanced Edit dialog session (must assume something changed)
+ gCellDataChanged = true;
+ }
+}
+
+function GetCellData(rowIndex, colIndex) {
+ // Get actual rowspan and colspan
+ var startRowIndexObj = { value: 0 };
+ var startColIndexObj = { value: 0 };
+ var rowSpanObj = { value: 0 };
+ var colSpanObj = { value: 0 };
+ var actualRowSpanObj = { value: 0 };
+ var actualColSpanObj = { value: 0 };
+ var isSelectedObj = { value: false };
+
+ try {
+ gActiveEditor.getCellDataAt(
+ gTableElement,
+ rowIndex,
+ colIndex,
+ gCellData,
+ startRowIndexObj,
+ startColIndexObj,
+ rowSpanObj,
+ colSpanObj,
+ actualRowSpanObj,
+ actualColSpanObj,
+ isSelectedObj
+ );
+ // We didn't find a cell
+ if (!gCellData.value) {
+ return false;
+ }
+ } catch (ex) {
+ return false;
+ }
+
+ gCellData.startRowIndex = startRowIndexObj.value;
+ gCellData.startColIndex = startColIndexObj.value;
+ gCellData.rowSpan = rowSpanObj.value;
+ gCellData.colSpan = colSpanObj.value;
+ gCellData.actualRowSpan = actualRowSpanObj.value;
+ gCellData.actualColSpan = actualColSpanObj.value;
+ gCellData.isSelected = isSelectedObj.value;
+ return true;
+}
+
+function SelectCellHAlign() {
+ SetCheckbox("CellHAlignCheckbox");
+ // Once user changes the alignment,
+ // we lose their original "CharAt" alignment"
+ gAlignWasChar = false;
+}
+
+function GetColorAndUpdate(ColorWellID) {
+ var colorWell = document.getElementById(ColorWellID);
+ if (!colorWell) {
+ return;
+ }
+
+ var colorObj = {
+ Type: "",
+ TableColor: 0,
+ CellColor: 0,
+ NoDefault: false,
+ Cancel: false,
+ BackgroundColor: 0,
+ };
+
+ switch (ColorWellID) {
+ case "tableBackgroundCW":
+ colorObj.Type = "Table";
+ colorObj.TableColor = gTableColor;
+ break;
+ case "cellBackgroundCW":
+ colorObj.Type = "Cell";
+ colorObj.CellColor = gCellColor;
+ break;
+ }
+ window.openDialog(
+ "chrome://messenger/content/messengercompose/EdColorPicker.xhtml",
+ "_blank",
+ "chrome,close,titlebar,modal",
+ "",
+ colorObj
+ );
+
+ // User canceled the dialog
+ if (colorObj.Cancel) {
+ return;
+ }
+
+ switch (ColorWellID) {
+ case "tableBackgroundCW":
+ gTableColor = colorObj.BackgroundColor;
+ SetColor(ColorWellID, gTableColor);
+ break;
+ case "cellBackgroundCW":
+ gCellColor = colorObj.BackgroundColor;
+ SetColor(ColorWellID, gCellColor);
+ SetCheckbox("CellColorCheckbox");
+ break;
+ }
+}
+
+function SetColor(ColorWellID, color) {
+ // Save the color
+ if (ColorWellID == "cellBackgroundCW") {
+ if (color) {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(
+ globalCellElement,
+ bgcolor,
+ color,
+ true
+ );
+ } catch (e) {}
+ gDialog.CellInheritColor.collapsed = true;
+ } else {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(
+ globalCellElement,
+ bgcolor,
+ true
+ );
+ } catch (e) {}
+ // Reveal addition message explaining "default" color
+ gDialog.CellInheritColor.collapsed = false;
+ }
+ } else {
+ if (color) {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(
+ globalTableElement,
+ bgcolor,
+ color,
+ true
+ );
+ } catch (e) {}
+ gDialog.TableInheritColor.collapsed = true;
+ } else {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(
+ globalTableElement,
+ bgcolor,
+ true
+ );
+ } catch (e) {}
+ gDialog.TableInheritColor.collapsed = false;
+ }
+ SetCheckbox("CellColorCheckbox");
+ }
+
+ setColorWell(ColorWellID, color);
+}
+
+function ChangeSelectionToFirstCell() {
+ if (!GetCellData(0, 0)) {
+ dump("Can't find first cell in table!\n");
+ return;
+ }
+ gCellElement = gCellData.value;
+ globalCellElement = gCellElement;
+
+ gCurRowIndex = 0;
+ gCurColIndex = 0;
+ ChangeSelection(RESET_SELECTION);
+}
+
+function ChangeSelection(newType) {
+ newType = Number(newType);
+
+ if (gSelectedCellsType == newType) {
+ return;
+ }
+
+ if (newType == RESET_SELECTION) {
+ // Restore selection to existing focus cell
+ gSelection.collapse(gCellElement, 0);
+ } else {
+ gSelectedCellsType = newType;
+ }
+
+ // Keep the same focus gCellElement, just change the type
+ DoCellSelection();
+ SetSelectionButtons();
+
+ // Note: globalCellElement should still be a clone of gCellElement
+}
+
+function MoveSelection(forward) {
+ var newRowIndex = gCurRowIndex;
+ var newColIndex = gCurColIndex;
+ var inRow = false;
+
+ if (gSelectedCellsType == SELECT_ROW) {
+ newRowIndex += forward ? 1 : -1;
+
+ // Wrap around if before first or after last row
+ if (newRowIndex < 0) {
+ newRowIndex = gLastRowIndex;
+ } else if (newRowIndex > gLastRowIndex) {
+ newRowIndex = 0;
+ }
+ inRow = true;
+
+ // Use first cell in row for focus cell
+ newColIndex = 0;
+ } else {
+ // Cell or column:
+ if (!forward) {
+ newColIndex--;
+ }
+
+ if (gSelectedCellsType == SELECT_CELL) {
+ // Skip to next cell
+ if (forward) {
+ newColIndex += gCurColSpan;
+ }
+ } else {
+ // SELECT_COLUMN
+ // Use first cell in column for focus cell
+ newRowIndex = 0;
+
+ // Don't skip by colspan,
+ // but find first cell in next cellmap column
+ if (forward) {
+ newColIndex++;
+ }
+ }
+
+ if (newColIndex < 0) {
+ // Request is before the first cell in column
+
+ // Wrap to last cell in column
+ newColIndex = gLastColIndex;
+
+ if (gSelectedCellsType == SELECT_CELL) {
+ // If moving by cell, also wrap to previous...
+ if (newRowIndex > 0) {
+ newRowIndex -= 1;
+ } else {
+ // ...or the last row.
+ newRowIndex = gLastRowIndex;
+ }
+
+ inRow = true;
+ }
+ } else if (newColIndex > gLastColIndex) {
+ // Request is after the last cell in column
+
+ // Wrap to first cell in column
+ newColIndex = 0;
+
+ if (gSelectedCellsType == SELECT_CELL) {
+ // If moving by cell, also wrap to next...
+ if (newRowIndex < gLastRowIndex) {
+ newRowIndex++;
+ } else {
+ // ...or the first row.
+ newRowIndex = 0;
+ }
+
+ inRow = true;
+ }
+ }
+ }
+
+ // Get the cell at the new location
+ do {
+ if (!GetCellData(newRowIndex, newColIndex)) {
+ dump("MoveSelection: CELL NOT FOUND\n");
+ return;
+ }
+ if (inRow) {
+ if (gCellData.startRowIndex == newRowIndex) {
+ break;
+ } else {
+ // Cell spans from a row above, look for the next cell in row.
+ newRowIndex += gCellData.actualRowSpan;
+ }
+ } else if (gCellData.startColIndex == newColIndex) {
+ break;
+ } else {
+ // Cell spans from a Col above, look for the next cell in column
+ newColIndex += gCellData.actualColSpan;
+ }
+ } while (true);
+
+ // Save data for current selection before changing
+ if (gCellDataChanged) {
+ // && gDialog.ApplyBeforeMove.checked)
+ if (!ValidateCellData()) {
+ return;
+ }
+
+ gActiveEditor.beginTransaction();
+ // Apply changes to all selected cells
+ ApplyCellAttributes();
+ gActiveEditor.endTransaction();
+
+ SetCloseButton();
+ }
+
+ // Set cell and other data for new selection
+ gCellElement = gCellData.value;
+
+ // Save globals for new current cell
+ gCurRowIndex = gCellData.startRowIndex;
+ gCurColIndex = gCellData.startColIndex;
+ gCurColSpan = gCellData.actualColSpan;
+
+ // Copy for new global cell
+ globalCellElement = gCellElement.cloneNode(false);
+
+ // Change the selection
+ DoCellSelection();
+
+ // Scroll page so new selection is visible
+ // Using SELECTION_ANCHOR_REGION makes the upper-left corner of first selected cell
+ // the point to bring into view.
+ try {
+ var selectionController = gActiveEditor.selectionController;
+ selectionController.scrollSelectionIntoView(
+ selectionController.SELECTION_NORMAL,
+ selectionController.SELECTION_ANCHOR_REGION,
+ true
+ );
+ } catch (e) {}
+
+ // Reinitialize dialog using new cell
+ // if (!gDialog.KeepCurrentData.checked)
+ // Setting this false unchecks all "set attributes" checkboxes
+ gAdvancedEditUsed = false;
+ InitCellPanel();
+ gAdvancedEditUsed = true;
+}
+
+function DoCellSelection() {
+ // Collapse selection into to the focus cell
+ // so editor uses that as start cell
+ gSelection.collapse(gCellElement, 0);
+
+ var tagNameObj = { value: "" };
+ var countObj = { value: 0 };
+ try {
+ switch (gSelectedCellsType) {
+ case SELECT_CELL:
+ gActiveEditor.selectTableCell();
+ break;
+ case SELECT_ROW:
+ gActiveEditor.selectTableRow();
+ break;
+ default:
+ gActiveEditor.selectTableColumn();
+ break;
+ }
+ // Get number of cells selected
+ gActiveEditor.getSelectedOrParentTableElement(tagNameObj, countObj);
+ } catch (e) {}
+
+ if (tagNameObj.value == "td") {
+ gSelectedCellCount = countObj.value;
+ } else {
+ gSelectedCellCount = 0;
+ }
+
+ // Currently, we can only allow advanced editing on ONE cell element at a time
+ // else we ignore CSS, JS, and HTML attributes not already in dialog
+ SetElementEnabled(gDialog.AdvancedEditCell, gSelectedCellCount == 1);
+
+ gDialog.AdvancedEditCell.setAttribute(
+ "tooltiptext",
+ gSelectedCellCount > 1
+ ? GetString("AdvancedEditForCellMsg")
+ : gDialog.AdvancedEditCellToolTipText
+ );
+}
+
+function SetSelectionButtons() {
+ if (gSelectedCellsType == SELECT_ROW) {
+ // Trigger CSS to set images of up and down arrows
+ gDialog.PreviousButton.setAttribute("type", "row");
+ gDialog.NextButton.setAttribute("type", "row");
+ } else {
+ // or images of left and right arrows
+ gDialog.PreviousButton.setAttribute("type", "col");
+ gDialog.NextButton.setAttribute("type", "col");
+ }
+ DisableSelectionButtons(
+ (gSelectedCellsType == SELECT_ROW && gRowCount == 1) ||
+ (gSelectedCellsType == SELECT_COLUMN && gColCount == 1) ||
+ (gRowCount == 1 && gColCount == 1)
+ );
+}
+
+function DisableSelectionButtons(disable) {
+ gDialog.PreviousButton.setAttribute("disabled", disable ? "true" : "false");
+ gDialog.NextButton.setAttribute("disabled", disable ? "true" : "false");
+}
+
+function SwitchToValidatePanel() {
+ if (gDialog.TabBox.selectedTab != gValidateTab) {
+ gDialog.TabBox.selectedTab = gValidateTab;
+ }
+}
+
+function SetAlign(listID, defaultValue, element, attName) {
+ var value = document.getElementById(listID).value;
+ if (value == defaultValue) {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(element, attName, true);
+ } catch (e) {}
+ } else {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(element, attName, value, true);
+ } catch (e) {}
+ }
+}
+
+function ValidateTableData() {
+ gValidateTab = gDialog.TableTab;
+ gNewRowCount = Number(
+ ValidateNumber(gDialog.TableRowsInput, null, 1, gMaxRows, null, true, true)
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ gNewColCount = Number(
+ ValidateNumber(
+ gDialog.TableColumnsInput,
+ null,
+ 1,
+ gMaxColumns,
+ null,
+ true,
+ true
+ )
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ // If user is deleting any cells, get confirmation
+ // (This is a global to the dialog and we ask only once per dialog session)
+ if (!gCanDelete && (gNewRowCount < gRowCount || gNewColCount < gColCount)) {
+ if (
+ ConfirmWithTitle(
+ GetString("DeleteTableTitle"),
+ GetString("DeleteTableMsg"),
+ GetString("DeleteCells")
+ )
+ ) {
+ gCanDelete = true;
+ } else {
+ SetTextboxFocus(
+ gNewRowCount < gRowCount
+ ? gDialog.TableRowsInput
+ : gDialog.TableColumnsInput
+ );
+ return false;
+ }
+ }
+
+ ValidateNumber(
+ gDialog.TableWidthInput,
+ gDialog.TableWidthUnits,
+ 1,
+ gMaxTableSize,
+ globalTableElement,
+ "width"
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ if (gUseCSS) {
+ ValidateNumber(
+ gDialog.TableHeightInput,
+ gDialog.TableHeightUnits,
+ 1,
+ gMaxTableSize,
+ globalTableElement,
+ "height"
+ );
+ if (gValidationError) {
+ return false;
+ }
+ }
+
+ ValidateNumber(
+ gDialog.BorderWidthInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalTableElement,
+ "border"
+ );
+ // TODO: Deal with "BORDER" without value issue
+ if (gValidationError) {
+ return false;
+ }
+
+ ValidateNumber(
+ gDialog.SpacingInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalTableElement,
+ "cellspacing"
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ ValidateNumber(
+ gDialog.PaddingInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalTableElement,
+ "cellpadding"
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ SetAlign("TableAlignList", defHAlign, globalTableElement, "align");
+
+ // Color is set on globalCellElement immediately
+ return true;
+}
+
+function ValidateCellData() {
+ gValidateTab = gDialog.CellTab;
+
+ if (gDialog.CellHeightCheckbox.checked) {
+ ValidateNumber(
+ gDialog.CellHeightInput,
+ gDialog.CellHeightUnits,
+ 1,
+ gMaxTableSize,
+ globalCellElement,
+ "height"
+ );
+ if (gValidationError) {
+ return false;
+ }
+ }
+
+ if (gDialog.CellWidthCheckbox.checked) {
+ ValidateNumber(
+ gDialog.CellWidthInput,
+ gDialog.CellWidthUnits,
+ 1,
+ gMaxTableSize,
+ globalCellElement,
+ "width"
+ );
+ if (gValidationError) {
+ return false;
+ }
+ }
+
+ if (gDialog.CellHAlignCheckbox.checked) {
+ var hAlign = gDialog.CellHAlignList.value;
+
+ // Horizontal alignment is complicated by "char" type
+ // We don't change current values if user didn't edit alignment
+ if (!gAlignWasChar) {
+ globalCellElement.removeAttribute(charStr);
+
+ // Always set "align" attribute,
+ // so the default "left" is effective in a cell
+ // when parent row has align set.
+ globalCellElement.setAttribute("align", hAlign);
+ }
+ }
+
+ if (gDialog.CellVAlignCheckbox.checked) {
+ // Always set valign (no default in 2nd param) so
+ // the default "middle" is effective in a cell
+ // when parent row has valign set.
+ SetAlign("CellVAlignList", "", globalCellElement, "valign");
+ }
+
+ if (gDialog.TextWrapCheckbox.checked) {
+ if (gDialog.TextWrapList.value == "nowrap") {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(
+ globalCellElement,
+ "nowrap",
+ "nowrap",
+ true
+ );
+ } catch (e) {}
+ } else {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(
+ globalCellElement,
+ "nowrap",
+ true
+ );
+ } catch (e) {}
+ }
+ }
+
+ return true;
+}
+
+function ValidateData() {
+ var result;
+
+ // Validate current panel first
+ if (gDialog.TabBox.selectedTab == gDialog.TableTab) {
+ result = ValidateTableData();
+ if (result) {
+ result = ValidateCellData();
+ }
+ } else {
+ result = ValidateCellData();
+ if (result) {
+ result = ValidateTableData();
+ }
+ }
+ if (!result) {
+ return false;
+ }
+
+ // Set global element for AdvancedEdit
+ if (gDialog.TabBox.selectedTab == gDialog.TableTab) {
+ globalElement = globalTableElement;
+ } else {
+ globalElement = globalCellElement;
+ }
+
+ return true;
+}
+
+function ChangeCellTextbox(textboxID) {
+ // Filter input for just integers
+ forceInteger(textboxID);
+
+ if (gDialog.TabBox.selectedTab == gDialog.CellTab) {
+ gCellDataChanged = true;
+ }
+}
+
+// Call this when a textbox or menulist is changed
+// so the checkbox is automatically set
+function SetCheckbox(checkboxID) {
+ if (checkboxID && checkboxID.length > 0) {
+ // Set associated checkbox
+ document.getElementById(checkboxID).checked = true;
+ }
+ gCellDataChanged = true;
+}
+
+function ChangeIntTextbox(checkboxID) {
+ // Set associated checkbox
+ SetCheckbox(checkboxID);
+}
+
+function CloneAttribute(destElement, srcElement, attr) {
+ var value = srcElement.getAttribute(attr);
+ // Use editor methods since we are always
+ // modifying a table in the document and
+ // we need transaction system for undo
+ try {
+ if (!value || value.length == 0) {
+ gActiveEditor.removeAttributeOrEquivalent(destElement, attr, false);
+ } else {
+ gActiveEditor.setAttributeOrEquivalent(destElement, attr, value, false);
+ }
+ } catch (e) {}
+}
+
+/* eslint-disable complexity */
+function ApplyTableAttributes() {
+ var newAlign = gDialog.TableCaptionList.value;
+ if (!newAlign) {
+ newAlign = "";
+ }
+
+ if (gTableCaptionElement) {
+ // Get current alignment
+ var align = GetHTMLOrCSSStyleValue(
+ gTableCaptionElement,
+ "align",
+ "caption-side"
+ ).toLowerCase();
+ // This is the default
+ if (!align) {
+ align = "top";
+ }
+
+ if (newAlign == "") {
+ // Remove existing caption
+ try {
+ gActiveEditor.deleteNode(gTableCaptionElement);
+ } catch (e) {}
+ gTableCaptionElement = null;
+ } else if (newAlign != align) {
+ try {
+ if (newAlign == "top") {
+ // This is default, so don't explicitly set it
+ gActiveEditor.removeAttributeOrEquivalent(
+ gTableCaptionElement,
+ "align",
+ false
+ );
+ } else {
+ gActiveEditor.setAttributeOrEquivalent(
+ gTableCaptionElement,
+ "align",
+ newAlign,
+ false
+ );
+ }
+ } catch (e) {}
+ }
+ } else if (newAlign != "") {
+ // Create and insert a caption:
+ try {
+ gTableCaptionElement = gActiveEditor.createElementWithDefaults("caption");
+ } catch (e) {}
+ if (gTableCaptionElement) {
+ if (newAlign != "top") {
+ gTableCaptionElement.setAttribute("align", newAlign);
+ }
+
+ // Insert it into the table - caption is always inserted as first child
+ try {
+ gActiveEditor.insertNode(gTableCaptionElement, gTableElement, 0);
+ } catch (e) {}
+
+ // Put selection back where it was
+ ChangeSelection(RESET_SELECTION);
+ }
+ }
+
+ var countDelta;
+ var foundCell;
+ var i;
+
+ if (gNewRowCount != gRowCount) {
+ countDelta = gNewRowCount - gRowCount;
+ if (gNewRowCount > gRowCount) {
+ // Append new rows
+ // Find first cell in last row
+ if (GetCellData(gLastRowIndex, 0)) {
+ try {
+ // Move selection to the last cell
+ gSelection.collapse(gCellData.value, 0);
+ // Insert new rows after it
+ gActiveEditor.insertTableRow(countDelta, true);
+ gRowCount = gNewRowCount;
+ gLastRowIndex = gRowCount - 1;
+ // Put selection back where it was
+ ChangeSelection(RESET_SELECTION);
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+ }
+ }
+ } else if (gCanDelete) {
+ // Delete rows
+ // Find first cell starting in first row we delete
+ var firstDeleteRow = gRowCount + countDelta;
+ foundCell = false;
+ for (i = 0; i <= gLastColIndex; i++) {
+ if (!GetCellData(firstDeleteRow, i)) {
+ // We failed to find a cell.
+ break;
+ }
+
+ if (gCellData.startRowIndex == firstDeleteRow) {
+ foundCell = true;
+ break;
+ }
+ }
+ if (foundCell) {
+ try {
+ // Move selection to the cell we found
+ gSelection.collapse(gCellData.value, 0);
+ gActiveEditor.deleteTableRow(-countDelta);
+ gRowCount = gNewRowCount;
+ gLastRowIndex = gRowCount - 1;
+ if (gCurRowIndex > gLastRowIndex) {
+ // We are deleting our selection
+ // move it to start of table
+ ChangeSelectionToFirstCell();
+ } else {
+ // Put selection back where it was.
+ ChangeSelection(RESET_SELECTION);
+ }
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+ }
+ }
+ }
+ }
+
+ if (gNewColCount != gColCount) {
+ countDelta = gNewColCount - gColCount;
+
+ if (gNewColCount > gColCount) {
+ // Append new columns
+ // Find last cell in first column
+ if (GetCellData(0, gLastColIndex)) {
+ try {
+ // Move selection to the last cell
+ gSelection.collapse(gCellData.value, 0);
+ gActiveEditor.insertTableColumn(countDelta, true);
+ gColCount = gNewColCount;
+ gLastColIndex = gColCount - 1;
+ // Restore selection
+ ChangeSelection(RESET_SELECTION);
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST COLUMN\n");
+ }
+ }
+ } else if (gCanDelete) {
+ // Delete columns
+ var firstDeleteCol = gColCount + countDelta;
+ foundCell = false;
+ for (i = 0; i <= gLastRowIndex; i++) {
+ // Find first cell starting in first column we delete
+ if (!GetCellData(i, firstDeleteCol)) {
+ // We failed to find a cell.
+ break;
+ }
+
+ if (gCellData.startColIndex == firstDeleteCol) {
+ foundCell = true;
+ break;
+ }
+ }
+ if (foundCell) {
+ try {
+ // Move selection to the cell we found
+ gSelection.collapse(gCellData.value, 0);
+ gActiveEditor.deleteTableColumn(-countDelta);
+ gColCount = gNewColCount;
+ gLastColIndex = gColCount - 1;
+ if (gCurColIndex > gLastColIndex) {
+ ChangeSelectionToFirstCell();
+ } else {
+ ChangeSelection(RESET_SELECTION);
+ }
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+ }
+ }
+ }
+ }
+
+ // Clone all remaining attributes to pick up
+ // anything changed by Advanced Edit Dialog
+ try {
+ gActiveEditor.cloneAttributes(gTableElement, globalTableElement);
+ } catch (e) {}
+}
+/* eslint-enable complexity */
+
+function ApplyCellAttributes() {
+ let selectedCells = gActiveEditor.getSelectedCells();
+ if (selectedCells.length == 0) {
+ return;
+ }
+
+ if (selectedCells.length == 1) {
+ let cell = selectedCells[0];
+ // When only one cell is selected, simply clone entire element,
+ // thus CSS and JS from Advanced edit is copied
+
+ gActiveEditor.cloneAttributes(cell, globalCellElement);
+
+ if (gDialog.CellStyleCheckbox.checked) {
+ let currentStyleIndex = cell.nodeName.toLowerCase() == "th" ? 1 : 0;
+ if (gDialog.CellStyleList.selectedIndex != currentStyleIndex) {
+ // Switch cell types
+ // (replaces with new cell and copies attributes and contents)
+ gActiveEditor.switchTableCellHeaderType(cell);
+ }
+ }
+ } else {
+ // Apply changes to all selected cells
+ // XXX THIS DOESN'T COPY ADVANCED EDIT CHANGES!
+ for (let cell of selectedCells) {
+ ApplyAttributesToOneCell(cell);
+ }
+ }
+ gCellDataChanged = false;
+}
+
+function ApplyAttributesToOneCell(destElement) {
+ if (gDialog.CellHeightCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "height");
+ }
+
+ if (gDialog.CellWidthCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "width");
+ }
+
+ if (gDialog.CellHAlignCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "align");
+ CloneAttribute(destElement, globalCellElement, charStr);
+ }
+
+ if (gDialog.CellVAlignCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "valign");
+ }
+
+ if (gDialog.TextWrapCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "nowrap");
+ }
+
+ if (gDialog.CellStyleCheckbox.checked) {
+ var newStyleIndex = gDialog.CellStyleList.selectedIndex;
+ var currentStyleIndex = destElement.nodeName.toLowerCase() == "th" ? 1 : 0;
+
+ if (newStyleIndex != currentStyleIndex) {
+ // Switch cell types
+ // (replaces with new cell and copies attributes and contents)
+ try {
+ destElement = gActiveEditor.switchTableCellHeaderType(destElement);
+ } catch (e) {}
+ }
+ }
+
+ if (gDialog.CellColorCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "bgcolor");
+ }
+}
+
+function SetCloseButton() {
+ // Change text on "Cancel" button after Apply is used
+ if (!gApplyUsed) {
+ document
+ .querySelector("dialog")
+ .setAttribute(
+ "buttonlabelcancel",
+ document.querySelector("dialog").getAttribute("buttonlabelclose")
+ );
+ gApplyUsed = true;
+ }
+}
+
+function Apply() {
+ if (ValidateData()) {
+ gActiveEditor.beginTransaction();
+
+ ApplyTableAttributes();
+
+ // We may have just a table, so check for cell element
+ if (globalCellElement) {
+ ApplyCellAttributes();
+ }
+
+ gActiveEditor.endTransaction();
+
+ SetCloseButton();
+ return true;
+ }
+ return false;
+}
+
+function onAccept(event) {
+ // Do same as Apply and close window if ValidateData succeeded
+ var retVal = Apply();
+ if (retVal) {
+ SaveWindowLocation();
+ } else {
+ event.preventDefault();
+ }
+}