From e6e4343f43a787b185d98d1799595d5cccb48611 Mon Sep 17 00:00:00 2001 From: "cmanske%netscape.com" Date: Sat, 5 Oct 2002 20:44:49 +0000 Subject: [PATCH] More remove editorShell from dialogs work (comments added by neil as requested). b=158881, r=cmanske, sr=alecf --- editor/ui/dialogs/content/EdFieldSetProps.js | 36 +- editor/ui/dialogs/content/EdLabelProps.js | 13 +- editor/ui/dialogs/content/EdSelectProps.js | 709 ++++++++++--------- editor/ui/dialogs/content/EdSelectProps.xul | 64 +- editor/ui/dialogs/content/EdTextAreaProps.js | 27 +- 5 files changed, 468 insertions(+), 381 deletions(-) diff --git a/editor/ui/dialogs/content/EdFieldSetProps.js b/editor/ui/dialogs/content/EdFieldSetProps.js index 2093450c61e6..3e984ea91da8 100644 --- a/editor/ui/dialogs/content/EdFieldSetProps.js +++ b/editor/ui/dialogs/content/EdFieldSetProps.js @@ -46,6 +46,7 @@ function Startup() var editor = GetCurrentEditor(); if (!editor) { + dump("Failed to get active editor!\n"); window.close(); return; } @@ -56,12 +57,15 @@ function Startup() gDialog.RemoveFieldSet = document.getElementById("RemoveFieldSet"); // Get a single selected field set element - var tagName = "fieldset"; - fieldsetElement = editor.getSelectedElement(tagName); - if (!fieldsetElement) - fieldsetElement = editor.getElementOrParentByTagName(tagName, editor.selection.anchorNode); - if (!fieldsetElement) - fieldsetElement = editor.getElementOrParentByTagName(tagName, editor.selection.focusNode); + const kTagName = "fieldset"; + try { + // Find a selected fieldset, or if one is at start or end of selection. + fieldsetElement = editor.getSelectedElement(kTagName); + if (!fieldsetElement) + fieldsetElement = editor.getElementOrParentBykTagName(kTagName, editor.selection.anchorNode); + if (!fieldsetElement) + fieldsetElement = editor.getElementOrParentBykTagName(kTagName, editor.selection.focusNode); + } catch (e) {} if (fieldsetElement) // We found an element and don't need to insert one @@ -72,8 +76,10 @@ function Startup() // We don't have an element selected, // so create one with default attributes + try { + fieldsetElement = editor.createElementWithDefaults(kTagName); + } catch (e) {} - fieldsetElement = editor.createElementWithDefaults(tagName); if (!fieldsetElement) { dump("Failed to get selected element or create a new one!\n"); @@ -175,8 +181,15 @@ function onAccept() editor.beginTransaction(); try { + editor.cloneAttributes(legendElement, globalElement); + + if (insertNew) + InsertElementAroundSelection(fieldsetElement); + if (gDialog.editText.checked) { + editor.setShouldTxnSetSelection(false); + if (gDialog.legendText.value) { if (newLegend) @@ -187,14 +200,9 @@ function onAccept() } else if (!newLegend) editor.DeleteNode(legendElement); - } - - if (insertNew) - InsertElementAroundSelection(fieldsetElement); - else - editor.selectElement(fieldsetElement); - editor.cloneAttributes(legendElement, globalElement); + editor.setShouldTxnSetSelection(true); + } } finally { editor.endTransaction(); diff --git a/editor/ui/dialogs/content/EdLabelProps.js b/editor/ui/dialogs/content/EdLabelProps.js index 96a413e4ad84..74213ddf73f2 100644 --- a/editor/ui/dialogs/content/EdLabelProps.js +++ b/editor/ui/dialogs/content/EdLabelProps.js @@ -43,6 +43,7 @@ function Startup() var editor = GetCurrentEditor(); if (!editor) { + dump("Failed to get active editor!\n"); window.close(); return; } @@ -59,8 +60,11 @@ function Startup() InitDialog(); - editor.selectElement(labelElement); - gDialog.labelText.value = GetSelectionAsText(); + try { + editor.selectElement(labelElement); + gDialog.labelText.value = GetSelectionAsText(); + } catch (e) {} + if (/ 1); + return index; } function UpdateSelectMultiple() @@ -87,69 +77,71 @@ function UpdateSelectMultiple() gDialog.selectMultiple.disabled = false; } -function createXUL(localName) -{ - return document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", localName); -} +/* wrapper objects: + * readonly attribute Node element; // DOM node (select/optgroup/option) + * readonly attribute int level; // tree depth + * readonly attribute boolean container; // can contain options + * string getCellText(string col); // tree view helper + * string cycleCell(int currentIndex); // tree view helper + * void onFocus(); // load data into deck + * void onBlur(); // save data from deck + * boolean canDestroy(boolean prompt); // NB prompt not used + * void destroy(); // post remove callback + * void moveUp(); + * boolean canMoveDown(); + * void moveDown(); + * void appendOption(newElement, currentIndex); + */ // OPTION element wrapper object -function optionObject(parent, option) +// Create a wrapper for the given element at the given level +function optionObject(option, level) { + // select an added option (when loading from document) if (option.hasAttribute("selected")) selectedOptionCount++; - this.globalIndex = globalArray.length; - globalArray[globalArray.length++] = this; - this.parentObject = parent; + this.level = level; this.element = option; - this.treeItem = createXUL("treeitem"); - this.treeRow = createXUL("treerow"); - this.treeCellText = createXUL("treecell"); - this.treeCellValue = createXUL("treecell"); - this.treeCellSelected = createXUL("treecell"); - this.treeItem.setAttribute("index", this.globalIndex); - this.treeItem.setAttribute("container", "true"); - this.treeItem.setAttribute("empty", "true"); - this.treeCellText.setAttribute("class", "treecell-indent"); - this.treeCellText.setAttribute("notwisty", "true"); - this.treeCellText.setAttribute("label", option.text); - if (option.hasAttribute("value")) - this.treeCellValue.setAttribute("label", option.value); - else - this.treeCellValue.setAttribute("label", option.text); - this.treeCellSelected.setAttribute("properties", "checked-"+option.hasAttribute("selected")); - this.treeRow.appendChild(this.treeCellText); - this.treeRow.appendChild(this.treeCellValue); - this.treeRow.appendChild(this.treeCellSelected); - this.treeItem.appendChild(this.treeRow); - parent.treeChildren.appendChild(this.treeItem); - gDialog.treeItem.setAttribute("open", "true"); } -optionObject.prototype.onSpace = function onSpace() +optionObject.prototype.container = false; + +optionObject.prototype.getCellText = function getCellText(column) +{ + if (column == "SelectSelCol") + return ""; + if (column == "SelectValCol" && this.element.hasAttribute("value")) + return this.element.getAttribute("value"); + return this.element.text; +} + +optionObject.prototype.cycleCell = function cycleCell(index) { if (this.element.hasAttribute("selected")) { - selectedOptionCount--; this.element.removeAttribute("selected"); - this.treeCellSelected.setAttribute("properties", "checked-false"); - gDialog.optionSelected.setAttribute("checked", "false"); - selectedOption = 0; + selectedOptionCount--; + selectedOption = null; } else { - if (gDialog.selectMultiple.checked || !globalArray[selectedOption].element.hasAttribute("selected")) + // Different handling for multiselect lists + if (gDialog.selectMultiple.checked || !selectedOption) selectedOptionCount++; - else + else if (selectedOption) { - globalArray[selectedOption].element.removeAttribute("selected"); - globalArray[selectedOption].treeCellSelected.setAttribute("properties", "checked-false"); + selectedOption.removeAttribute("selected"); + treeBoxObject.invalidateColumn("SelectSelCol"); + selectedOption = null; } this.element.setAttribute("selected", ""); - this.treeCellSelected.setAttribute("properties", "checked-true"); - gDialog.optionSelected.setAttribute("checked", "true"); - selectedOption = this.globalIndex; + selectedOption = this.element; + treeBoxObject.invalidateCell(index, "SelectSelCol"); } + if (currentItem == this) + // Also update the deck + gDialog.optionSelected.setAttribute("checked", this.element.hasAttribute("selected")); UpdateSelectMultiple(); }; @@ -193,87 +185,107 @@ optionObject.prototype.canDestroy = function canDestroy(prompt) optionObject.prototype.destroy = function destroy() { + // Deselect a removed option if (this.element.hasAttribute("selected")) { selectedOptionCount--; + selectedOption = null; UpdateSelectMultiple(); } - this.parentObject.removeChild(this); }; -optionObject.prototype.canMoveUp = function canMoveUp() -{ - return this.treeItem.previousSibling || this.parentObject != gDialog; -} +/* 4 cases: + * a) optgroup -> optgroup + * ... ... + * option option + * b) optgroup -> option + * option optgroup + * ... ... + * c) option + * option + * d) option + * option + */ optionObject.prototype.moveUp = function moveUp() { - if (this.treeItem.previousSibling) - GetObjectForTreeItem(this.treeItem.previousSibling).insertAfter(this); + var i; + var index = treeSelection.currentIndex; + if (itemArray[index].level < itemArray[index - 1].level + itemArray[index - 1].container) + { + // we need to repaint the tree's lines + treeBoxObject.invalidateRange(getParentIndex(index), index); + // a) option is just after an optgroup, so it becomes the last child + itemArray[index].level = 2; + treeBoxObject.view.selectionChanged(); + } else - InsertBefore(gDialog, this, this.parentObject); -} - -optionObject.prototype.insertAfter = function insertAfter(option) -{ - InsertBefore(this.parentObject, option, this); + { + // otherwise new option level is now the same as the previous item + itemArray[index].level = itemArray[index - 1].level; + // swap the option with the previous item + itemArray.splice(index, 0, itemArray.splice(--index, 1)[0]); + } + selectTreeIndex(index, true); } optionObject.prototype.canMoveDown = function canMoveDown() { - return this.treeItem.nextSibling || this.parentObject != gDialog; + // move down is not allowed on the last option if its level is 1 + return this.level > 1 || itemArray.length - treeSelection.currentIndex > 1; } optionObject.prototype.moveDown = function moveDown() { - if (this.treeItem.nextSibling) - GetObjectForTreeItem(this.treeItem.nextSibling).insertBefore(this); - else if (this.parentObject.treeItem.nextSibling) - InsertBefore(gDialog, this, GetObjectForTreeItem(this.parentObject.treeItem.nextSibling)); + var i; + var index = treeSelection.currentIndex; + if (index + 1 == itemArray.length || itemArray[index].level > itemArray[index + 1].level) + { + // we need to repaint the tree's lines + treeBoxObject.invalidateRange(getParentIndex(index), index); + // a) option is last child of an optgroup, so it moves just after + itemArray[index].level = 1; + treeBoxObject.view.selectionChanged(); + } else - AppendChild(gDialog, this); + { + // level increases if the option was preceding an optgroup + itemArray[index].level += itemArray[index + 1].container; + // swap the option with the next item + itemArray.splice(index, 0, itemArray.splice(++index, 1)[0]); + } + selectTreeIndex(index, true); } -optionObject.prototype.insertBefore = function insertBefore(option) +optionObject.prototype.appendOption = function appendOption(child, parent) { - InsertBefore(this.parentObject, this, option); -} + // special case quick check + if (this.level == 1) + return gDialog.appendOption(child, 0); -optionObject.prototype.appendChild = function appendChild(child) -{ - return this.parentObject.appendChild(child); + // append the option to the parent element + parent = getParentIndex(parent); + return itemArray[parent].appendOption(child, parent); }; // OPTGROUP element wrapper object -function optgroupObject(parent, optgroup) +// +function optgroupObject(optgroup) { - this.globalIndex = globalArray.length; - globalArray[globalArray.length++] = this; - this.parentObject = parent; this.element = optgroup; - this.treeItem = createXUL("treeitem"); - this.treeRow = createXUL("treerow"); - this.treeCell = createXUL("treecell"); - this.treeChildren = createXUL("treechildren"); - this.treeItem.setAttribute("index", this.globalIndex); - this.treeItem.setAttribute("container", "true"); - this.treeItem.setAttribute("empty", "true"); - this.treeItem.setAttribute("open", "true"); - this.treeCell.setAttribute("class", "treecell-indent"); - this.treeCell.setAttribute("notwisty", "true"); - this.treeCell.setAttribute("label", optgroup.label); - this.treeRow.appendChild(this.treeCell); - this.treeItem.appendChild(this.treeRow); - this.treeItem.appendChild(this.treeChildren); - parent.treeChildren.appendChild(this.treeItem); - gDialog.treeItem.setAttribute("open", "true"); - for (var child = optgroup.firstChild; child; child = child.nextSibling) - if (child.tagName == "OPTION") - new optionObject(this, child); } -optgroupObject.prototype.onSpace = function onSpace() +optgroupObject.prototype.level = 1; + +optgroupObject.prototype.container = true; + +optgroupObject.prototype.getCellText = function getCellText(column) +{ + return column == "SelectTextCol" ? this.element.label : ""; +} + +optgroupObject.prototype.cycleCell = function cycleCell(index) { }; @@ -292,8 +304,9 @@ optgroupObject.prototype.onBlur = function onBlur() optgroupObject.prototype.canDestroy = function canDestroy(prompt) { - return !this.element.firstChild; -/*return !this.element.firstChild && (!prompt || + // Only removing empty option groups for now + return gDialog.nextChild(treeSelection.currentIndex) - treeSelection.currentIndex == 1; +/*&& (!prompt || ConfirmWithTitle(GetString("DeleteOptGroup"), GetString("DeleteOptGroupMsg"), GetString("DeleteOptGroup"))); @@ -302,65 +315,73 @@ optgroupObject.prototype.canDestroy = function canDestroy(prompt) optgroupObject.prototype.destroy = function destroy() { - gDialog.removeChild(this); }; -optgroupObject.prototype.canMoveUp = function canMoveUp() -{ - return this.treeItem.previousSibling; -} - optgroupObject.prototype.moveUp = function moveUp() { - InsertBefore(this.parentObject, this, GetObjectForTreeItem(this.treeItem.previousSibling)); -} - -optgroupObject.prototype.insertBefore = function insertBefore(option) -{ - if (this.treeChildren.firstChild) - InsertBefore(this, option, GetObjectForTreeItem(this.treeChildren.firstChild)); - else - AppendChild(this, option); + // Find the index of the previous and next elements at the same level + var index = treeSelection.currentIndex; + var i = index; + while (itemArray[--index].level > 1); + var j = gDialog.nextChild(i); + // Cut out the element, cut the array in two, then join together + var movedItems = itemArray.splice(i, j - i); + var endItems = itemArray.splice(index); + itemArray = itemArray.concat(movedItems).concat(endItems); + // Repaint the lot + treeBoxObject.invalidateRange(index, j); + selectTreeIndex(index, true); } optgroupObject.prototype.canMoveDown = function canMoveDown() { - return this.treeItem.nextSibling; + return gDialog.lastChild() > treeSelection.currentIndex; } optgroupObject.prototype.moveDown = function moveDown() { - InsertBefore(this.parentObject, GetObjectForTreeItem(this.treeItem.nextSibling), this); + // Find the index of the next two elements at the same level + var index = treeSelection.currentIndex; + var i = gDialog.nextChild(index); + var j = gDialog.nextChild(i); + // Cut out the element, cut the array in two, then join together + var movedItems = itemArray.splice(i, j - 1); + var endItems = itemArray.splice(index); + itemArray = itemArray.concat(movedItems).concat(endItems); + // Repaint the lot + treeBoxObject.invalidateRange(index, j); + index += j - i; + selectTreeIndex(index, true); } -optgroupObject.prototype.insertAfter = function insertAfter(option) +optgroupObject.prototype.appendOption = function appendOption(child, parent) { - AppendChild(this, option); -} - -optgroupObject.prototype.appendChild = function appendChild(child) -{ - this.element.appendChild(child); - return new optionObject(this, child); -}; - -optgroupObject.prototype.removeChild = function removeChild(child) -{ - this.element.removeChild(child.element); - this.treeChildren.removeChild(child.treeItem); - globalArray[child.globalIndex] = null; + var index = gDialog.nextChild(parent); + // XXX need to repaint the lines, tree won't do this + treeBoxObject.invalidatePrimaryCell(index - 1); + // insert the wrapped object as the last child + itemArray.splice(index, 0, new optionObject(child, 2)); + treeBoxObject.rowCountChanged(index, 1); + selectTreeIndex(index, false); }; // dialog initialization code function Startup() { - if (!InitEditorShell()) + var editor = GetCurrentEditor(); + if (!editor) + { + dump("Failed to get active editor!\n"); + window.close(); return; + } // Get a single selected select element - var tagName = "select"; - selectElement = editorShell.GetSelectedElement(tagName); + const kTagName = "select"; + try { + selectElement = editor.getSelectedElement(kTagName); + } catch (e) {} if (selectElement) // We found an element and don't need to insert one @@ -371,8 +392,10 @@ function Startup() // We don't have an element selected, // so create one with default attributes + try { + selectElement = editor.createElementWithDefaults(kTagName); + } catch (e) {} - selectElement = editorShell.CreateElementWithDefaults(tagName); if(!selectElement) { dump("Failed to get selected element or create a new one!\n"); @@ -383,6 +406,7 @@ function Startup() // SELECT element wrapper object gDialog = { + // useful elements accept: document.documentElement.getButton("accept"), selectDeck: document.getElementById("SelectDeck"), selectName: document.getElementById("SelectName"), @@ -401,13 +425,15 @@ function Startup() previousButton: document.getElementById("PreviousButton"), nextButton: document.getElementById("NextButton"), tree: document.getElementById("SelectTree"), - treeCols: document.getElementById("SelectCols"), - treeItem: document.getElementById("SelectItem"), - treeCell: document.getElementById("SelectCell"), - treeChildren: document.getElementById("SelectChildren"), + // wrapper methods (except MoveUp and MoveDown) element: selectElement.cloneNode(false), - globalIndex: 0, - onSpace: function onSpace() {}, + level: 0, + container: true, + getCellText: function getCellText(column) + { + return column == "SelectTextCol" ? this.element.getAttribute("name") : ""; + }, + cycleCell: function cycleCell(index) {}, onFocus: function onFocus() { gDialog.selectName.value = this.element.getAttribute("name"); @@ -438,69 +464,154 @@ function Startup() else this.element.removeAttribute("tabindex"); }, - appendChild: function appendChild(child) + appendOption: function appendOption(child, parent) { - if (child.tagName == "OPTION") - { - this.element.appendChild(child) - return new optionObject(this, child); - } - if (child.tagName == "OPTGROUP") - { - this.element.appendChild(child) - return new optgroupObject(this, child); - } - return null; - }, - removeChild: function removeChild(child) - { - this.treeChildren.removeChild(child.treeItem); - globalArray[child.globalIndex] = null; + var index = itemArray.length; + // XXX need to repaint the lines, tree won't do this + treeBoxObject.invalidateRange(this.lastChild(), index); + // append the wrapped object + itemArray.push(new optionObject(child, 1)); + treeBoxObject.rowCountChanged(index, 1); + selectTreeIndex(index, false); }, canDestroy: function canDestroy(prompt) { return false; }, - canMoveUp: function canMoveUp() - { - return false; - }, canMoveDown: function canMoveDown() { return false; + }, + // helper methods + // Find the index of the next immediate child of the select + nextChild: function nextChild(index) + { + while (++index < itemArray.length && itemArray[index].level > 1); + return index; + }, + // Find the index of the last immediate child of the select + lastChild: function lastChild() + { + var index = itemArray.length; + while (itemArray[--index].level > 1); + return index; } } - globalArray = [gDialog]; - - // Workaround for tree scrollbar bug - for (var col = gDialog.treeCols.firstChild; col.nextSibling; col = col.nextSibling) - { - col.setAttribute("width", col.boxObject.width); - col.removeAttribute("flex"); - } + // Start with the