Revision control
Copy as Markdown
Other Tools
/* 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
/* import-globals-from ../../composer/content/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:
// 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(
"_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(textboxID, checkboxID) {
// Filter input for just integers
forceInteger(textboxID);
// 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() {
var rangeObj = { value: null };
var selectedCell;
try {
selectedCell = gActiveEditor.getFirstSelectedCell(rangeObj);
} catch (e) {}
if (!selectedCell) {
return;
}
if (gSelectedCellCount == 1) {
// When only one cell is selected, simply clone entire element,
// thus CSS and JS from Advanced edit is copied
try {
gActiveEditor.cloneAttributes(selectedCell, globalCellElement);
} catch (e) {}
if (gDialog.CellStyleCheckbox.checked) {
var currentStyleIndex =
selectedCell.nodeName.toLowerCase() == "th" ? 1 : 0;
if (gDialog.CellStyleList.selectedIndex != currentStyleIndex) {
// Switch cell types
// (replaces with new cell and copies attributes and contents)
try {
selectedCell = gActiveEditor.switchTableCellHeaderType(selectedCell);
} catch (e) {}
}
}
} else {
// Apply changes to all selected cells
// XXX THIS DOESN'T COPY ADVANCED EDIT CHANGES!
try {
while (selectedCell) {
ApplyAttributesToOneCell(selectedCell);
selectedCell = gActiveEditor.getNextSelectedCell(rangeObj);
}
} catch (e) {}
}
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.documentElement.setAttribute(
"buttonlabelcancel",
document.documentElement.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();
}
}