976 lines
30 KiB
XML
976 lines
30 KiB
XML
<?xml version="1.0"?>
|
|
|
|
<!-- ***** 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 Mozilla XForms support.
|
|
-
|
|
- The Initial Developer of the Original Code is
|
|
- Mozilla Foundation.
|
|
- Portions created by the Initial Developer are Copyright (C) 2007
|
|
- the Initial Developer. All Rights Reserved.
|
|
-
|
|
- Contributor(s):
|
|
- Alexander Surkov <surkov.alexander@gmail.com> (original author)
|
|
-
|
|
- 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 ***** -->
|
|
|
|
<bindings id="xformsSelectsNativeWidgetBindings"
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
|
|
|
<!--
|
|
This file implements the "abstract" UI classes for XForms select/select1
|
|
controls that are used native widgets for their representation.
|
|
-->
|
|
|
|
<!-- BASE binding for select/select1 elements that are used native widgets -->
|
|
<binding id="selectcontrols-base"
|
|
extends="chrome://xforms/content/selects.xml#selectcontrols-base">
|
|
|
|
<implementation>
|
|
<!-- nsIAccessibleProvider -->
|
|
<property name="accessibleType" readonly="true">
|
|
<getter>
|
|
return Components.interfaces.nsIAccessibleProvider.XFormsSelect;
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- overriding the methods from the 'selectcontrols-base' binding -->
|
|
<method name="getFreeEntryValues">
|
|
<body>
|
|
return this.nativeWidget.getFreeEntryValues();
|
|
</body>
|
|
</method>
|
|
|
|
<method name="allowFreeEntry">
|
|
<parameter name="aAllowed"/>
|
|
<body>
|
|
return this.nativeWidget.allowFreeEntry(aAllowed);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="appendFreeEntryItem">
|
|
<parameter name="aValue"/>
|
|
<body>
|
|
this.nativeWidget.appendFreeEntryItem(aValue);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="markItemSelected">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aIsSelected"/>
|
|
<body>
|
|
this.nativeWidget.selectItem(aItem, aIsSelected);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isItemMarkedSelected">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
return this.nativeWidget.isItemSelected(aItem);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="markItemDisabled">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aIsDisabled"/>
|
|
<body>
|
|
this.nativeWidget.disableItem(aItem, aIsDisabled);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isItemMarkedDisabled">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
return this.nativeWidget.isItemDisabled(aItem);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="focusItem">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
this.nativeWidget.focus();
|
|
</body>
|
|
</method>
|
|
|
|
<!-- private -->
|
|
<constructor>
|
|
this.handleInsertion(this, null);
|
|
</constructor>
|
|
|
|
<!-- Return native widget control -->
|
|
<property name="nativeWidget">
|
|
<getter>
|
|
if (!this._nativeWidget)
|
|
this._nativeWidget = this.ownerDocument.
|
|
getAnonymousElementByAttribute(this, "anonid", "nativewidget");
|
|
return this._nativeWidget;
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- Try to update label element when DOM tree has been changed.
|
|
|
|
@param aNode - the node that was inserted or will be removed
|
|
@param aIsInsertion - if true then node was inserted
|
|
-->
|
|
<method name="handleLabel">
|
|
<parameter name="aNode"/>
|
|
<parameter name="aIsInsertion"/>
|
|
<body>
|
|
<![CDATA[
|
|
var node = aNode;
|
|
while (node && node != this && (node.namespaceURI != this.XFORMS_NS ||
|
|
node.localName != "label")) {
|
|
node = node.parentNode;
|
|
}
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
if (!node || node == this)
|
|
return;
|
|
|
|
var label = node;
|
|
|
|
var parent = label.parentNode;
|
|
var labels = parent.getElementsByTagNameNS(this.XFORMS_NS, "label");
|
|
if (labels[0] != label)
|
|
return;
|
|
|
|
label = ((aNode == label) && !aIsInsertion) ? null : label;
|
|
if (parent.namespaceURI == this.XFORMS_NS) {
|
|
// Set label only for xf:item or xf:choices elements.
|
|
switch (parent.localName) {
|
|
case "choices":
|
|
case "item":
|
|
this.nativeWidget.setLabelFor(parent, label);
|
|
break;
|
|
}
|
|
}
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Updates native widget when DOM tree has been changed i.e. "item"/
|
|
"itemset"/"choices" elements have been inserted or removed.
|
|
|
|
@param aNode - the given node, is is either "select"/"select1" elements
|
|
to initialize native widget or "choices"/"item"/"itemset"
|
|
if it was inserted
|
|
@param aParentNode - either parent node of the given node or null if
|
|
native widget is initialized
|
|
@param aParentIndex - index of parent node (for recursive calls)
|
|
@param aPrevSiblingIndex - index of previous sibling node (for recursive
|
|
calls)
|
|
-->
|
|
<method name="handleInsertion">
|
|
<parameter name="aNode"/>
|
|
<parameter name="aParentNode"/>
|
|
<parameter name="aParentIndex"/>
|
|
<parameter name="aPrevSiblingIndex"/>
|
|
<body>
|
|
<![CDATA[
|
|
const nsIXFormsItemSetUIElement =
|
|
Components.interfaces.nsIXFormsItemSetUIElement;
|
|
if (aNode.namespaceURI != this.XFORMS_NS)
|
|
return -1;
|
|
|
|
var container = null;
|
|
var index = -1;
|
|
var prevIndex = -1;
|
|
|
|
switch (aNode.localName) {
|
|
case "select1":
|
|
case "select":
|
|
case "choices":
|
|
container = aNode;
|
|
break;
|
|
case "item":
|
|
break;
|
|
case "itemset":
|
|
var itemset = aNode.QueryInterface(nsIXFormsItemSetUIElement);
|
|
container = itemset.anonymousItemSetContent;
|
|
index = aParentIndex;
|
|
prevIndex = aPrevSiblingIndex;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
// Create native item/choices and insert it into native widget
|
|
// hierarchy if inserted elements are xf:item or xf:choices only.
|
|
if (index == -1) {
|
|
this.isInsertionHandlingPrevented = true;
|
|
if (aParentIndex != null && aParentIndex != -1) {
|
|
index = this.nativeWidget.appendElm(aNode, aParentIndex,
|
|
aPrevSiblingIndex);
|
|
} else {
|
|
index = this.nativeWidget.insertElm(aNode, aParentNode);
|
|
}
|
|
this.isInsertionHandlingPrevented = false;
|
|
}
|
|
|
|
// We return whether inserted element is not container of
|
|
// select/select1 child elements or native element wasn't inserted
|
|
// successfully.
|
|
if (index == -1 || !container)
|
|
return index;
|
|
|
|
// Create/insert native elements for choices/item/itemset child
|
|
// elements of inserted element if any.
|
|
var hasChildNodes = false;
|
|
for (var child = container.firstChild; child; child = child.nextSibling) {
|
|
if (child.namespaceURI != this.XFORMS_NS)
|
|
continue;
|
|
|
|
switch (child.localName) {
|
|
case "choices":
|
|
case "itemset":
|
|
case "item":
|
|
hasChildNodes = true;
|
|
prevIndex = this.handleInsertion(child, null, index, prevIndex);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hasChildNodes ? prevIndex : index;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Flag prevents to handle DOM mutation events if mutation events are
|
|
cause of native widget is updated. -->
|
|
<field name="isInsertionHandlingPrevented">false</field>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="DOMNodeInserted">
|
|
<![CDATA[
|
|
if (this.isInsertionHandlingPrevented)
|
|
return;
|
|
|
|
var target = event.originalTarget;
|
|
var parent = event.relatedNode;
|
|
|
|
// If inserted element is item/itemset/choides element then we should
|
|
// update native widget
|
|
if (target.namespaceURI == this.XFORMS_NS &&
|
|
(target.localName == "choices" || target.localName == "itemset" ||
|
|
target.localName == "item")) {
|
|
|
|
// Search for parent element that is reflected by native widget.
|
|
// The parent element can be select/select1, itemset or choices
|
|
// element so we skip itemset element because it isn't presented
|
|
// in native widget.
|
|
while (parent != this && (parent.namespaceURI != this.XFORMS_NS ||
|
|
parent.localName != "choices"))
|
|
parent = parent.parentNode;
|
|
|
|
this.handleInsertion(target, parent);
|
|
return;
|
|
}
|
|
|
|
// otherwise we try to update label for item/choices element.
|
|
this.handleLabel(target, true);
|
|
]]>
|
|
</handler>
|
|
|
|
<handler event="DOMNodeRemoved">
|
|
if (this.isInsertionHandlingPrevented)
|
|
return;
|
|
|
|
var target = event.originalTarget;
|
|
|
|
if (target.namespaceURI == this.XFORMS_NS) {
|
|
switch (target.localName) {
|
|
case "choices":
|
|
case "item":
|
|
this.nativeWidget.removeNativeElm(target);
|
|
return;
|
|
|
|
case "itemset":
|
|
var itemset = target.QueryInterface(Components.interfaces.nsIXFormsItemSetUIElement);
|
|
var container = itemset.anonymousItemSetContent;
|
|
for (var child = container.firstChild; child; child = child.nextSibling)
|
|
this.nativeWidget.removeNativeElm(child);
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.handleLabel(target, false);
|
|
</handler>
|
|
|
|
<handler event="DOMCharacterDataModified">
|
|
if (this.isInsertionHandlingPrevented)
|
|
return;
|
|
|
|
this.handleLabel(event.originalTarget, true);
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
|
|
<!-- SELECT: BASE
|
|
Note, keep synchronized with 'selects.xml#select-base' binding
|
|
-->
|
|
<binding id="select-base"
|
|
extends="#selectcontrols-base">
|
|
|
|
<implementation implements="nsIXFormsNSSelectElement">
|
|
|
|
<!-- nsIXFormsNSSelectElement -->
|
|
<property name="selectedItems" readonly="true">
|
|
<getter>
|
|
function _isSelected(aItem, aItemList) {
|
|
if (this.isItemMarkedSelected(aItem))
|
|
aItemList.push(aItem);
|
|
return true;
|
|
}
|
|
var list = [];
|
|
this.traverseItems(this, _isSelected, list);
|
|
return list;
|
|
</getter>
|
|
</property>
|
|
|
|
<method name="addItemToSelection">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
this.markItemSelected(aItem, true);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="removeItemFromSelection">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
this.markItemSelected(aItem, false);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="clearSelection">
|
|
<body>
|
|
function _clearSelection(aItem) {
|
|
this.markItemSelected(aItem, false);
|
|
return true;
|
|
}
|
|
this.traverseItems(this, _clearSelection);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="selectAll">
|
|
<body>
|
|
function _selectAll(aItem) {
|
|
this.markItemSelected(aItem, true);
|
|
return true;
|
|
}
|
|
this.traverseItems(this, _selectAll);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isItemSelected">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
return this.isItemMarkedSelected(aItem);
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Private implementation -->
|
|
<method name="getValuesArrayFor">
|
|
<parameter name="aString"/>
|
|
<parameter name="aWhiteSpaceExpr"/>
|
|
<body>
|
|
// A limitation of the XML Schema list datatypes is that white space
|
|
// characters in the storage values (the value element) are always
|
|
// interpreted as separators between individual data values.
|
|
// Therefore, authors should avoid using white space characters within
|
|
// storage values with list simpleContent.
|
|
|
|
// Replace new line (\n), tabs (\t) and carriage returns (\r) with
|
|
// space (" ").
|
|
var value = aString.replace(aWhiteSpaceExpr, " ");
|
|
return value.split(/\s/);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="selectFreeEntryItemElements">
|
|
<body>
|
|
for (var i = 0; this.values.length; ++i) {
|
|
if (!this.values[i].isUsed) {
|
|
this.appendFreeEntryItem(this.values[i].value);
|
|
this.values[i].isUsed = true;
|
|
}
|
|
}
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isOutOfRange">
|
|
<parameter name="aHitArray"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (!aHitArray)
|
|
return false;
|
|
|
|
var i = 0;
|
|
for (; i < aHitArray.length && aHitArray[i].isUsed; ++i);
|
|
return i != aHitArray.length;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
</implementation>
|
|
</binding>
|
|
|
|
|
|
<!-- SELECT1: BASE
|
|
Note, keep synchronized with 'selects.xml#select1-base' binding.
|
|
-->
|
|
<binding id="select1-base"
|
|
extends="#selectcontrols-base">
|
|
|
|
<implementation implements="nsIXFormsNSSelect1Element">
|
|
<!-- nsIXFormsNSSelect1Element -->
|
|
<property name="selectedItem">
|
|
<getter>
|
|
function getSelectedItem(aItem, aSelectedItem) {
|
|
var selected = this.isItemMarkedSelected(aItem);
|
|
if (selected)
|
|
aSelectedItem.value = aItem;
|
|
return !selected;
|
|
}
|
|
var selectedItem = {value: null};
|
|
this.traverseItems(this, getSelectedItem, selectedItem);
|
|
return selectedItem.value;
|
|
</getter>
|
|
<setter>
|
|
function setSelectedItem(aItem, aSelectedItem) {
|
|
this.markItemSelected(aItem, aItem == aSelectedItem);
|
|
return true;
|
|
}
|
|
this.traverseItems(this, setSelectedItem, val);
|
|
</setter>
|
|
</property>
|
|
|
|
<!-- Private implementation -->
|
|
<method name="getValuesArrayFor">
|
|
<parameter name="aString"/>
|
|
<parameter name="aWhiteSpaceExpr"/>
|
|
<body>
|
|
return [aString];
|
|
</body>
|
|
</method>
|
|
|
|
<method name="selectFreeEntryItemElements">
|
|
<body>
|
|
if (this.values.length != 1)
|
|
return;
|
|
|
|
if (!this.values[0].isUsed) {
|
|
this.appendFreeEntryItem(this.values[0].value);
|
|
this.values[0].isUsed = true;
|
|
}
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isOutOfRange">
|
|
<parameter name="aHitArray"/>
|
|
<body>
|
|
<![CDATA[
|
|
return aHitArray && (aHitArray.length > 1 || aHitArray.length == 1 &&
|
|
!aHitArray[0].isUsed);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
</implementation>
|
|
</binding>
|
|
|
|
|
|
<!-- BASE binding for NATIVE WIDGET CONTROL -->
|
|
<binding id="nativewidget-select">
|
|
|
|
<implementation>
|
|
<!-- public -->
|
|
<method name="selectItem">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aDoSelect"/>
|
|
<body>
|
|
var index = this.getIndexByElm(aItem);
|
|
if (index != -1) {
|
|
var listElm = this.nodeList[index];
|
|
this.selectItemNative(listElm.nativeElm, aDoSelect);
|
|
listElm.wasSelected = aDoSelect;
|
|
}
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isItemSelected">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
var index = this.getIndexByElm(aItem);
|
|
if (index != -1)
|
|
return this.isItemSelectedNative(this.nodeList[index].nativeElm);
|
|
return false;
|
|
</body>
|
|
</method>
|
|
|
|
<method name="disableItem">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aDoDisable"/>
|
|
<body>
|
|
var index = this.getIndexByElm(aItem);
|
|
if (index != -1)
|
|
this.disableItemNative(this.nodeList[index].nativeElm, aDoDisable);
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isItemDisabled">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
var index = this.getIndexByElm(aItem);
|
|
if (index != -1)
|
|
return this.isItemDisabledNative(this.nodeList[index].nativeElm);
|
|
return false;
|
|
</body>
|
|
</method>
|
|
|
|
<method name="focus">
|
|
<body>
|
|
this.control.focus();
|
|
</body>
|
|
</method>
|
|
|
|
<method name="getFreeEntryValues">
|
|
<body>
|
|
return "";
|
|
</body>
|
|
</method>
|
|
|
|
<method name="allowFreeEntry">
|
|
<parameter name="aAllowed"/>
|
|
<body>
|
|
return false;
|
|
</body>
|
|
</method>
|
|
|
|
<method name="appendFreeEntryItem">
|
|
<parameter name="aValue"/>
|
|
<body>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="setLabelFor">
|
|
<parameter name="aNode"/>
|
|
<parameter name="aLabelNode"/>
|
|
<body>
|
|
var index = this.getIndexByElm(aNode);
|
|
if (index != -1)
|
|
this.setLabelForNative(this.nodeList[index].nativeElm, aLabelNode);
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Create and appends native element.
|
|
|
|
@param aElm - the given element
|
|
@param aParentIndex - the index of parent element
|
|
@param aPrevSiblingIndex - the index of previous sibling element
|
|
|
|
@note - previous sibling elements must be in native widget already
|
|
-->
|
|
<method name="appendElm">
|
|
<parameter name="aElm"/>
|
|
<parameter name="aParentIndex"/>
|
|
<parameter name="aPrevSiblingIndex"/>
|
|
<body>
|
|
<![CDATA[
|
|
var parentListElm = this.nodeList[aParentIndex];
|
|
var nativeParentElm = parentListElm.nativeElm;
|
|
|
|
var isItemElm = {value: false};
|
|
var nativeElm = this.createNativeElm(aElm, nativeParentElm, null,
|
|
isItemElm);
|
|
if (!nativeElm)
|
|
return -1;
|
|
|
|
var parentElm = parentListElm.elm;
|
|
var parentLevel = parentListElm.level;
|
|
|
|
var listElm = {
|
|
elm: aElm,
|
|
nativeElm: nativeElm,
|
|
level: parentLevel + 1,
|
|
};
|
|
|
|
if (isItemElm.value)
|
|
listElm.wasSelected = false;
|
|
|
|
var index = -1;
|
|
if (aPrevSiblingIndex == null || aPrevSiblingIndex == -1)
|
|
index = aParentIndex + 1;
|
|
else
|
|
index = aPrevSiblingIndex + 1;
|
|
|
|
this.nodeList.splice(index, 0, listElm);
|
|
|
|
return index;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Create and insert native element.
|
|
|
|
@param aElm - the given element
|
|
@param aParent - parent of the given element
|
|
-->
|
|
<method name="insertElm">
|
|
<parameter name="aElm"/>
|
|
<parameter name="aParent"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (!aParent)
|
|
return this.appendTopElm(aElm);
|
|
|
|
var parentIndex = this.getIndexByElm(aParent);
|
|
if (parentIndex == -1)
|
|
return -1;
|
|
|
|
var nativeParent = this.nodeList[parentIndex].nativeElm;
|
|
|
|
var index = this.getInsertionIndexForElm(aElm, parentIndex);
|
|
if (index == -1)
|
|
return;
|
|
|
|
var isItemElm = {value: false};
|
|
var nextElm = aElm.nextSibling ? this.nodeList[index].nativeElm : null;
|
|
|
|
var nativeElm = this.createNativeElm(aElm, nativeParent, nextElm,
|
|
isItemElm);
|
|
if (!nativeElm)
|
|
return -1;
|
|
|
|
var parentLevel = this.nodeList[parentIndex].level;
|
|
var listElm = {
|
|
elm: aElm,
|
|
nativeElm: nativeElm,
|
|
level: parentLevel + 1,
|
|
};
|
|
|
|
if (isItemElm.value)
|
|
listElm.wasSelected = false;
|
|
|
|
this.nodeList.splice(index, 0, listElm);
|
|
|
|
return index;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Remove native node and its children. -->
|
|
<method name="removeNativeElm">
|
|
<parameter name="aElm"/>
|
|
<body>
|
|
<![CDATA[
|
|
var index = this.getIndexByElm(aElm);
|
|
if (index == -1)
|
|
return;
|
|
|
|
var nativeElm = this.nodeList[index].nativeElm;
|
|
nativeElm.parentNode.removeChild(nativeElm);
|
|
|
|
var childCount = 1;
|
|
var level = this.nodeList[index].level;
|
|
for (var i = index + 1; i < this.nodeList.length; ++i) {
|
|
var childLevel = this.nodeList[i].level;
|
|
if (childLevel <= level)
|
|
break;
|
|
|
|
childCount++;
|
|
}
|
|
|
|
this.nodeList.splice(index, childCount);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- overrideable -->
|
|
<method name="disableItemNative">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aDoDisable"/>
|
|
<body>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isItemDisabledNative">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
return false;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- private -->
|
|
<method name="appendTopElm">
|
|
<parameter name="aSelect"/>
|
|
<body>
|
|
var listElm = {
|
|
elm: aSelect,
|
|
nativeElm: this.control,
|
|
level: 0,
|
|
wasSelected: false
|
|
};
|
|
|
|
this.nodeList = [listElm];
|
|
this.selectControl = aSelect;
|
|
return 0;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Create and append native element.
|
|
|
|
@param aElm - the given element, this is either item or choices element
|
|
@param aParentElm - parent element of the given element
|
|
@param aNextElm - next sibling of the given element if any
|
|
@param aIsItemElm - [out] returns true if the given element is item
|
|
-->
|
|
<method name="createNativeElm">
|
|
<parameter name="aElm"/>
|
|
<parameter name="aParentElm"/>
|
|
<parameter name="aNextElm"/>
|
|
<parameter name="aIsItemElm"/>
|
|
<body>
|
|
switch (aElm.localName) {
|
|
case "choices":
|
|
aIsItemElm.value = false;
|
|
var group = this.createGroupElm(aParentElm, aNextElm,
|
|
this.getLabelFor(aElm));
|
|
return group ? group : this.control;
|
|
case "item":
|
|
aIsItemElm.value = true;
|
|
return this.createItemElm(aParentElm, aNextElm,
|
|
this.getLabelFor(aElm));
|
|
}
|
|
return null;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return label element for the given element -->
|
|
<method name="getLabelFor">
|
|
<parameter name="aNode"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (!aNode)
|
|
return null;
|
|
|
|
for (var child = aNode.firstChild; child; child = child.nextSibling) {
|
|
if (child.namespaceURI == this.XFORMS_NS) {
|
|
if (child.localName == "label")
|
|
return child;
|
|
}
|
|
}
|
|
return null;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Returns index for the given element.
|
|
@param aElm - the given element
|
|
@return - index of the given element
|
|
-->
|
|
<method name="getIndexByElm">
|
|
<parameter name="aElm"/>
|
|
<body>
|
|
<![CDATA[
|
|
for (var i = 0; i < this.nodeList.length; ++i) {
|
|
if (this.nodeList[i].elm == aElm)
|
|
return i;
|
|
}
|
|
|
|
dump("ERROR: selectsnw binding, can't locate the given element in the node list\n");
|
|
return -1;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return index that the given element will be inserted at
|
|
@param aElm - the inserted element
|
|
@param aParentIndex - index of parent element
|
|
@return - index for inserted element
|
|
-->
|
|
<method name="getInsertionIndexForElm">
|
|
<parameter name="aElm"/>
|
|
<parameter name="aParentIndex"/>
|
|
<body>
|
|
<![CDATA[
|
|
var delta = 0;
|
|
var elm = aElm;
|
|
while (elm = elm.previousSibling)
|
|
delta++;
|
|
|
|
var parentLevel = this.nodeList[aParentIndex].level;
|
|
var index = aParentIndex + 1;
|
|
var length = this.nodeList.length;
|
|
for (; index < length && delta; ++index) {
|
|
if (this.nodeList[index].level == parentLevel + 1)
|
|
delta--;
|
|
}
|
|
|
|
if (!delta)
|
|
return index;
|
|
|
|
dump("ERROR: selectsnw binding, can't find insertion point in the node list for the given element\n");
|
|
return -1;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Fires 'xforms-select'/'xforms-deselect' events and updates instance
|
|
data. The method is used by bindings of native widget implementation.
|
|
|
|
@param aIncremental - specifies if update is incremental
|
|
-->
|
|
<method name="updateInstanceData">
|
|
<parameter name="aIncremental"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (!this.selectControl)
|
|
return;
|
|
|
|
if (aIncremental) {
|
|
var deferredEventTargets = [];
|
|
for (var index = 0; index < this.nodeList.length; ++index) {
|
|
var listElm = this.nodeList[index];
|
|
if (!("wasSelected" in listElm))
|
|
continue;
|
|
|
|
// event state can be either:
|
|
// 0 - the state of element wasn't changed
|
|
// 1 - the element was selected
|
|
// 2 - the element was unselected
|
|
var eventState = 0;
|
|
|
|
var selected = this.isItemSelectedNative(listElm.nativeElm);
|
|
if (listElm.wasSelected && !selected)
|
|
eventState = 1;
|
|
else if (!listElm.wasSelected && selected)
|
|
eventState = 2;
|
|
|
|
if (!eventState)
|
|
continue;
|
|
|
|
var target = listElm.elm;
|
|
|
|
// First we should send 'xforms-unselect' events for all
|
|
// unselected item elements and then 'xforms-select' events.
|
|
if (eventState == 1) {
|
|
listElm.wasSelected = false;
|
|
this.selectControl.
|
|
dispatchXFormsNotificationEvent("xforms-deselect", target);
|
|
} else {
|
|
listElm.wasSelected = true;
|
|
deferredEventTargets.push(target);
|
|
}
|
|
}
|
|
|
|
for (var index = 0; index < deferredEventTargets.length; ++index) {
|
|
this.selectControl.dispatchXFormsNotificationEvent(
|
|
"xforms-select", deferredEventTargets[index]);
|
|
|
|
}
|
|
}
|
|
|
|
this.selectControl.updateInstanceData(aIncremental);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Returns the underlying control (native widget) -->
|
|
<property name="control" readonly="true">
|
|
<getter>
|
|
if (!this._control)
|
|
this._control = this.ownerDocument.
|
|
getAnonymousElementByAttribute(this, "anonid", "control");
|
|
return this._control;
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- Reference on xforms 'select'/'select1' element -->
|
|
<field name="selectControl">null</field>
|
|
|
|
<!-- Contains a list of objects each of them has the following properties:
|
|
elm - xforms element (may be select/select1, item or choices)
|
|
nativeElm - native element that represents related xforms element
|
|
level - level of elements hierarchy (level of select/select1 is 0)
|
|
wasSelected - if 'elm' property contains item element then this property
|
|
is presented and takes boolean value
|
|
|
|
First object in the list is for 'select'/'select1' element.
|
|
-->
|
|
<field name="nodeList">new Array()</field>
|
|
|
|
<!-- Debug method. Dumps current state of node list into console. -->
|
|
<method name="dumpNodeList">
|
|
<body>
|
|
<![CDATA[
|
|
dump("\n\n");
|
|
for (var i = 0; i < this.nodeList.length; ++i) {
|
|
var obj = this.nodeList[i];
|
|
for (var j = 0; j < obj.level; j++)
|
|
dump(" ");
|
|
dump("elm: " + obj.elm.localName + "\n");
|
|
|
|
for (var j = 0; j < obj.level; j++)
|
|
dump(" ");
|
|
dump("native elm: " + obj.nativeElm.localName);
|
|
var label = this.getLabelFor(obj.elm);
|
|
if (label)
|
|
dump(", label: " + label.textValue);
|
|
dump("\n");
|
|
}
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<property name="XFORMS_NS" readonly="true"
|
|
onget="return 'http://www.w3.org/2002/xforms';"/>
|
|
|
|
<property name="XHTML_NS" readonly="true"
|
|
onget="return 'http://www.w3.org/1999/xhtml';"/>
|
|
|
|
<property name="XUL_NS" readonly="true"
|
|
onget="return 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';"/>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="focus" phase="capturing">
|
|
if (this.selectControl)
|
|
this.selectControl.dispatchDOMUIEvent("DOMFocusIn");
|
|
</handler>
|
|
|
|
<handler event="blur" phase="capturing">
|
|
if (this.selectControl)
|
|
this.selectControl.dispatchDOMUIEvent("DOMFocusOut");
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
</bindings>
|
|
|