From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../compose/content/dialogs/EdTableProps.js | 1426 ++++++++++++++++++++ 1 file changed, 1426 insertions(+) create mode 100644 comm/mail/components/compose/content/dialogs/EdTableProps.js (limited to 'comm/mail/components/compose/content/dialogs/EdTableProps.js') 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(); + } +} -- cgit v1.2.3