2002-09-29 23:41:28 +04:00
|
|
|
<?xml version="1.0"?>
|
|
|
|
|
|
|
|
<bindings id="radioBindings"
|
|
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
|
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
|
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
|
|
|
|
|
|
|
<binding id="radiogroup">
|
|
|
|
<resources>
|
|
|
|
<stylesheet src="chrome://global/skin/radio.css"/>
|
|
|
|
</resources>
|
|
|
|
|
|
|
|
<implementation implements="nsIDOMXULSelectControlElement, nsIAccessibleProvider">
|
|
|
|
<property name="accessible">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
|
|
|
|
return accService.createXULRadioGroupAccessible(this);
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="value" onset="this.setAttribute('value',val); return val;"
|
|
|
|
onget="return this.getAttribute('value');"/>
|
|
|
|
<property name="disabled">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
2003-08-17 15:10:28 +04:00
|
|
|
if (this.getAttribute('disabled') == 'true')
|
|
|
|
return true;
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
if (!children[i].hidden && !children[i].collapsed && !children[i].disabled)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2002-09-29 23:41:28 +04:00
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (val)
|
|
|
|
this.setAttribute('disabled', 'true');
|
|
|
|
else
|
|
|
|
this.removeAttribute('disabled');
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
children[i].disabled = val;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
2003-08-17 15:10:28 +04:00
|
|
|
<property name="selectedIndex">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
if (children[i].selected)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
this.selectedItem = this._getRadioChildren()[val];
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
2002-09-29 23:41:28 +04:00
|
|
|
<property name="selectedItem">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
if (children[i].selected)
|
|
|
|
return children[i];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
2003-08-17 15:10:28 +04:00
|
|
|
var focused = this.getAttribute("focused") == "true";
|
|
|
|
var alreadySelected = false;
|
|
|
|
|
|
|
|
if (val) {
|
|
|
|
alreadySelected = val.getAttribute("selected") == "true";
|
|
|
|
val.setAttribute("focused", focused);
|
|
|
|
val.setAttribute("selected", "true");
|
|
|
|
this.value = val.value;
|
2002-11-11 04:51:50 +03:00
|
|
|
}
|
2002-09-29 23:41:28 +04:00
|
|
|
|
|
|
|
// uncheck all other group nodes
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
if (children[i] != val) {
|
|
|
|
children[i].removeAttribute("selected");
|
|
|
|
children[i].removeAttribute("focused");
|
|
|
|
}
|
|
|
|
}
|
2003-08-17 15:10:28 +04:00
|
|
|
|
|
|
|
var event = document.createEvent("Events");
|
2002-09-29 23:41:28 +04:00
|
|
|
event.initEvent("select", false, true);
|
|
|
|
this.dispatchEvent(event);
|
|
|
|
|
2002-11-11 04:51:50 +03:00
|
|
|
if (!alreadySelected && focused) {
|
|
|
|
// Only report if actual change
|
|
|
|
var myEvent = document.createEvent("Events");
|
|
|
|
myEvent.initEvent("RadioStateChange", true, true);
|
|
|
|
val.dispatchEvent(myEvent);
|
|
|
|
}
|
2002-09-29 23:41:28 +04:00
|
|
|
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="focusedItem">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
if (children[i].getAttribute("focused") == "true")
|
|
|
|
return children[i];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (val) val.setAttribute("focused", "true");
|
|
|
|
|
|
|
|
// unfocus all other group nodes
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
if (children[i] != val)
|
|
|
|
children[i].removeAttribute("focused");
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<method name="checkAdjacentElement">
|
|
|
|
<parameter name="aNextFlag"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var currentElement = this.focusedItem;
|
2003-08-17 15:10:28 +04:00
|
|
|
var i;
|
2002-09-29 23:41:28 +04:00
|
|
|
var children = this._getRadioChildren();
|
|
|
|
for (i = 0; i < children.length; ++i ) {
|
|
|
|
if (children[i] == currentElement)
|
|
|
|
break;
|
|
|
|
}
|
2003-08-17 15:10:28 +04:00
|
|
|
var index = i;
|
|
|
|
|
2002-09-29 23:41:28 +04:00
|
|
|
if (aNextFlag) {
|
|
|
|
do {
|
2003-08-17 15:10:28 +04:00
|
|
|
if (++i == children.length)
|
|
|
|
i = 0;
|
|
|
|
if (i == index)
|
2002-09-29 23:41:28 +04:00
|
|
|
break;
|
|
|
|
}
|
2003-08-17 15:10:28 +04:00
|
|
|
while (children[i].hidden || children[i].collapsed || children[i].disabled);
|
|
|
|
// XXX check for display/visibility props too
|
2002-09-29 23:41:28 +04:00
|
|
|
|
2003-08-17 15:10:28 +04:00
|
|
|
this.selectedItem = children[i];
|
|
|
|
children[i].doCommand();
|
2002-09-29 23:41:28 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
do {
|
2003-08-17 15:10:28 +04:00
|
|
|
if (i == 0)
|
|
|
|
i = children.length;
|
|
|
|
if (--i == index)
|
2002-09-29 23:41:28 +04:00
|
|
|
break;
|
|
|
|
}
|
2003-08-17 15:10:28 +04:00
|
|
|
while (children[i].hidden || children[i].collapsed || children[i].disabled);
|
|
|
|
// XXX check for display/visibility props too
|
2002-09-29 23:41:28 +04:00
|
|
|
|
2003-08-17 15:10:28 +04:00
|
|
|
this.selectedItem = children[i];
|
|
|
|
children[i].doCommand();
|
2002-09-29 23:41:28 +04:00
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
<field name="mRadioChildren">[]</field>
|
|
|
|
<method name="_getRadioChildren">
|
|
|
|
<parameter name="aNode">this</parameter>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (aNode) {
|
|
|
|
if (aNode == this && this.mRadioChildren)
|
|
|
|
return this.mRadioChildren;
|
|
|
|
else if (aNode.localName == "radio") {
|
|
|
|
this.mRadioChildren[this.mRadioChildren.length++] = aNode;
|
|
|
|
return this.mRadioChildren;
|
|
|
|
}
|
|
|
|
else if (aNode.localName == "radiogroup" && aNode != this)
|
|
|
|
return this.mRadioChildren;
|
|
|
|
for (var i = 0; i < aNode.childNodes.length; ++i)
|
|
|
|
this._getRadioChildren(aNode.childNodes[i]);
|
|
|
|
}
|
|
|
|
return this.mRadioChildren;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="appendItem">
|
|
|
|
<parameter name="label"/>
|
|
|
|
<parameter name="value"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
|
|
var radio = document.createElementNS(XULNS, "radio");
|
|
|
|
radio.setAttribute("label", label);
|
|
|
|
radio.setAttribute("value", value);
|
|
|
|
this.appendChild(radio);
|
|
|
|
return radio;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="insertItemAt">
|
|
|
|
<parameter name="index"/>
|
|
|
|
<parameter name="label"/>
|
|
|
|
<parameter name="value"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
|
|
var radio = document.createElementNS(XULNS, "radio");
|
|
|
|
radio.setAttribute("label", label);
|
|
|
|
radio.setAttribute("value", value);
|
|
|
|
var before = this.childNodes[index];
|
|
|
|
if (before)
|
|
|
|
this.insertBefore(radio, before);
|
|
|
|
else
|
|
|
|
this.appendChild(radio);
|
|
|
|
return radio;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="removeItemAt">
|
|
|
|
<parameter name="index"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var remove = this.childNodes[index];
|
|
|
|
if (remove)
|
|
|
|
this.removeChild(remove);
|
|
|
|
return remove;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
|
|
|
|
<handlers>
|
|
|
|
<handler event="select">
|
|
|
|
<![CDATA[
|
|
|
|
//XXXblake this should not be necessary
|
|
|
|
// initEvent was supposed to prevent this from bubbling
|
|
|
|
event.preventBubble();
|
|
|
|
]]>
|
|
|
|
</handler>
|
2003-08-17 15:10:28 +04:00
|
|
|
<handler event="mousedown">
|
|
|
|
if (this.disabled)
|
|
|
|
event.preventDefault();
|
|
|
|
</handler>
|
2002-09-29 23:41:28 +04:00
|
|
|
|
|
|
|
<!-- keyboard navigation -->
|
|
|
|
<!-- Here's how keyboard navigation works in radio groups on Windows:
|
|
|
|
The group takes 'focus'
|
|
|
|
The user is then free to navigate around inside the group
|
|
|
|
using the arrow keys. Accessing previous or following radio buttons
|
|
|
|
is done solely through the arrow keys and not the tab button. Tab
|
|
|
|
takes you to the next widget in the tab order -->
|
2003-08-17 15:10:28 +04:00
|
|
|
<handler event="keypress" key=" " phase="target">
|
2002-09-29 23:41:28 +04:00
|
|
|
this.selectedItem = this.focusedItem;
|
|
|
|
this.selectedItem.doCommand();
|
|
|
|
</handler>
|
|
|
|
<handler event="keypress" keycode="VK_UP" phase="target">
|
|
|
|
this.checkAdjacentElement(false);
|
|
|
|
event.preventBubble();
|
|
|
|
</handler>
|
|
|
|
<handler event="keypress" keycode="VK_LEFT" phase="target">
|
|
|
|
this.checkAdjacentElement(false);
|
|
|
|
event.preventBubble();
|
|
|
|
</handler>
|
|
|
|
<handler event="keypress" keycode="VK_DOWN" phase="target">
|
|
|
|
this.checkAdjacentElement(true);
|
|
|
|
event.preventBubble();
|
|
|
|
</handler>
|
|
|
|
<handler event="keypress" keycode="VK_RIGHT" phase="target">
|
|
|
|
this.checkAdjacentElement(true);
|
|
|
|
event.preventBubble();
|
|
|
|
</handler>
|
|
|
|
|
|
|
|
<!-- set a focused attribute on the selected item when the group
|
|
|
|
receives focus so that we can style it as if it were focused even though
|
|
|
|
it is not (Windows platform behaviour is for the group to receive focus,
|
|
|
|
not the item -->
|
|
|
|
<handler event="focus" phase="target">
|
2003-08-17 15:10:28 +04:00
|
|
|
<![CDATA[
|
2002-09-29 23:41:28 +04:00
|
|
|
this.setAttribute("focused", "true");
|
2003-08-17 15:10:28 +04:00
|
|
|
if (this.focusedItem)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var val = this.selectedItem;
|
|
|
|
if (!val || val.disabled || val.hidden || val.collapsed) {
|
|
|
|
var children = this._getRadioChildren();
|
|
|
|
var i;
|
|
|
|
for (var i = 0; i < children.length; ++i) {
|
|
|
|
if (!children[i].hidden && !children[i].collapsed && !children[i].disabled) {
|
|
|
|
val = children[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.focusedItem = val;
|
|
|
|
]]>
|
2002-09-29 23:41:28 +04:00
|
|
|
</handler>
|
|
|
|
<handler event="blur" phase="target">
|
|
|
|
this.removeAttribute("focused");
|
|
|
|
this.focusedItem = null;
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
|
|
|
</binding>
|
|
|
|
|
2003-08-17 15:10:28 +04:00
|
|
|
<binding id="radio" extends="chrome://global/content/widgets/general.xml#control-item">
|
2002-09-29 23:41:28 +04:00
|
|
|
<resources>
|
|
|
|
<stylesheet src="chrome://global/skin/radio.css"/>
|
|
|
|
</resources>
|
|
|
|
|
|
|
|
<content>
|
|
|
|
<xul:image class="radio-check" xbl:inherits="disabled,selected"/>
|
2003-08-17 15:10:28 +04:00
|
|
|
<xul:hbox class="radio-label-box" flex="1">
|
2002-09-29 23:41:28 +04:00
|
|
|
<xul:image class="radio-icon" xbl:inherits="src"/>
|
2003-08-17 15:10:28 +04:00
|
|
|
<xul:label class="radio-label" xbl:inherits="xbl:text=label,accesskey,crop" flex="1"/>
|
2002-09-29 23:41:28 +04:00
|
|
|
</xul:hbox>
|
|
|
|
</content>
|
|
|
|
|
|
|
|
<implementation implements="nsIDOMXULSelectControlItemElement, nsIAccessibleProvider">
|
|
|
|
<constructor>
|
|
|
|
<![CDATA[
|
|
|
|
var parent = this.radioGroup;
|
|
|
|
parent.mRadioChildren[parent.mRadioChildren.length++] = this;
|
|
|
|
]]>
|
|
|
|
</constructor>
|
|
|
|
<destructor>
|
|
|
|
<![CDATA[
|
|
|
|
var parent = this.radioGroup;
|
|
|
|
for (var i = 0; i < parent.mRadioChildren.length; ++i) {
|
|
|
|
if (parent.mRadioChildren[i] == this) {
|
|
|
|
parent.mRadioChildren.slice(i, i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</destructor>
|
|
|
|
<property name="accessible">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
|
|
|
|
return accService.createXULRadioButtonAccessible(this);
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
<property name="selected" readonly="true">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
return this.hasAttribute('selected');
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
<property name="radioGroup">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
2003-08-17 15:10:28 +04:00
|
|
|
var parent = this.parentNode;
|
|
|
|
while (parent) {
|
2002-09-29 23:41:28 +04:00
|
|
|
if (parent.localName == "radiogroup")
|
|
|
|
return parent;
|
2003-08-17 15:10:28 +04:00
|
|
|
parent = parent.parentNode;
|
2002-09-29 23:41:28 +04:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
</implementation>
|
2003-08-17 15:10:28 +04:00
|
|
|
<handlers>
|
|
|
|
<handler event="click" button="0">
|
|
|
|
<![CDATA[
|
|
|
|
if (!this.disabled)
|
|
|
|
this.radioGroup.selectedItem = this;
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
|
|
|
|
<handler event="mousedown" button="0">
|
|
|
|
<![CDATA[
|
|
|
|
if (!this.disabled)
|
|
|
|
this.radioGroup.focusedItem = this;
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
2002-09-29 23:41:28 +04:00
|
|
|
</binding>
|
2003-08-17 15:10:28 +04:00
|
|
|
</bindings>
|