2002-01-15 18:49:46 +03:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Selection List Properties Dialog.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Neil Rashbrook.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2001
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
// Global variables
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
var atomService = Components.classes["@mozilla.org/atom-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIAtomService);
|
|
|
|
var checkedAtoms = {
|
|
|
|
"false": atomService.getAtom("checked-false"),
|
|
|
|
"true": atomService.getAtom("checked-true")};
|
|
|
|
|
2002-01-15 18:49:46 +03:00
|
|
|
var hasValue;
|
|
|
|
var oldValue;
|
|
|
|
var insertNew;
|
2002-10-06 00:44:49 +04:00
|
|
|
var itemArray;
|
|
|
|
var treeBoxObject;
|
|
|
|
var treeSelection;
|
2002-01-15 18:49:46 +03:00
|
|
|
var selectElement;
|
2002-10-06 00:44:49 +04:00
|
|
|
var currentItem = null;
|
|
|
|
var selectedOption = null;
|
2002-01-15 18:49:46 +03:00
|
|
|
var selectedOptionCount = 0;
|
|
|
|
|
|
|
|
// Utility functions
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
function getParentIndex(index)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
switch (itemArray[index].level)
|
|
|
|
{
|
|
|
|
case 0: return -1;
|
|
|
|
case 1: return 0;
|
|
|
|
}
|
|
|
|
while (itemArray[--index].level > 1);
|
|
|
|
return index;
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function UpdateSelectMultiple()
|
|
|
|
{
|
|
|
|
if (selectedOptionCount > 1)
|
|
|
|
{
|
|
|
|
gDialog.selectMultiple.checked = true;
|
|
|
|
gDialog.selectMultiple.disabled = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
gDialog.selectMultiple.disabled = false;
|
|
|
|
}
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
/* 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);
|
|
|
|
*/
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
// OPTION element wrapper object
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
// Create a wrapper for the given element at the given level
|
|
|
|
function optionObject(option, level)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// select an added option (when loading from document)
|
2002-01-15 18:49:46 +03:00
|
|
|
if (option.hasAttribute("selected"))
|
|
|
|
selectedOptionCount++;
|
2002-10-06 00:44:49 +04:00
|
|
|
this.level = level;
|
2002-01-15 18:49:46 +03:00
|
|
|
this.element = option;
|
|
|
|
}
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
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)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
|
|
|
if (this.element.hasAttribute("selected"))
|
|
|
|
{
|
|
|
|
this.element.removeAttribute("selected");
|
2002-10-06 00:44:49 +04:00
|
|
|
selectedOptionCount--;
|
|
|
|
selectedOption = null;
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// Different handling for multiselect lists
|
|
|
|
if (gDialog.selectMultiple.checked || !selectedOption)
|
2002-01-15 18:49:46 +03:00
|
|
|
selectedOptionCount++;
|
2002-10-06 00:44:49 +04:00
|
|
|
else if (selectedOption)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
selectedOption.removeAttribute("selected");
|
|
|
|
treeBoxObject.invalidateColumn("SelectSelCol");
|
|
|
|
selectedOption = null;
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
this.element.setAttribute("selected", "");
|
2002-10-06 00:44:49 +04:00
|
|
|
selectedOption = this.element;
|
|
|
|
treeBoxObject.invalidateCell(index, "SelectSelCol");
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
2002-10-06 00:44:49 +04:00
|
|
|
if (currentItem == this)
|
|
|
|
// Also update the deck
|
|
|
|
gDialog.optionSelected.setAttribute("checked", this.element.hasAttribute("selected"));
|
2002-01-15 18:49:46 +03:00
|
|
|
UpdateSelectMultiple();
|
|
|
|
};
|
|
|
|
|
|
|
|
optionObject.prototype.onFocus = function onFocus()
|
|
|
|
{
|
|
|
|
gDialog.optionText.value = this.element.text;
|
|
|
|
hasValue = this.element.hasAttribute("value");
|
|
|
|
oldValue = this.element.value;
|
|
|
|
gDialog.optionHasValue.checked = hasValue;
|
|
|
|
gDialog.optionValue.value = hasValue ? this.element.value : this.element.text;
|
|
|
|
gDialog.optionSelected.checked = this.element.hasAttribute("selected");
|
|
|
|
gDialog.optionDisabled.checked = this.element.hasAttribute("disabled");
|
|
|
|
gDialog.selectDeck.setAttribute("selectedIndex", "2");
|
|
|
|
};
|
|
|
|
|
|
|
|
optionObject.prototype.onBlur = function onBlur()
|
|
|
|
{
|
|
|
|
this.element.text = gDialog.optionText.value;
|
|
|
|
if (gDialog.optionHasValue.checked)
|
|
|
|
this.element.value = gDialog.optionValue.value;
|
|
|
|
else
|
|
|
|
this.element.removeAttribute("value");
|
|
|
|
if (gDialog.optionSelected.checked)
|
|
|
|
this.element.setAttribute("selected", "");
|
|
|
|
else
|
|
|
|
this.element.removeAttribute("selected");
|
|
|
|
if (gDialog.optionDisabled.checked)
|
|
|
|
this.element.setAttribute("disabled", "");
|
|
|
|
else
|
|
|
|
this.element.removeAttribute("disabled");
|
|
|
|
};
|
|
|
|
|
|
|
|
optionObject.prototype.canDestroy = function canDestroy(prompt)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
/*return !prompt ||
|
|
|
|
ConfirmWithTitle(GetString("DeleteOption"),
|
|
|
|
GetString("DeleteOptionMsg"),
|
|
|
|
GetString("DeleteOption"));*/
|
|
|
|
};
|
|
|
|
|
|
|
|
optionObject.prototype.destroy = function destroy()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// Deselect a removed option
|
2002-01-15 18:49:46 +03:00
|
|
|
if (this.element.hasAttribute("selected"))
|
|
|
|
{
|
|
|
|
selectedOptionCount--;
|
2002-10-06 00:44:49 +04:00
|
|
|
selectedOption = null;
|
2002-01-15 18:49:46 +03:00
|
|
|
UpdateSelectMultiple();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
/* 4 cases:
|
|
|
|
* a) optgroup -> optgroup
|
|
|
|
* ... ...
|
|
|
|
* option option
|
|
|
|
* b) optgroup -> option
|
|
|
|
* option optgroup
|
|
|
|
* ... ...
|
|
|
|
* c) option
|
|
|
|
* option
|
|
|
|
* d) option
|
|
|
|
* option
|
|
|
|
*/
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
optionObject.prototype.moveUp = function moveUp()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
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();
|
|
|
|
}
|
2002-01-15 18:49:46 +03:00
|
|
|
else
|
2002-10-06 00:44:49 +04:00
|
|
|
{
|
|
|
|
// 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);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
optionObject.prototype.canMoveDown = function canMoveDown()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// move down is not allowed on the last option if its level is 1
|
|
|
|
return this.level > 1 || itemArray.length - treeSelection.currentIndex > 1;
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
optionObject.prototype.moveDown = function moveDown()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
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();
|
|
|
|
}
|
2002-01-15 18:49:46 +03:00
|
|
|
else
|
2002-10-06 00:44:49 +04:00
|
|
|
{
|
|
|
|
// 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);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
optionObject.prototype.appendOption = function appendOption(child, parent)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// special case quick check
|
|
|
|
if (this.level == 1)
|
|
|
|
return gDialog.appendOption(child, 0);
|
2002-01-15 18:49:46 +03:00
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
// append the option to the parent element
|
|
|
|
parent = getParentIndex(parent);
|
|
|
|
return itemArray[parent].appendOption(child, parent);
|
2002-01-15 18:49:46 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// OPTGROUP element wrapper object
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
function optgroupObject(optgroup)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
|
|
|
this.element = optgroup;
|
|
|
|
}
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
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)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
optgroupObject.prototype.onFocus = function onFocus()
|
|
|
|
{
|
|
|
|
gDialog.optgroupLabel.value = this.element.label;
|
|
|
|
gDialog.optgroupDisabled.checked = this.element.disabled;
|
|
|
|
gDialog.selectDeck.setAttribute("selectedIndex", "1");
|
|
|
|
};
|
|
|
|
|
|
|
|
optgroupObject.prototype.onBlur = function onBlur()
|
|
|
|
{
|
|
|
|
this.element.label = gDialog.optgroupLabel.value;
|
|
|
|
this.element.disabled = gDialog.optgroupDisabled.checked;
|
|
|
|
};
|
|
|
|
|
|
|
|
optgroupObject.prototype.canDestroy = function canDestroy(prompt)
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// Only removing empty option groups for now
|
|
|
|
return gDialog.nextChild(treeSelection.currentIndex) - treeSelection.currentIndex == 1;
|
|
|
|
/*&& (!prompt ||
|
2002-01-15 18:49:46 +03:00
|
|
|
ConfirmWithTitle(GetString("DeleteOptGroup"),
|
|
|
|
GetString("DeleteOptGroupMsg"),
|
|
|
|
GetString("DeleteOptGroup")));
|
|
|
|
*/
|
|
|
|
};
|
|
|
|
|
|
|
|
optgroupObject.prototype.destroy = function destroy()
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
optgroupObject.prototype.moveUp = function moveUp()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// 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);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
optgroupObject.prototype.canMoveDown = function canMoveDown()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
return gDialog.lastChild() > treeSelection.currentIndex;
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
optgroupObject.prototype.moveDown = function moveDown()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// 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.appendOption = function appendOption(child, parent)
|
|
|
|
{
|
|
|
|
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);
|
2002-01-15 18:49:46 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// dialog initialization code
|
|
|
|
|
|
|
|
function Startup()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
var editor = GetCurrentEditor();
|
|
|
|
if (!editor)
|
|
|
|
{
|
|
|
|
dump("Failed to get active editor!\n");
|
|
|
|
window.close();
|
2002-01-15 18:49:46 +03:00
|
|
|
return;
|
2002-10-06 00:44:49 +04:00
|
|
|
}
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
// Get a single selected select element
|
2002-10-06 00:44:49 +04:00
|
|
|
const kTagName = "select";
|
|
|
|
try {
|
|
|
|
selectElement = editor.getSelectedElement(kTagName);
|
|
|
|
} catch (e) {}
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
if (selectElement)
|
|
|
|
// We found an element and don't need to insert one
|
|
|
|
insertNew = false;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
insertNew = true;
|
|
|
|
|
|
|
|
// We don't have an element selected,
|
|
|
|
// so create one with default attributes
|
2002-10-06 00:44:49 +04:00
|
|
|
try {
|
|
|
|
selectElement = editor.createElementWithDefaults(kTagName);
|
|
|
|
} catch (e) {}
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
if(!selectElement)
|
|
|
|
{
|
|
|
|
dump("Failed to get selected element or create a new one!\n");
|
|
|
|
window.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SELECT element wrapper object
|
|
|
|
gDialog = {
|
2002-10-06 00:44:49 +04:00
|
|
|
// useful elements
|
2002-01-15 18:49:46 +03:00
|
|
|
accept: document.documentElement.getButton("accept"),
|
|
|
|
selectDeck: document.getElementById("SelectDeck"),
|
|
|
|
selectName: document.getElementById("SelectName"),
|
|
|
|
selectSize: document.getElementById("SelectSize"),
|
|
|
|
selectMultiple: document.getElementById("SelectMultiple"),
|
|
|
|
selectDisabled: document.getElementById("SelectDisabled"),
|
|
|
|
selectTabIndex: document.getElementById("SelectTabIndex"),
|
|
|
|
optgroupLabel: document.getElementById("OptGroupLabel"),
|
|
|
|
optgroupDisabled: document.getElementById("OptGroupDisabled"),
|
|
|
|
optionText: document.getElementById("OptionText"),
|
|
|
|
optionHasValue: document.getElementById("OptionHasValue"),
|
|
|
|
optionValue: document.getElementById("OptionValue"),
|
|
|
|
optionSelected: document.getElementById("OptionSelected"),
|
|
|
|
optionDisabled: document.getElementById("OptionDisabled"),
|
|
|
|
removeButton: document.getElementById("RemoveButton"),
|
|
|
|
previousButton: document.getElementById("PreviousButton"),
|
|
|
|
nextButton: document.getElementById("NextButton"),
|
|
|
|
tree: document.getElementById("SelectTree"),
|
2002-10-06 00:44:49 +04:00
|
|
|
// wrapper methods (except MoveUp and MoveDown)
|
2002-01-15 18:49:46 +03:00
|
|
|
element: selectElement.cloneNode(false),
|
2002-10-06 00:44:49 +04:00
|
|
|
level: 0,
|
|
|
|
container: true,
|
|
|
|
getCellText: function getCellText(column)
|
|
|
|
{
|
|
|
|
return column == "SelectTextCol" ? this.element.getAttribute("name") : "";
|
|
|
|
},
|
|
|
|
cycleCell: function cycleCell(index) {},
|
2002-01-15 18:49:46 +03:00
|
|
|
onFocus: function onFocus()
|
|
|
|
{
|
|
|
|
gDialog.selectName.value = this.element.getAttribute("name");
|
|
|
|
gDialog.selectSize.value = this.element.getAttribute("size");
|
|
|
|
gDialog.selectMultiple.checked = this.element.hasAttribute("multiple");
|
|
|
|
gDialog.selectDisabled.checked = this.element.hasAttribute("disabled");
|
|
|
|
gDialog.selectTabIndex.value = this.element.getAttribute("tabindex");
|
|
|
|
this.selectDeck.setAttribute("selectedIndex", "0");
|
|
|
|
onNameInput();
|
|
|
|
},
|
|
|
|
onBlur: function onBlur()
|
|
|
|
{
|
|
|
|
this.element.setAttribute("name", gDialog.selectName.value);
|
|
|
|
if (gDialog.selectSize.value)
|
|
|
|
this.element.setAttribute("size", gDialog.selectSize.value);
|
|
|
|
else
|
|
|
|
this.element.removeAttribute("size");
|
|
|
|
if (gDialog.selectMultiple.checked)
|
|
|
|
this.element.setAttribute("multiple", "");
|
|
|
|
else
|
|
|
|
this.element.removeAttribute("multiple");
|
|
|
|
if (gDialog.selectDisabled.checked)
|
|
|
|
this.element.setAttribute("disabled", "");
|
|
|
|
else
|
|
|
|
this.element.removeAttribute("disabled");
|
|
|
|
if (gDialog.selectTabIndex.value)
|
|
|
|
this.element.setAttribute("tabindex", gDialog.selectTabIndex.value);
|
|
|
|
else
|
|
|
|
this.element.removeAttribute("tabindex");
|
|
|
|
},
|
2002-10-06 00:44:49 +04:00
|
|
|
appendOption: function appendOption(child, parent)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
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);
|
2002-01-15 18:49:46 +03:00
|
|
|
},
|
|
|
|
canDestroy: function canDestroy(prompt)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
},
|
2002-10-06 00:44:49 +04:00
|
|
|
canMoveDown: function canMoveDown()
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
},
|
2002-10-06 00:44:49 +04:00
|
|
|
// helper methods
|
|
|
|
// Find the index of the next immediate child of the select
|
|
|
|
nextChild: function nextChild(index)
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
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;
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
}
|
2002-10-06 00:44:49 +04:00
|
|
|
// Start with the <select> wrapper
|
|
|
|
itemArray = [gDialog];
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
// We modify the actual option and optgroup elements so clone them first
|
|
|
|
for (var child = selectElement.firstChild; child; child = child.nextSibling)
|
2002-10-06 00:44:49 +04:00
|
|
|
{
|
|
|
|
if (child.tagName == "OPTION")
|
|
|
|
itemArray.push(new optionObject(child.cloneNode(true), 1));
|
|
|
|
else if (child.tagName == "OPTGROUP")
|
|
|
|
{
|
|
|
|
itemArray.push(new optgroupObject(child.cloneNode(false)));
|
|
|
|
for (var grandchild = child.firstChild; grandchild; grandchild = grandchild.nextSibling)
|
|
|
|
if (grandchild.tagName == "OPTION")
|
|
|
|
itemArray.push(new optionObject(grandchild.cloneNode(true), 2));
|
|
|
|
}
|
|
|
|
}
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
UpdateSelectMultiple();
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
// Define a custom view for the tree
|
|
|
|
treeBoxObject = gDialog.tree.treeBoxObject;
|
|
|
|
treeBoxObject.view = {
|
|
|
|
QueryInterface : function QueryInterface(aIID)
|
|
|
|
{
|
|
|
|
if (aIID.equals(Components.interfaces.nsITreeView) ||
|
|
|
|
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
|
|
|
|
aIID.equals(Components.interfaces.nsISupports))
|
|
|
|
return this;
|
|
|
|
throw Components.results.NS_NOINTERFACE;
|
|
|
|
},
|
|
|
|
// useful for debugging
|
|
|
|
get wrappedJSObject() { return this; },
|
|
|
|
get rowCount() { return itemArray.length; },
|
|
|
|
get selection() { return treeSelection; },
|
|
|
|
set selection(selection) { return treeSelection = selection; },
|
|
|
|
getRowProperties: function getRowProperties(index, column, prop) { },
|
|
|
|
// could have used a wrapper for this
|
|
|
|
getCellProperties: function getCellProperties(index, column, prop)
|
|
|
|
{
|
|
|
|
if (column == "SelectSelCol" && !itemArray[index].container)
|
|
|
|
prop.AppendElement(checkedAtoms[itemArray[index].element.hasAttribute("selected")]);
|
|
|
|
},
|
|
|
|
getColumnProperties: function getColumnProperties(column, elem, prop) { },
|
|
|
|
// get info from wrapper
|
|
|
|
isContainer: function isContainer(index) { return itemArray[index].container; },
|
|
|
|
isContainerOpen: function isContainerOpen(index) { return true; },
|
|
|
|
isContainerEmpty: function isContainerEmpty(index) { return true; },
|
|
|
|
isSeparator: function isSeparator(index) { return false; },
|
|
|
|
isSorted: function isSorted() { return false; },
|
|
|
|
// d&d not implemented yet!
|
|
|
|
canDropOn: function canDropOn(index) { return false; },
|
|
|
|
canDropBeforeAfter: function canDropBeforeAfter(index, before) { return index >= before; },
|
|
|
|
drop: function drop(index, orientation) { alert('drop:' + index + ',' + orientation); },
|
|
|
|
// same as the global helper
|
|
|
|
getParentIndex: getParentIndex,
|
|
|
|
// tree needs to know when to paint lines
|
|
|
|
hasNextSibling: function hasNextSibling(index, after)
|
|
|
|
{
|
|
|
|
if (!index)
|
|
|
|
return false;
|
|
|
|
var level = itemArray[index].level;
|
|
|
|
while (++after < itemArray.length)
|
|
|
|
switch (level - itemArray[after].level)
|
|
|
|
{
|
|
|
|
case 1: return false;
|
|
|
|
case 0: return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
getLevel: function getLevel(index) { return itemArray[index].level; },
|
|
|
|
getImageSrc: function getImageSrc(index, column) { },
|
|
|
|
getProgressMode : function getProgressMode(index,column) { },
|
|
|
|
getCellValue: function getCellValue(index, column) { },
|
|
|
|
getCellText: function getCellText(index, column) { return itemArray[index].getCellText(column); },
|
|
|
|
setTree: function setTree(tree) { this.tree = tree; },
|
|
|
|
toggleOpenState: function toggleOpenState(index) { },
|
|
|
|
cycleHeader: function cycleHeader(col, elem) { },
|
|
|
|
selectionChanged: function selectionChanged()
|
|
|
|
{
|
|
|
|
// Save current values and update buttons and deck
|
|
|
|
if (currentItem)
|
|
|
|
currentItem.onBlur();
|
|
|
|
var currentIndex = treeSelection.currentIndex;
|
|
|
|
currentItem = itemArray[currentIndex];
|
|
|
|
gDialog.removeButton.disabled = !currentItem.canDestroy();
|
|
|
|
gDialog.previousButton.disabled = currentIndex < 2;
|
|
|
|
gDialog.nextButton.disabled = !currentItem.canMoveDown();
|
|
|
|
// For Advanced Edit
|
|
|
|
globalElement = currentItem.element;
|
|
|
|
currentItem.onFocus();
|
|
|
|
},
|
|
|
|
cycleCell: function cycleCell(index, column) { itemArray[index].cycleCell(index); },
|
|
|
|
isEditable: function isEditable(index, column) { return false; },
|
|
|
|
performAction: function performAction(action) { },
|
|
|
|
performActionOnCell: function performActionOnCell(action, index, column) { }
|
|
|
|
};
|
|
|
|
treeSelection.select(0);
|
|
|
|
currentItem = gDialog;
|
|
|
|
//onNameInput();
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
SetTextboxFocus(gDialog.selectName);
|
|
|
|
|
|
|
|
SetWindowLocation();
|
|
|
|
}
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
// Called from Advanced Edit
|
2002-01-15 18:49:46 +03:00
|
|
|
function InitDialog()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.onFocus();
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
// Called from Advanced Edit
|
2002-01-15 18:49:46 +03:00
|
|
|
function ValidateData()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.onBlur();
|
2002-01-15 18:49:46 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function onAccept()
|
|
|
|
{
|
|
|
|
// All values are valid - copy to actual element in doc or
|
|
|
|
// element created to insert
|
|
|
|
ValidateData();
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
var editor = GetCurrentEditor();
|
|
|
|
|
|
|
|
// Coalesce into one undo transaction
|
|
|
|
editor.beginTransaction();
|
2002-01-15 18:49:46 +03:00
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
try
|
|
|
|
{
|
|
|
|
editor.cloneAttributes(selectElement, gDialog.element);
|
2002-01-15 18:49:46 +03:00
|
|
|
|
|
|
|
if (insertNew)
|
|
|
|
// 'true' means delete the selection before inserting
|
2002-10-06 00:44:49 +04:00
|
|
|
editor.insertElementAtSelection(selectElement, true);
|
2002-01-15 18:49:46 +03:00
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
editor.setShouldTxnSetSelection(false);
|
2002-01-15 18:49:46 +03:00
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
while (selectElement.lastChild)
|
|
|
|
editor.deleteNode(selectElement.lastChild);
|
|
|
|
|
2003-02-24 15:50:21 +03:00
|
|
|
var offset = 0;
|
2002-10-06 00:44:49 +04:00
|
|
|
for (var i = 1; i < itemArray.length; i++)
|
|
|
|
if (itemArray[i].level > 1)
|
|
|
|
selectElement.lastChild.appendChild(itemArray[i].element);
|
|
|
|
else
|
|
|
|
editor.insertNode(itemArray[i].element, selectElement, offset++, true);
|
|
|
|
|
|
|
|
editor.setShouldTxnSetSelection(true);
|
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
editor.endTransaction();
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
SaveWindowLocation();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Button actions
|
|
|
|
function AddOption()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.appendOption(GetCurrentEditor().createElementWithDefaults("option"), treeSelection.currentIndex);
|
2002-01-15 18:49:46 +03:00
|
|
|
SetTextboxFocus(gDialog.optionText);
|
|
|
|
}
|
|
|
|
|
|
|
|
function AddOptGroup()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
var optgroupElement = GetCurrentEditor().createElementWithDefaults("optgroup");
|
|
|
|
var index = itemArray.length;
|
|
|
|
// XXX need to repaint the lines, tree won't do this
|
|
|
|
treeBoxObject.invalidateRange(gDialog.lastChild(), index);
|
|
|
|
// append the wrapped object
|
|
|
|
itemArray.push(new optgroupObject(optgroupElement));
|
|
|
|
treeBoxObject.rowCountChanged(index, 1);
|
|
|
|
selectTreeIndex(index, false);
|
2002-01-15 18:49:46 +03:00
|
|
|
SetTextboxFocus(gDialog.optgroupLabel);
|
|
|
|
}
|
|
|
|
|
|
|
|
function RemoveElement()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
if (currentItem.canDestroy(true))
|
2002-01-15 18:49:46 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// Only removing empty option groups for now
|
|
|
|
var index = treeSelection.currentIndex;
|
|
|
|
var level = itemArray[index].level;
|
|
|
|
// Perform necessary cleanup and remove the wrapper
|
|
|
|
itemArray[index].destroy();
|
|
|
|
itemArray.splice(index, 1);
|
|
|
|
--index;
|
|
|
|
// XXX need to repaint the lines, tree won't do this
|
|
|
|
if (level == 1) {
|
|
|
|
var last = gDialog.lastChild();
|
|
|
|
if (index > last)
|
|
|
|
treeBoxObject.invalidateRange(last, index);
|
|
|
|
}
|
|
|
|
selectTreeIndex(index, true);
|
|
|
|
treeBoxObject.rowCountChanged(++index, -1);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
// Event handler
|
2002-01-15 18:49:46 +03:00
|
|
|
function onTreeKeyUp(event)
|
|
|
|
{
|
|
|
|
if (event.keyCode == event.DOM_VK_SPACE)
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.cycleCell();
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onNameInput()
|
|
|
|
{
|
|
|
|
var disabled = !gDialog.selectName.value;
|
|
|
|
if (gDialog.accept.disabled != disabled)
|
|
|
|
gDialog.accept.disabled = disabled;
|
2002-10-06 00:44:49 +04:00
|
|
|
gDialog.element.setAttribute("name", gDialog.selectName.value);
|
|
|
|
// repaint the tree
|
|
|
|
treeBoxObject.invalidatePrimaryCell(treeSelection.currentIndex);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onLabelInput()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.element.setAttribute("label", gDialog.optgroupLabel.value);
|
|
|
|
// repaint the tree
|
|
|
|
treeBoxObject.invalidatePrimaryCell(treeSelection.currentIndex);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onTextInput()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.element.text = gDialog.optionText.value;
|
|
|
|
// repaint the tree
|
|
|
|
if (hasValue)
|
|
|
|
treeBoxObject.invalidatePrimaryCell(treeSelection.currentIndex);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gDialog.optionValue.value = gDialog.optionText.value;
|
|
|
|
treeBoxObject.invalidateRow(treeSelection.currentIndex);
|
|
|
|
}
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onValueInput()
|
|
|
|
{
|
|
|
|
gDialog.optionHasValue.checked = hasValue = true;
|
|
|
|
oldValue = gDialog.optionValue.value;
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.element.setAttribute("value", oldValue);
|
|
|
|
// repaint the tree
|
|
|
|
treeBoxObject.invalidateCell(treeSelection.currentIndex, "SelectValCol");
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onHasValueClick()
|
|
|
|
{
|
|
|
|
hasValue = gDialog.optionHasValue.checked;
|
|
|
|
if (hasValue)
|
|
|
|
{
|
|
|
|
gDialog.optionValue.value = oldValue;
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.element.setAttribute("value", oldValue);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
oldValue = gDialog.optionValue.value;
|
|
|
|
gDialog.optionValue.value = gDialog.optionText.value;
|
2002-10-06 00:44:49 +04:00
|
|
|
currentItem.element.removeAttribute("value");
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
2002-10-06 00:44:49 +04:00
|
|
|
// repaint the tree
|
|
|
|
treeBoxObject.invalidateCell(treeSelection.currentIndex, "SelectValCol");
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onSelectMultipleClick()
|
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
// Recalculate the unique selected option if we need it and have lost it
|
2002-01-15 18:49:46 +03:00
|
|
|
if (!gDialog.selectMultiple.checked && selectedOptionCount == 1 && !selectedOption)
|
2002-10-06 00:44:49 +04:00
|
|
|
for (var i = 1; !(selectedOption = itemArray[i].element).hasAttribute("selected"); i++);
|
2002-01-15 18:49:46 +03:00
|
|
|
}
|
2002-03-29 05:46:01 +03:00
|
|
|
|
2002-10-06 00:44:49 +04:00
|
|
|
function selectTreeIndex(index, focus)
|
2002-03-29 05:46:01 +03:00
|
|
|
{
|
2002-10-06 00:44:49 +04:00
|
|
|
treeSelection.select(index);
|
|
|
|
treeBoxObject.ensureRowIsVisible(index);
|
|
|
|
if (focus)
|
|
|
|
gDialog.tree.focus();
|
|
|
|
}
|