allan%beaufour.dk 32530e598c [XForms] select1 .xf-value targets dropdown arrow. Bug 339200, r=smaug+aaronr
git-svn-id: svn://10.0.0.236/trunk@198448 18797224-902f-48f8-a5cc-f745e15eee43
2006-05-26 08:20:05 +00:00

1095 lines
38 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
- Olli Pettay
- Portions created by the Initial Developer are Copyright (C) 2005
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Olli Pettay <Olli.Pettay@helsinki.fi>
-
- 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="select1Bindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xforms="http://www.w3.org/2002/xforms">
<!-- select1 -->
<binding id="xformswidget-select1"
extends="chrome://xforms/content/xforms.xml#xformswidget-base">
<!-- The strange indentation is because of the whitespace nodes.-->
<content>
<children includes="label|hint"/>
<html:div class="-moz-xforms-select1-popup" anonid="popup"
onmouseover="this.parentNode.shouldHandleBlur = false;
this.parentNode.mouseOver(event);"
onmouseup="this.parentNode.mouseUp(event);"
onmouseout="this.parentNode.shouldHandleBlur = true;">
<children/>
</html:div>
<html:span class="-moz-select1-container"
anonid="container"><html:input
class="-moz-xforms-select1-input xf-value"
anonid="control"
xbl:inherits="accesskey"
onfocus="this.parentNode.parentNode.dispatchDOMUIEvent('DOMFocusIn')"
onblur="this.parentNode.parentNode.handleBlur(); this.parentNode.parentNode.dispatchDOMUIEvent('DOMFocusOut');"
onclick="this.parentNode.parentNode.handleControlClick();"
onkeypress="this.parentNode.parentNode.handleKeyPress(event);"
onkeyup="this.parentNode.parentNode.handleKeyUp(event);"
/><html:input class="-moz-xforms-select1-dropdown"
type="button"
anonid="dropmarker"
tabindex="-1"
onmousedown="this.parentNode.parentNode.shouldHandleBlur = false;"
onmouseup="this.parentNode.parentNode.shouldHandleBlur = true;"
onclick="this.parentNode.parentNode.togglePopup();
this.previousSibling.focus();"
/></html:span></content>
<implementation implements="nsIXFormsUIWidget">
<field name="_inputField">null</field>
<field name="_dropMarker">null</field>
<field name="_popup">null</field>
<field name="_container">null</field>
<field name="_width">-1</field>
<!-- This is either an nsIXFormsItemElement or null. -->
<field name="_selected">null</field>
<field name="_tmpSelected">null</field>
<field name="_lastSelectedItem">null</field>
<field name="popupOpen">false</field>
<field name="shouldHandleBlur">true</field>
<field name="_outOfRange">false</field>
<property name="selectionOpen" readonly="true">
<getter>
return this.getAttribute("selection") == "open";
</getter>
</property>
<property name="inputField" readonly="true">
<getter>
if (!this._inputField) {
this._inputField =
document.getAnonymousElementByAttribute(this, "anonid", "control");
}
return this._inputField;
</getter>
</property>
<property name="dropMarker" readonly="true">
<getter>
if (!this._dropMarker) {
this._dropMarker =
document.getAnonymousElementByAttribute(this, "anonid", "dropmarker");
}
return this._dropMarker;
</getter>
</property>
<property name="popup" readonly="true">
<getter>
if (!this._popup) {
this._popup =
document.getAnonymousElementByAttribute(this, "anonid", "popup");
}
return this._popup;
</getter>
</property>
<property name="container" readonly="true">
<getter>
if (!this._container) {
this._container =
document.getAnonymousElementByAttribute(this, "anonid", "container");
}
return this._container;
</getter>
</property>
<property name="incremental" readonly="true">
<getter>
<![CDATA[
// default is true
var incremental = true;
if (this.getAttribute("incremental") == "false") {
incremental = false;
}
return incremental;
]]>
</getter>
</property>
<method name="updateInputField">
<body>
<![CDATA[
if (this._selected) {
// Remove extra white space characters from the beginning of the label.
this.inputField.value = this._selected.labelText.replace(/^[\s\n]+/, "");
}
]]>
</body>
</method>
<method name="handleControlClick">
<parameter name="aEvent"/>
<body>
<![CDATA[
if (this.selectionOpen && !this._selected && this.incremental) {
this._handleSelection(false);
} else {
this.togglePopup();
}
]]>
</body>
</method>
<method name="handleKeyPress">
<parameter name="aEvent"/>
<body>
<![CDATA[
var key = aEvent.keyCode;
if (key == aEvent.DOM_VK_RETURN || key == aEvent.DOM_VK_ENTER) {
var open = this.popupOpen;
this.togglePopup();
if (open && this._selected) {
this.updateInputField();
if (this.incremental) {
this._handleSelection(true);
} else {
this.dispatchSelectEvents();
}
}
} else if (key == aEvent.DOM_VK_UP ||
key == aEvent.DOM_VK_DOWN) {
this.internalScroll(aEvent.keyCode == aEvent.DOM_VK_DOWN);
if (this._selected && this.popupOpen) {
var el = this._selected.QueryInterface(Components.interfaces.nsIDOMElement);
if ("scrollIntoView" in el) {
el.scrollIntoView(false);
}
}
if (!this.popupOpen && this.incremental) {
if (this._selected) {
this.updateInputField();
}
this._handleSelection(true);
}
} else if (key == aEvent.DOM_VK_TAB) {
// Hiding popup when user uses keyboard to focus out
// from <select1>. No need to update the value of the control
// in this case.
if (this._selected && this.popupOpen) {
this.hidePopup();
this._selected.setActive(false);
this._selected = this._tmpSelected;
this._tmpSelected = null;
if (this._selected) {
this._selected.setActive(true);
}
}
}
return true;
]]>
</body>
</method>
<method name="handleKeyUp">
<parameter name="aEvent"/>
<body>
<![CDATA[
// These events are handled in handleKeyPress...
if (aEvent.keyCode == aEvent.DOM_VK_RETURN ||
aEvent.keyCode == aEvent.DOM_VK_ENTER ||
aEvent.keyCode == aEvent.DOM_VK_UP ||
aEvent.keyCode == aEvent.DOM_VK_DOWN) {
return true;
}
// ..other key events are handled in keyUp, because otherwise
// this.inputField.value doesn't show the just updated value.
if (this.selectionOpen) {
if (this._selected) {
this._selected.setActive(false);
this._selected = null;
}
if (this.incremental) {
this._handleSelection(false);
}
}
return true;
]]>
</body>
</method>
<!-- This is used by internalScroll to find the next
selectable <item>. Returns a DOMElement or null. -->
<method name="findNextSelectable">
<parameter name="aNode"/>
<parameter name="aDown"/>
<body>
<![CDATA[
if (!aNode) {
return null;
}
var node = aNode;
var next = null;
while (node) {
if (aDown) {
next = node.nextSibling;
} else {
next = node.previousSibling;
}
if (next && next.namespaceURI == this.XFORMS_NS) {
if (next.localName == "item") {
return next;
} else if (next.localName == "choices") {
var child = null;
if (aDown) {
child = next.firstChild;
} else {
child = next.lastChild;
}
if (child.namespaceURI == this.XFORMS_NS &&
child.localName == "item") {
return child;
}
child = this.findNextSelectable(child, aDown);
if (child) {
return child;
}
} else if (next.localName == "itemset" &&
next.anonymousItemSetContent.childNodes.length > 0) {
return aDown ? next.anonymousItemSetContent.firstChild
: next.anonymousItemSetContent.lastChild;
}
}
node = next;
}
// if we are in a choices or itemset element
var parent = aNode.parentNode;
if (parent.namespaceURI == this.XFORMS_NS &&
parent.localName == "choices") {
var sibling = aDown ? parent.nextSibling : parent.previousSibling;
if (sibling.namespaceURI == this.XFORMS_NS &&
sibling.localName == "item") {
return sibling;
}
return this.findNextSelectable(sibling, aDown);
}
if (parent.parentNode.namespaceURI == this.XFORMS_NS &&
parent.parentNode.localName == "itemset") {
var sibling2 = aDown
? parent.parentNode.nextSibling
: parent.parentNode.previousSibling;
if (sibling2.namespaceURI == this.XFORMS_NS &&
sibling2.localName == "item") {
return sibling2;
}
return this.findNextSelectable(sibling2, aDown);
}
return null;
]]>
</body>
</method>
<method name="internalScroll">
<parameter name="aDown"/>
<body>
<![CDATA[
var label = null;
var next = null, nextItem = null;
var node = this.firstChild;
while (node) {
if (node.namespaceURI == this.XFORMS_NS &&
node.localName == "label") {
label = node;
break;
}
node = node.nextSibling;
}
if (this._selected) {
node = this._selected.QueryInterface(Components.interfaces.nsIDOMNode);
} else if (label) {
node = label.nextSibling;
} else {
node = this.firstChild;
}
next = this.findNextSelectable(node, aDown);
if (next) {
if (this._selected) {
this._lastSelected = this._selected;
this._selected.setActive(false);
this._selected = null;
}
nextItem = next.QueryInterface(Components.interfaces.nsIXFormsItemElement);
if (nextItem) {
this._selected = nextItem;
this._selected.setActive(true);
this.updateInputField();
}
return true;
}
if (!aDown && this.selectionOpen) {
if (this._selected) {
this._selected.setActive(false);
this._selected = null;
}
this.inputField.value = "";
}
]]>
</body>
</method>
<method name="mouseUp">
<parameter name="aEvent"/>
<body>
<![CDATA[
// Use original target, because <item> is possible (anonymously)
// inside <itemset>
var target = aEvent.originalTarget;
while (target && target != this) {
if (target.namespaceURI == this.XFORMS_NS &&
(target.localName == "item" || target.localName == "choices")) {
break;
}
target = target.parentNode;
}
if (target == this) {
return true;
}
this.hidePopup();
if (this._selected) {
this.updateInputField();
if (this.incremental) {
this._handleSelection(true);
} else {
this.dispatchSelectEvents();
}
}
this.inputField.focus();
]]>
</body>
</method>
<method name="mouseOver">
<parameter name="aEvent"/>
<body>
<![CDATA[
// Use original target, because <item> is possible (anonymously)
// inside <itemset>
var target = aEvent.originalTarget;
while (target && target != this) {
if (target.namespaceURI == this.XFORMS_NS && target.localName == "item") {
if (this._selected) {
this._selected.setActive(false);
this._selected = null;
}
var item =
target.QueryInterface(Components.interfaces.nsIXFormsItemElement);
if (item) {
item.setActive(true);
this._selected = item;
}
break;
}
target = target.parentNode;
}
]]>
</body>
</method>
<method name="hidePopup">
<body>
this.popup.style.visibility = "hidden";
this.popupOpen = false;
</body>
</method>
<method name="refreshWidth">
<body>
<![CDATA[
if (!this.popupOpen) {
this.inputField.removeAttribute("style");
this.popup.style.width = "auto";
this.popup.style.height = "auto";
this.popup.style.maxHeight = "none";
this._width = -1;
var popupBox = document.getBoxObjectFor(this.popup);
var w = popupBox.width;
if (w > 0) {
w = w + 12; // Adding some 'padding' for possible scrollbar
this.inputField.setAttribute("style", "width:" + w + "px;");
this._width = w + document.getBoxObjectFor(this.dropMarker).width;
}
this.popup.style.maxHeight = "10px";
this.popup.style.left = "0px";
this.popup.style.top = "0px";
}
]]>
</body>
</method>
<method name="togglePopup">
<body>
<![CDATA[
if (!this.popupOpen && !this.accessors.isReadonly()) {
// Calculating the size and position of the popup.
var style = "";
var containerBox = document.getBoxObjectFor(this.container);
var x;
var y;
var adjust = 0;
var absolute = false;
var absoluteOffsetY = 0;
var p = this.container.offsetParent;
var compStyle =
document.defaultView.getComputedStyle(p, null);
if (compStyle.getPropertyValue("position") != "absolute") {
adjust = document.documentElement.offsetTop;
x = containerBox.x;
y = containerBox.y;
} else {
absolute = true;
x = this.container.offsetLeft;
y = this.container.offsetTop;
absoluteOffsetY = y;
while (p) {
absoluteOffsetY += p.offsetTop;
p = p.offsetParent;
}
}
var h = containerBox.height;
var w = containerBox.width;
var targetY = y + h;
this.popup.style.maxHeight = "none";
var popupBox = document.getBoxObjectFor(this.popup);
var popupHeight = popupBox.height;
var pY = window.pageYOffset;
var iH = window.innerHeight;
var belowSelect = absolute
? (iH - (absoluteOffsetY + h) - h)
: (iH - (y - pY + h - adjust) - h);
if (belowSelect < popupHeight) {
if ((y - pY) > popupHeight) {
targetY = y - popupHeight;
} else if (belowSelect < (y - pY)) {
style = style + "max-height:" + (y - pY - adjust) + "px;";
targetY = pY + adjust;
} else {
style = style + "max-height:" + belowSelect + "px;";
}
}
style = style + "left:" + x + "px;";
style = style + "top:" + targetY + "px;";
style = style + "width:";
if (this.selectionOpen) {
style = style + w + "px;";
} else if (this._width < 0) {
style = style + "auto;"
} else {
style = style + this._width + "px;";
}
style = style + "visibility:visible;";
this.popup.setAttribute("style", style);
this.popupOpen = true;
this._tmpSelected = this._selected;
if (this._selected) {
var el = this._selected.QueryInterface(Components.interfaces.nsIDOMElement);
if ("scrollIntoView" in el) {
el.scrollIntoView(false);
}
}
} else {
this.hidePopup();
return;
}
]]>
</body>
</method>
<method name="refresh">
<body>
<![CDATA[
try {
var nodeValue = null, newValue = null;
var boundNode = this.accessors.getBoundNode();
var outOfRange = false;
if (boundNode && boundNode.hasChildNodes()) {
// Since this is a select1, there should normally be just one
// child node here. But no guarantee that a select1 generated
// the value coming in. So we'll look for text node with
// non-whitespace characters to compare with an item's xf:value.
// Any other node that we encounter we look to match with an
// item's xf:copy. If more than one of either of these exists
// in the instance data, we need to generate a xforms-out-of-range
// event and style the select1 as out-of-range since by
// definition a select1 can not select more than one item.
var child = boundNode.firstChild;
while (child) {
var type = child.nodeType;
if (type == Node.TEXT_NODE) {
// if child is a text node completely filled with
// whitespace let's ignore it and get the next node
var string = child.nodeValue;
var nonWhitespace = false;
if (string) {
// this regexp tests whether only whitespace is contained
// between the beginning and ending of the string.
nonWhitespace = !(/^\s*$/.test(string));
}
if (nonWhitespace) {
if (newValue || nodeValue) {
// oh oh! We've already found a selectable node in the
// instance data and now we have another. That shouldn't
// happen.
outOfRange = true;
}
newValue = string;
}
} else {
// if it's not a text node, we'll assume that we are looking at
// a node worth comparing. As such, look for an
// item with a copy element that might match this node.
if (newValue || nodeValue) {
// oh oh! We've already found a selectable node in the
// instance data and now we have another. That shouldn't
// happen.
outOfRange = true;
}
nodeValue = child;
}
if (child == boundNode.lastChild) {
break;
}
child = child.nextSibling;
}
}
if (outOfRange) {
// a control can't be out of range (or in range for that matter)
// if there is no selected value, so make sure that there is a
// bound node first.
if ((outOfRange != this._outOfRange) && boundNode) {
this._outOfRange = outOfRange;
this.accessors.setInRange(false);
}
// can't possibly work, no sense continuing.
this.inputField.value = "";
this._selected.setActive(false);
this._selected = null;
this.refreshWidth();
return false;
}
if (!this.selectionOpen || this.accessors.isReadonly()) {
this.inputField.setAttribute("readonly", "readonly");
} else {
this.inputField.removeAttribute("readonly");
}
if (this._selected && !this._selected.isCopyItem) {
var envelope = this._getSelectedValue();
if (envelope) {
var textNode = null;
if (envelope.nodeType == Node.ELEMENT_NODE) {
textNode = envelope.firstChild;
if (newValue == textNode.nodeValue) {
// Value in instance data already selected. Need to only
// refresh the width.
this.refreshWidth();
return true;
}
} else {
if (newValue == envelope.nodeValue) {
// Value in instance data already selected. Need to only
// refresh the width.
this.refreshWidth();
return true;
}
}
}
this._selected.setActive(false);
this._selected = null;
this._lastSelectedItem = null;
}
if (newValue) {
this.selectItemByValue(newValue);
} else if (nodeValue) {
this.selectItemByNode(nodeValue);
}
outOfRange = false;
if (this._selected) {
this.updateInputField();
this._lastSelectedItem = this._selected;
} else if (this.selectionOpen) {
this.inputField.value = newValue;
} else {
this.inputField.value = "";
outOfRange = true;
}
// a control can't be out of range (or in range for that matter)
// if there is no selected value, so make sure that there is a
// bound node first.
if ((outOfRange != this._outOfRange) && boundNode) {
this._outOfRange = outOfRange;
this.accessors.setInRange(!outOfRange);
}
this.refreshWidth();
} catch (ex) {}
return true;
]]>
</body>
</method>
<method name="focus">
<body>
this.inputField.focus();
return true;
</body>
</method>
<method name="selectItemByValue">
<parameter name="aValue"/>
<body>
<![CDATA[
var node = this.firstChild;
var item;
while (node) {
item = null;
try {
if (node.nodeType == document.ELEMENT_NODE &&
node.namespaceURI == this.XFORMS_NS &&
node.localName != "label") {
item = node.QueryInterface(Components.interfaces.nsIXFormsSelectChild);
if (item) {
item = item.selectItemByValue(aValue);
if (item) {
if (this._selected) {
this._selected.setActive(false);
this._selected = null;
}
this._selected = item.QueryInterface(Components.interfaces.nsIXFormsItemElement);
if (this._selected) {
this._selected.setActive(true);
return;
}
}
}
}
} catch (ex) {}
node = node.nextSibling;
}
]]>
</body>
</method>
<method name="selectItemByNode">
<parameter name="aNode"/>
<body>
<![CDATA[
// select the copyItem in this select1 whose copyNode equals aNode
var node = this.firstChild;
var item;
while (node) {
item = null;
try {
if (node.nodeType == document.ELEMENT_NODE &&
node.namespaceURI == this.XFORMS_NS &&
node.localName != "label") {
item = node.QueryInterface(Components.interfaces.nsIXFormsSelectChild);
if (item) {
item = item.selectItemByNode(aNode);
if (item) {
if (this._selected) {
this._selected.setActive(false);
this._selected = null;
}
this._selected = item.QueryInterface(Components.interfaces.nsIXFormsItemElement);
if (this._selected) {
this._selected.setActive(true);
return;
}
}
}
}
} catch (ex) {}
node = node.nextSibling;
}
]]>
</body>
</method>
<method name="handleBlur">
<body>
<![CDATA[
if (this.shouldHandleBlur) {
var open = this.popupOpen;
this.hidePopup();
if (open) {
if (this._selected) {
this._selected.setActive(false);
this._selected = this._tmpSelected;
this._tmpSelected = null;
if (this._selected) {
this._selected.setActive(true);
}
}
return;
}
if (this._selected) {
this.updateInputField();
}
this._handleSelection(false, true);
}
]]>
</body>
</method>
<!-- _handleSelection updates the bound node with the value from the
currently selected item's value element or copy element. -->
<method name="_handleSelection">
<parameter name="aDispatchSelectEvents"/>
<parameter name="aInBlur"/>
<body>
<![CDATA[
// if aDispatchSelectEvents is true, then we need to make sure to
// dispatch the xforms-deselect and xforms-select events before we
// change the value of the bound node otherwise we'll get the
// event ordering wrong. Similar with setting out of/in range (must
// happen after dispatch select/deselect). aDispatchSelectEvents is
// a REQUIRED parameter, whether it be true or false.
// aInBlur is not a required parameter. It is true if handleSelection
// was called from the blur handler.
var boundNode = this.accessors.getBoundNode();
if (!boundNode) {
return;
}
if (this.selectionOpen && !this._selected) {
if (aDispatchSelectEvents == true) {
this.dispatchSelectEvents();
}
this.accessors.setValue(this.inputField.value);
// open selection can't be out of range
this._outOfRange = false;
this.accessors.setInRange(true);
return;
}
if (!this._selected) {
// no reason to continue
return;
}
if (aInBlur && aInBlur == true) {
// if _handleSelection is called due to a blur, we only really care
// about making sure the bound node is in sync if @incremental is
// false. Otherwise the bound node is already up to date so might
// as well return.
if (this.incremental) {
return;
}
}
if (boundNode.nodeType != boundNode.ELEMENT_NODE) {
// if the boundNode type isn't an ELEMENT_NODE, then contentEnvelope
// isn't an ELEMENT_NODE (since it is a clone of the bound node).
// So if contentEnvelope has a value, it will be the nodeValue.
var envelope = this._getSelectedValue();
if (envelope) {
if (aDispatchSelectEvents == true) {
this.dispatchSelectEvents();
}
this.accessors.setValue(envelope.nodeValue);
this._outOfRange = false;
this.accessors.setInRange(true);
return;
}
// not allowed to copy a node under a non ELEMENT node, so
// generating a binding exception per spec.
var ev = document.createEvent("Events");
ev.initEvent("xforms-binding-exception", true, false);
this.dispatchEvent(ev);
// well, whatever we had selected isn't going to cut it. But the
// user did choose to deselect the previous item in favor of this
// this item, so we really shouldn't go back to what
// was there before. So we'll go to nothing. Make sure bound
// node reflects this. Seems to be consistent with what Novell
// and formsPlayer does, too.
this._selected.setActive(false);
this._selected = null;
this.inputField.value = "";
if (aDispatchSelectEvents == true) {
this.dispatchSelectEvents();
}
this.accessors.setValue("");
this._outOfRange = true;
this.accessors.setInRange(false);
return;
}
var contentEnvelope = this._getSelectedValue();
var copyInvolved = this._selected.isCopyItem;
if (!copyInvolved && this._lastSelectedItem) {
copyInvolved = this._lastSelectedItem.isCopyItem;
}
if (!copyInvolved) {
// Since we aren't selecting a copyItem nor causing a copyItem to
// be deselected, no sense using setContent. Too expensive.
if (aDispatchSelectEvents == true) {
this.dispatchSelectEvents();
}
this.accessors.setValue(contentEnvelope.textContent);
this._outOfRange = false;
this.accessors.setInRange(true);
} else {
if (aDispatchSelectEvents == true) {
this.dispatchSelectEvents();
}
this.accessors.setContent(contentEnvelope, true);
this._outOfRange = false;
this.accessors.setInRange(true);
}
}
]]>
</body>
</method>
<method name="dispatchSelectEvents">
<body>
<![CDATA[
if (this._lastSelectedItem != this._selected) {
if (this._lastSelectedItem) {
this.dispatchSelectEvent(this._lastSelectedItem, "xforms-deselect");
}
if (this._selected) {
this.dispatchSelectEvent(this._selected, "xforms-select");
}
this._lastSelectedItem = this._selected;
}
]]>
</body>
</method>
<method name="dispatchSelectEvent">
<parameter name="aElement"/>
<parameter name="aName"/>
<body>
<![CDATA[
var ev = document.createEvent("Events");
ev.initEvent(aName, true, false);
var elm = aElement;
// per http://www.w3.org/TR/2005/PER-xforms-20051006/index-all.html#evt-select
// we send the event to the itemset if it is a parent.
if (elm.parentNode && elm.parentNode.localName == "itemset")
elm = elm.parentNode;
elm.dispatchEvent(ev);
return true;
]]>
</body>
</method>
<method name="_getSelectedValue">
<body>
<![CDATA[
// The purpose of this function is to return the select1's currently
// selected item's value in a contentEnvelope. It achieves this by
// cloning the bound node to create the contentEnvelope which will be
// returned. If the contentEnvelope is an element node, the contents
// of the selected item's value will be inserted as a child of the
// contentEnvelope. If it is a textnode, the selected item value will
// be put in the contentEnvelope.nodeValue.
if (!this._selected) {
// this will probably only happen if there was an exception
// somewhere else first. But no sense continuing below and adding
// more exceptions to the console.
return null;
}
var boundNode = this.accessors.getBoundNode();
if (!boundNode) {
return null;
}
var contentEnvelope = boundNode.cloneNode(false);
if (!contentEnvelope) {
return null;
}
if (contentEnvelope.nodeType == Node.ELEMENT_NODE) {
var contentNode = null;
if (this._selected.isCopyItem) {
var copyNode = this._selected.copyNode;
if (copyNode) {
contentNode = copyNode.cloneNode(true);
}
} else {
contentNode = document.createTextNode(this._selected.value);
}
contentEnvelope.appendChild(contentNode);
} else {
// if the selected item is not a copyItem, then we'll just put the
// item's value in the nodeValue for the contentEnvelope. Otherwise
// we are stuck trying to stick an element node under a non-element
// node and that ainna gonna work.
if (!this._selected.isCopyItem) {
contentEnvelope.nodeValue = this._selected.value;
} else {
contentEnvelope = null;
}
}
return contentEnvelope;
]]>
</body>
</method>
</implementation>
</binding>
<binding id="xformswidget-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>
<!-- The binding for <item> is needed only because of the
scrollIntoView method. -->
<binding id="xformswidget-select1-item">
<content>
<html:div anonid="content">
<children/>
</html:div>
</content>
<implementation>
<field name="_content">null</field>
<property name="content" readonly="true">
<getter>
if (!this._content) {
this._content =
document.getAnonymousElementByAttribute(this, "anonid", "content");
}
return this._content;
</getter>
</property>
<!-- Only (X)HTML elements have method 'scrollIntoView',
so we need to forward this method call to the anonymous content
of this element. -->
<method name="scrollIntoView">
<parameter name="aTop"/>
<body>
// this.content is null if anonymous content hasn't been created yet.
var content = this.content;
if (content) {
content.scrollIntoView(aTop);
}
</body>
</method>
</implementation>
</binding>
</bindings>