967 lines
32 KiB
XML
967 lines
32 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) 2006
|
|
- 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="xformsSelectsBindings"
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
|
|
|
<!--
|
|
This file implements the "abstract" UI classes for XForms select/select1
|
|
controls. Bindings defined here are base bindings that are used for two
|
|
approaches of select/select1 elements implementations:
|
|
1. Every item or choices element is visible and represented. An example is
|
|
the controls for XHTML in "selects-xhtml.xml" file
|
|
2. Using of native widget that represents select/select1 elements. An example
|
|
is the controls for XHTML in "selectsnw-xhtml.xml" file.
|
|
-->
|
|
|
|
<!-- BASE for select/select1 elements. -->
|
|
<binding id="selectcontrols-base"
|
|
extends="chrome://xforms/content/xforms.xml#xformswidget-base">
|
|
|
|
<implementation implements="nsIAccessibleProvider">
|
|
|
|
<!-- nsIXFormsUIWidget -->
|
|
<method name="refresh">
|
|
<body>
|
|
<![CDATA[
|
|
var boundNode = this.accessors.getBoundNode();
|
|
if (!boundNode)
|
|
return null;
|
|
|
|
// Make sure that 'getNodesArray' method is called before
|
|
// 'getValuesArray' method because nodes array returned by
|
|
// 'getNodesArray' is used by 'getValuesArray' method.
|
|
this.nodes = this.getNodesArray(boundNode);
|
|
this.values = this.getValuesArray(boundNode);
|
|
|
|
this.traverseItems(this, this.selectItemElements);
|
|
if (this.freeEntryAllowed)
|
|
this.selectFreeEntryItemElements();
|
|
|
|
var outOfRange = this.isOutOfRange(this.values) ||
|
|
this.isOutOfRange(this.nodes);
|
|
if (this.outOfRange == null || this.outOfRange != outOfRange) {
|
|
this.accessors.setInRange(!outOfRange);
|
|
this.outOfRange = outOfRange;
|
|
}
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="focus">
|
|
<body>
|
|
function focusItem(aItem) {
|
|
var disabled = this.isItemMarkedDisabled(aItem);
|
|
if (!disabled)
|
|
this.focusItem(aItem);
|
|
return disabled;
|
|
}
|
|
this.traverseItems(this, focusItem);
|
|
</body>
|
|
</method>
|
|
|
|
<!-- public -->
|
|
<property name="incremental">
|
|
<getter>
|
|
return this.getAttribute("incremental") != "false";
|
|
</getter>
|
|
<setter>
|
|
if (!val)
|
|
this.setAttribute("incremental", "false");
|
|
else
|
|
this.removeAttribute("incremental");
|
|
</setter>
|
|
</property>
|
|
|
|
<property name="selection">
|
|
<getter>
|
|
return this.getAttribute("selection");
|
|
</getter>
|
|
<setter>
|
|
this.setAttribute("selection", val);
|
|
this.freeEntryAllowed = this.allowFreeEntry(val == "open");
|
|
</setter>
|
|
</property>
|
|
|
|
<!-- private -->
|
|
<!-- Run through xforms:item elements and select them if needed. If
|
|
xforms:item element contains xforms:value element value of which is
|
|
matched with item of given values array or if it contains xforms:copy
|
|
element value of which is matched with item of given nodes array then
|
|
that xforms:item element will be selected.
|
|
The method is used in conjunction with traverseItems method.
|
|
|
|
@param aItem - current traversed item element
|
|
-->
|
|
<method name="selectItemElements">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
<![CDATA[
|
|
this.markItemDisabled(aItem, this.accessors.isReadonly());
|
|
|
|
if (aItem.isCopyItem) {
|
|
if (!this.nodes || !aItem.copyNode) {
|
|
// aNodes is empty only if select controls is bound to non element
|
|
// node. We just disable item element since it's value can't be
|
|
// saved in bound node.
|
|
this.markItemDisabled(aItem, true);
|
|
return true;
|
|
}
|
|
|
|
var length = this.nodes.length;
|
|
for (var i = 0; i < length; i++) {
|
|
if (aItem.copyNodeEquals(this.nodes[i].node)) {
|
|
this.markItemSelected(aItem, true);
|
|
this.nodes[i].isUsed = true;
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
var length = this.values.length;
|
|
for (var i = 0; i < length; i++) {
|
|
if (this.values[i].value == aItem.value) {
|
|
this.markItemSelected(aItem, true);
|
|
this.values[i].isUsed = true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.isItemMarkedSelected(aItem))
|
|
this.markItemSelected(aItem, false);
|
|
|
|
return true;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return array of values each of them item elemnent should be selected
|
|
for. -->
|
|
<method name="getValuesArray">
|
|
<parameter name="aNode"/>
|
|
<body>
|
|
<![CDATA[
|
|
var nsIDOMNode = Components.interfaces.nsIDOMNode;
|
|
var whiteSpaceExpr = /\n|\t|\r/g;
|
|
|
|
var array = [];
|
|
if (aNode.nodeType != nsIDOMNode.ELEMENT_NODE) {
|
|
if (/\S/.test(aNode.nodeValue)) {
|
|
var values = this.getValuesArrayFor(aNode.nodeValue,
|
|
whiteSpaceExpr);
|
|
|
|
for (var i = 0; i < values.length; i++)
|
|
array.push({value: values[i], isUsed: false});
|
|
} else {
|
|
array.push({value: "", isUsed: false});
|
|
}
|
|
return array;
|
|
}
|
|
|
|
if (!aNode.hasChildNodes()) {
|
|
array.push({value: "", isUsed: false});
|
|
return array;
|
|
}
|
|
|
|
for (var child = aNode.firstChild; child; child = child.nextSibling) {
|
|
if ((child.nodeType == nsIDOMNode.TEXT_NODE ||
|
|
child.nodeType == nsIDOMNode.CDATA_SECTION_NODE) &&
|
|
child.nodeValue) {
|
|
if (/\S/.test(child.nodeValue)) {
|
|
var values = this.getValuesArrayFor(child.nodeValue,
|
|
whiteSpaceExpr)
|
|
|
|
for (var i = 0; i < values.length; i++)
|
|
array.push({value: values[i], isUsed: false});
|
|
} else if (!array.length && !this.nodes) {
|
|
array.push({value: "", isUsed: false});
|
|
}
|
|
}
|
|
}
|
|
return array;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Exctact values from given string and return array of values. Should
|
|
be implemented by successor bindings. -->
|
|
<method name="getValuesArrayFor">
|
|
<parameter name="aString"/>
|
|
<parameter name="aWhiteSpaceExpr"/>
|
|
<body>
|
|
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return array of copy nodes each of them item element should be
|
|
selected for. If bound node is not element node then return null. -->
|
|
<method name="getNodesArray">
|
|
<parameter name="aNode"/>
|
|
<body>
|
|
var nsIDOMNode = Components.interfaces.nsIDOMNode;
|
|
if (aNode.nodeType != nsIDOMNode.ELEMENT_NODE)
|
|
return;
|
|
|
|
var array = [];
|
|
for (var child = aNode.firstChild; child; child = child.nextSibling) {
|
|
if (child.nodeType == nsIDOMNode.ELEMENT_NODE)
|
|
array.push({node: child, isUsed: false});
|
|
}
|
|
|
|
return array;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return true if instance data can't be presented by select element.
|
|
Should be implemented by successors bindings. -->
|
|
<method name="isOutOfRange">
|
|
<body>
|
|
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Update instance node. This method is called when selection of select
|
|
element is changed.
|
|
|
|
@param aIncremental - specifies if instance node should be updated
|
|
incrementally.
|
|
-->
|
|
<method name="updateInstanceData">
|
|
<parameter name="aIncremental"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (aIncremental != this.incremental)
|
|
return;
|
|
|
|
var node = this.accessors.getBoundNode();
|
|
if (!node)
|
|
return;
|
|
|
|
node = node.cloneNode(false);
|
|
node.textContent = "";
|
|
|
|
var forceRebuild = {value: false};
|
|
this.traverseItems(this, this.buildInstanceData, node, forceRebuild);
|
|
if (this.freeEntryAllowed)
|
|
this.appendValueForInstanceNode(node, this.getFreeEntryValues());
|
|
|
|
var nsIDOMNode = Components.interfaces.nsIDOMNode;
|
|
|
|
if (node.nodeType != nsIDOMNode.ELEMENT_NODE || !forceRebuild.value) {
|
|
if (node.firstChild &&
|
|
(node.firstChild.nodeType == nsIDOMNode.TEXT_NODE ||
|
|
node.firstChild.nodeType == nsIDOMNode.CDATA_SECTION_NODE))
|
|
this.accessors.setValue(node.firstChild.nodeValue);
|
|
else
|
|
this.accessors.setValue("");
|
|
} else {
|
|
this.accessors.setContent(node, true);
|
|
}
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Run through item elements and build content of instance node for
|
|
selected item elements.
|
|
|
|
@param aItem - currently traversed item element
|
|
@param aInstanceNode - new generated instance node
|
|
@param aForceRebuild - object, its 'value' property should have value
|
|
'true' if copy item element was been selected or
|
|
deselected.
|
|
-->
|
|
<method name="buildInstanceData">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aInstanceNode"/>
|
|
<parameter name="aForceRebuild"/>
|
|
<body>
|
|
<![CDATA[
|
|
const nsIDOMNode = Components.interfaces.nsIDOMNode;
|
|
|
|
if (aItem.isCopyItem) {
|
|
var wasSelected = false;
|
|
if (this.nodes) {
|
|
var length = this.nodes.length;
|
|
for (var i = 0; i < length; i++) {
|
|
if (aItem.copyNodeEquals(this.nodes[i].node)) {
|
|
wasSelected = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (wasSelected != this.isItemMarkedSelected(aItem))
|
|
aForceRebuild.value = true;
|
|
|
|
if (this.isItemMarkedSelected(aItem)) {
|
|
if (aInstanceNode.nodeType != nsIDOMNode.ELEMENT_NODE) {
|
|
// Per specs we should fire 'xforms-binding-exception' event if
|
|
// bound node is not element and copy item is selected.
|
|
this.dispatchXFormsNotificationEvent("xforms-binding-exception",
|
|
this);
|
|
|
|
// We should probably un-select the item so that the list
|
|
// of selected data is accurate. This WON'T cause a
|
|
// xforms-select/deselect to fire. Since the user just selected
|
|
// this item and we are automatically deselecting it from
|
|
// underneath the user, we'll treat it like nothing happened.
|
|
this.markItemSelected(aItem, false);
|
|
return true;
|
|
}
|
|
|
|
var importedNode =
|
|
aInstanceNode.ownerDocument.importNode(aItem.copyNode, true);
|
|
aInstanceNode.appendChild(importedNode);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (!this.isItemMarkedSelected(aItem))
|
|
return true;
|
|
|
|
if (aInstanceNode.nodeType != nsIDOMNode.ELEMENT_NODE) {
|
|
if (aInstanceNode.textContent)
|
|
aInstanceNode.textContent += " ";
|
|
aInstanceNode.textContent += aItem.value;
|
|
return true;
|
|
}
|
|
|
|
this.appendValueForInstanceNode(aInstanceNode, aItem.value);
|
|
return true;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Append the given value for the instance node
|
|
@param aInstanceNode - the given instance node
|
|
@param aValue - appended value.
|
|
-->
|
|
<method name="appendValueForInstanceNode">
|
|
<parameter name="aInstanceNode"/>
|
|
<parameter name="aValue"/>
|
|
<body>
|
|
<![CDATA[
|
|
const nsIDOMNode = Components.interfaces.nsIDOMNode;
|
|
|
|
var fchild = aInstanceNode.firstChild;
|
|
if (fchild && (fchild.nodeType == nsIDOMNode.TEXT_NODE ||
|
|
fchild.nodeType == nsIDOMNode.CDATA_SECTION_NODE)) {
|
|
if (fchild.nodeValue)
|
|
fchild.nodeValue += " ";
|
|
fchild.nodeValue += aValue;
|
|
} else {
|
|
var textnode =
|
|
aInstanceNode.ownerDocument.createTextNode(aValue);
|
|
if (fchild)
|
|
aInstanceNode.insertBefore(textnode, fchild);
|
|
else
|
|
aInstanceNode.appendChild(textnode);
|
|
}
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Run through select child elements and invokes given function for
|
|
every item element until given function retunrs false.
|
|
|
|
@param aContextNode - current select child node
|
|
@param aFunc - the function that is invoked if current node is item
|
|
element, if function returns true then traversing is
|
|
stopped
|
|
@param aFuncArg1 - 1st argument that is passed to function
|
|
@param aFuncArg2 - 2nd argument that is passed to function
|
|
@param aUpDirection - specifies direction of items navigation
|
|
-->
|
|
<method name="traverseItems">
|
|
<parameter name="aContextNode"/>
|
|
<parameter name="aFunc"/>
|
|
<parameter name="aFuncArg1"/>
|
|
<parameter name="aFuncArg2"/>
|
|
<parameter name="aUpDirection"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (aContextNode.namespaceURI != this.XFORMS_NS)
|
|
return true;
|
|
|
|
var container;
|
|
switch (aContextNode.localName) {
|
|
case "select":
|
|
case "select1":
|
|
case "choices":
|
|
container = aContextNode;
|
|
break;
|
|
case "itemset":
|
|
container = aContextNode.anonymousItemSetContent;
|
|
break;
|
|
case "item":
|
|
var item = aContextNode.
|
|
QueryInterface(Components.interfaces.nsIXFormsItemElement);
|
|
if (!aFunc.call(this, item, aFuncArg1, aFuncArg2))
|
|
return false;
|
|
}
|
|
|
|
if (container) {
|
|
var child =
|
|
aUpDirection ? container.lastChild : container.firstChild;
|
|
while (child) {
|
|
var res = this.traverseItems(child, aFunc, aFuncArg1, aFuncArg2,
|
|
aUpDirection);
|
|
if (!res)
|
|
return false;
|
|
child = aUpDirection ? child.previousSibling : child.nextSibling;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Cycally traverse item elements for specified direction and invokes
|
|
given function for every item element.
|
|
|
|
@param aItemNode - start item element
|
|
@param aUpDirection - if true then then item elements are traversed in
|
|
up direction
|
|
@param aFunc, aFuncArg1, aFuncArg2 - invoked function and its arguments
|
|
@param aCurrNode - current traversed node, used internally
|
|
-->
|
|
<method name="cycleTraverseItems">
|
|
<parameter name="aItemNode"/>
|
|
<parameter name="aUpDirection"/>
|
|
<parameter name="aFunc"/>
|
|
<parameter name="aFuncArg1"/>
|
|
<parameter name="aFuncArg2"/>
|
|
<parameter name="aCurrNode"/>
|
|
<body>
|
|
if (aCurrNode == aItemNode)
|
|
return false;
|
|
|
|
if (!aCurrNode) {
|
|
if (aItemNode.namespaceURI != this.XFORMS_NS ||
|
|
aItemNode.localName != "item")
|
|
return false;
|
|
aCurrNode = aItemNode;
|
|
}
|
|
|
|
var next = aUpDirection ? aCurrNode.previousSibling :
|
|
aCurrNode.nextSibling;
|
|
if (next) {
|
|
var res = this.traverseItems(next, aFunc, aFuncArg1, aFuncArg2,
|
|
aUpDirection);
|
|
if (!res)
|
|
return false;
|
|
|
|
return this.cycleTraverseItems(aItemNode, aUpDirection, aFunc,
|
|
aFuncArg1, aFuncArg2, next);
|
|
}
|
|
|
|
var parent = aCurrNode;
|
|
while (parent = parent.parentNode) {
|
|
if (parent.namespaceURI == this.XFORMS_NS) {
|
|
switch (parent.localName) {
|
|
case "choices":
|
|
case "itemset":
|
|
next = parent;
|
|
break;
|
|
case "select":
|
|
case "select1":
|
|
next = aUpDirection ? parent.lastChild : parent.firstChild;
|
|
break;
|
|
}
|
|
if (next)
|
|
return this.cycleTraverseItems(aItemNode, aUpDirection, aFunc,
|
|
aFuncArg1, aFuncArg2, next);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return values of free entry. The method implementation is a stub and
|
|
it should be removed when all native controls will support
|
|
@selection="open".
|
|
|
|
@note - should be overriden by implementation binding
|
|
-->
|
|
<method name="getFreeEntryValues">
|
|
<body>
|
|
return "";
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Allow free entry. The method implementation is a stub and it should
|
|
be removed when all native controls will support @selection="open".
|
|
|
|
@return - true if free entries has been allowed
|
|
@note - should be overriden by implementation binding
|
|
-->
|
|
<method name="allowFreeEntry">
|
|
<parameter name="aAllowed"/>
|
|
<body>
|
|
return false;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Append and select free entry item. The implementations of this method
|
|
for xf:select should consider the scenario where several items may have
|
|
been selected by the user in addition to the user typing several values
|
|
directly into the editable field. In that case, these additional values
|
|
should be appended to the control's value and the items that represent
|
|
these additional values should be selected. In the case of
|
|
implementations for xf:select1, we'll assume that the widget that
|
|
represents the select1 will deselect the currently selected item if a
|
|
user types in the editable field. So the free entry value, if present,
|
|
is the only value that the control can have.
|
|
|
|
The method implementation is a stub and it should be removed when all
|
|
native controls will support @selection="open".
|
|
|
|
@param aValue - the value of free entry item
|
|
@note - should be overriden by implementation binding
|
|
-->
|
|
<method name="appendFreeEntryItem">
|
|
<parameter name="aValue"/>
|
|
<body>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Select/Unselect item element.
|
|
|
|
@param aItem - the given item element
|
|
@param aIsSelected - if true then item should be selected, otherwise
|
|
unselected
|
|
-->
|
|
<method name="markItemSelected">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aIsSelected"/>
|
|
<body>
|
|
if (aItem)
|
|
aItem.selected = aIsSelected;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return true if item is selected
|
|
|
|
@param aItem - the given item.
|
|
-->
|
|
<method name="isItemMarkedSelected">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
return aItem ? aItem.selected : false;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Disable/enable the given item element
|
|
|
|
@param aItem - the given item
|
|
@param aIsDisabled - if true then item should be disabled, otherwise
|
|
enabled
|
|
-->
|
|
<method name="markItemDisabled">
|
|
<parameter name="aItem"/>
|
|
<parameter name="aIsDisabled"/>
|
|
<body>
|
|
if (aItem)
|
|
aItem.disabled = aIsDisabled;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return true if the given item element disabled
|
|
|
|
@param aItem - the given item
|
|
-->
|
|
<method name="isItemMarkedDisabled">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
return aItem ? aItem.disabled : false;
|
|
</body>
|
|
</method>
|
|
|
|
<method name="focusItem">
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
if (aItem)
|
|
aItem.focus();
|
|
</body>
|
|
</method>
|
|
|
|
<constructor>
|
|
this.freeEntryAllowed = this.allowFreeEntry(this.selection == "open");
|
|
</constructor>
|
|
|
|
<!-- Storage for previous value of 'in-range' state of select element -->
|
|
<field name="outOfRange">null</field>
|
|
|
|
<!-- Specifies whether free entry is allowed by certain implementation of
|
|
select/select1 element. -->
|
|
<field name="freeEntryAllowed">false</field>
|
|
|
|
<!-- Arrays of selected values and nodes that combine to build the content
|
|
of the bound instance node. -->
|
|
<field name="values">null</field>
|
|
<field name="nodes">null</field>
|
|
</implementation>
|
|
</binding>
|
|
|
|
|
|
<!-- SELECT: BASE
|
|
Note, keep synchronized with 'selectsnw.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="updateInstanceNodeByItem">
|
|
<parameter name="aIncremental"/>
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (aIncremental) {
|
|
// Fire 'select'/'deselect' only if user changed the select value.
|
|
|
|
// per errata for XForms 1.0 second edition, we send the event to
|
|
// the item even if it is contained inside an itemset
|
|
|
|
var eventName = this.isItemMarkedSelected(aItem) ?
|
|
"xforms-select" : "xforms-deselect";
|
|
this.dispatchXFormsNotificationEvent(eventName, aItem);
|
|
}
|
|
|
|
this.updateInstanceData(aIncremental);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="selectFreeEntryItemElements">
|
|
<body>
|
|
<![CDATA[
|
|
var length = this.values.length;
|
|
for (var i = 0; i < 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) {
|
|
if (this.isItemMarkedSelected(aItem))
|
|
aSelectedItem.value = aItem;
|
|
return !this.isItemMarkedSelected(aItem);
|
|
}
|
|
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="updateInstanceNodeByItem">
|
|
<parameter name="aIncremental"/>
|
|
<parameter name="aItem"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (aIncremental) {
|
|
// Fire 'select'/'deselect' only if user changed the select1 value.
|
|
|
|
// per errata for XForms 1.0 second edition, we send the event
|
|
// to the item even if it is contained by an itemset
|
|
|
|
function _unselectItems(aItem, aNewSelectedItem, aTarget) {
|
|
if (aItem != aNewSelectedItem) {
|
|
if (this.isItemMarkedSelected(aItem)) {
|
|
this.markItemSelected(aItem, false);
|
|
this.dispatchXFormsNotificationEvent("xforms-deselect",
|
|
aTarget);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
this.traverseItems(this, _unselectItems, aItem, aItem);
|
|
|
|
var eventName = this.isItemMarkedSelected(aItem) ?
|
|
"xforms-select" : "xforms-deselect";
|
|
this.dispatchXFormsNotificationEvent(eventName, aItem);
|
|
}
|
|
|
|
this.updateInstanceData(aIncremental);
|
|
]]>
|
|
</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>
|
|
|
|
|
|
<!-- ITEMSET -->
|
|
<binding id="itemset"
|
|
extends="chrome://xforms/content/xforms.xml#xformswidget-base">
|
|
<content>
|
|
<html:div style="display:none;">
|
|
<children/>
|
|
</html:div>
|
|
<html:div anonid="insertion"/>
|
|
</content>
|
|
|
|
<implementation implements="nsIXFormsItemSetUIElement">
|
|
<field name="_anonymousItemSetContent">null</field>
|
|
|
|
<property name="anonymousItemSetContent" readonly="true">
|
|
<getter>
|
|
if (!this._anonymousItemSetContent) {
|
|
this._anonymousItemSetContent =
|
|
document.getAnonymousElementByAttribute(this, "anonid", "insertion");
|
|
}
|
|
return this._anonymousItemSetContent;
|
|
</getter>
|
|
</property>
|
|
</implementation>
|
|
</binding>
|
|
|
|
|
|
<!-- ITEM -->
|
|
<binding id="select-item-base"
|
|
extends="chrome://xforms/content/xforms.xml#xformswidget-general">
|
|
|
|
<implementation>
|
|
<!-- interface -->
|
|
<property name="selected"
|
|
onget="throw Error(Components.results.NS_ERROR_NOT_IMPLEMENTED);"
|
|
onset="throw Error(Components.results.NS_ERROR_NOT_IMPLEMENTED);"/>
|
|
|
|
<property name="disabled"
|
|
onget="throw Error(Components.results.NS_ERROR_NOT_IMPLEMENTED);"
|
|
onset="throw Error(Components.results.NS_ERROR_NOT_IMPLEMENTED);"/>
|
|
|
|
<method name="focus">
|
|
<body>
|
|
this.control.focus();
|
|
</body>
|
|
</method>
|
|
|
|
<!-- successor's interface -->
|
|
<method name="updateInstanceData">
|
|
<parameter name="aIncremental"/>
|
|
<body>
|
|
if (this.selectControl)
|
|
this.selectControl.updateInstanceNodeByItem(aIncremental, this);
|
|
</body>
|
|
</method>
|
|
|
|
<!-- private -->
|
|
<property name="selectControl" readonly="true">
|
|
<getter>
|
|
<![CDATA[
|
|
if (!this._selectControl) {
|
|
var node = this;
|
|
|
|
while (node = node.parentNode) {
|
|
if (node.namespaceURI == this.XFORMS_NS &&
|
|
(node.localName == "select" || node.localName == "select1")) {
|
|
this._selectControl = node;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return this._selectControl;
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
<field name="_selectControl">null</field>
|
|
</implementation>
|
|
</binding>
|
|
|
|
|
|
<!-- CHOICES element of FULL APPEARANCE SELECT/SELECT1 -->
|
|
<binding id="choices">
|
|
<implementation implements="nsIAccessibleProvider">
|
|
<property name="accessibleType" readonly="true">
|
|
<getter>
|
|
return Components.interfaces.nsIAccessibleProvider.XFormsChoices;
|
|
</getter>
|
|
</property>
|
|
</implementation>
|
|
</binding>
|
|
|
|
</bindings>
|
|
|