/* 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(); } }