Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 <?xml version="1.0"?>
2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
3 - License, v. 2.0. If a copy of the MPL was not distributed with this
4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
7 <bindings id="radioBindings"
8 xmlns="http://www.mozilla.org/xbl"
9 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
10 xmlns:xbl="http://www.mozilla.org/xbl">
12 <binding id="radiogroup" role="xul:radiogroup"
13 extends="chrome://global/content/bindings/general.xml#basecontrol">
14 <resources>
15 <stylesheet src="chrome://global/skin/radio.css"/>
16 </resources>
18 <implementation implements="nsIDOMXULSelectControlElement">
19 <constructor>
20 <![CDATA[
21 if (this.getAttribute("disabled") == "true")
22 this.disabled = true;
24 var children = this._getRadioChildren();
25 var length = children.length;
26 for (var i = 0; i < length; i++) {
27 if (children[i].getAttribute("selected") == "true") {
28 this.selectedIndex = i;
29 return;
30 }
31 }
33 var value = this.value;
34 if (value)
35 this.value = value;
36 else
37 this.selectedIndex = 0;
38 ]]>
39 </constructor>
41 <property name="value" onget="return this.getAttribute('value');">
42 <setter>
43 <![CDATA[
44 this.setAttribute("value", val);
45 var children = this._getRadioChildren();
46 for (var i = 0; i < children.length; i++) {
47 if (String(children[i].value) == String(val)) {
48 this.selectedItem = children[i];
49 break;
50 }
51 }
52 return val;
53 ]]>
54 </setter>
55 </property>
56 <property name="disabled">
57 <getter>
58 <![CDATA[
59 if (this.getAttribute('disabled') == 'true')
60 return true;
61 var children = this._getRadioChildren();
62 for (var i = 0; i < children.length; ++i) {
63 if (!children[i].hidden && !children[i].collapsed && !children[i].disabled)
64 return false;
65 }
66 return true;
67 ]]>
68 </getter>
69 <setter>
70 <![CDATA[
71 if (val)
72 this.setAttribute('disabled', 'true');
73 else
74 this.removeAttribute('disabled');
75 var children = this._getRadioChildren();
76 for (var i = 0; i < children.length; ++i) {
77 children[i].disabled = val;
78 }
79 return val;
80 ]]>
81 </setter>
82 </property>
84 <property name="itemCount" readonly="true"
85 onget="return this._getRadioChildren().length"/>
87 <property name="selectedIndex">
88 <getter>
89 <![CDATA[
90 var children = this._getRadioChildren();
91 for (var i = 0; i < children.length; ++i) {
92 if (children[i].selected)
93 return i;
94 }
95 return -1;
96 ]]>
97 </getter>
98 <setter>
99 <![CDATA[
100 this.selectedItem = this._getRadioChildren()[val];
101 return val;
102 ]]>
103 </setter>
104 </property>
106 <property name="selectedItem">
107 <getter>
108 <![CDATA[
109 var children = this._getRadioChildren();
110 for (var i = 0; i < children.length; ++i) {
111 if (children[i].selected)
112 return children[i];
113 }
114 return null;
115 ]]>
116 </getter>
117 <setter>
118 <![CDATA[
119 var focused = this.getAttribute("focused") == "true";
120 var alreadySelected = false;
122 if (val) {
123 alreadySelected = val.getAttribute("selected") == "true";
124 val.setAttribute("focused", focused);
125 val.setAttribute("selected", "true");
126 this.setAttribute("value", val.value);
127 }
128 else {
129 this.removeAttribute("value");
130 }
132 // uncheck all other group nodes
133 var children = this._getRadioChildren();
134 var previousItem = null;
135 for (var i = 0; i < children.length; ++i) {
136 if (children[i] != val) {
137 if (children[i].getAttribute("selected") == "true")
138 previousItem = children[i];
140 children[i].removeAttribute("selected");
141 children[i].removeAttribute("focused");
142 }
143 }
145 var event = document.createEvent("Events");
146 event.initEvent("select", false, true);
147 this.dispatchEvent(event);
149 if (!alreadySelected && focused) {
150 // Only report if actual change
151 var myEvent;
152 if (val) {
153 myEvent = document.createEvent("Events");
154 myEvent.initEvent("RadioStateChange", true, true);
155 val.dispatchEvent(myEvent);
156 }
158 if (previousItem) {
159 myEvent = document.createEvent("Events");
160 myEvent.initEvent("RadioStateChange", true, true);
161 previousItem.dispatchEvent(myEvent);
162 }
163 }
165 return val;
166 ]]>
167 </setter>
168 </property>
170 <property name="focusedItem">
171 <getter>
172 <![CDATA[
173 var children = this._getRadioChildren();
174 for (var i = 0; i < children.length; ++i) {
175 if (children[i].getAttribute("focused") == "true")
176 return children[i];
177 }
178 return null;
179 ]]>
180 </getter>
181 <setter>
182 <![CDATA[
183 if (val) val.setAttribute("focused", "true");
185 // unfocus all other group nodes
186 var children = this._getRadioChildren();
187 for (var i = 0; i < children.length; ++i) {
188 if (children[i] != val)
189 children[i].removeAttribute("focused");
190 }
191 return val;
192 ]]>
193 </setter>
194 </property>
196 <method name="checkAdjacentElement">
197 <parameter name="aNextFlag"/>
198 <body>
199 <![CDATA[
200 var currentElement = this.focusedItem || this.selectedItem;
201 var i;
202 var children = this._getRadioChildren();
203 for (i = 0; i < children.length; ++i ) {
204 if (children[i] == currentElement)
205 break;
206 }
207 var index = i;
209 if (aNextFlag) {
210 do {
211 if (++i == children.length)
212 i = 0;
213 if (i == index)
214 break;
215 }
216 while (children[i].hidden || children[i].collapsed || children[i].disabled);
217 // XXX check for display/visibility props too
219 this.selectedItem = children[i];
220 children[i].doCommand();
221 }
222 else {
223 do {
224 if (i == 0)
225 i = children.length;
226 if (--i == index)
227 break;
228 }
229 while (children[i].hidden || children[i].collapsed || children[i].disabled);
230 // XXX check for display/visibility props too
232 this.selectedItem = children[i];
233 children[i].doCommand();
234 }
235 ]]>
236 </body>
237 </method>
238 <field name="_radioChildren">null</field>
239 <method name="_getRadioChildren">
240 <body>
241 <![CDATA[
242 if (this._radioChildren)
243 return this._radioChildren;
245 var radioChildren = [];
246 var doc = this.ownerDocument;
248 if (this.hasChildNodes()) {
249 // Don't store the collected child nodes immediately,
250 // collecting the child nodes could trigger constructors
251 // which would blow away our list.
253 const nsIDOMNodeFilter = Components.interfaces.nsIDOMNodeFilter;
254 var iterator = doc.createTreeWalker(this,
255 nsIDOMNodeFilter.SHOW_ELEMENT,
256 this._filterRadioGroup);
257 while (iterator.nextNode())
258 radioChildren.push(iterator.currentNode);
259 return this._radioChildren = radioChildren;
260 }
262 // We don't have child nodes.
263 const XUL_NS = "http://www.mozilla.org/keymaster/"
264 + "gatekeeper/there.is.only.xul";
265 var elems = doc.getElementsByAttribute("group", this.id);
266 for (var i = 0; i < elems.length; i++) {
267 if ((elems[i].namespaceURI == XUL_NS) &&
268 (elems[i].localName == "radio")) {
269 radioChildren.push(elems[i]);
270 }
271 }
272 return this._radioChildren = radioChildren;
273 ]]>
274 </body>
275 </method>
276 <method name="_filterRadioGroup">
277 <parameter name="node"/>
278 <body>
279 <![CDATA[
280 switch (node.localName) {
281 case "radio": return NodeFilter.FILTER_ACCEPT;
282 case "template":
283 case "radiogroup": return NodeFilter.FILTER_REJECT;
284 default: return NodeFilter.FILTER_SKIP;
285 }
286 ]]>
287 </body>
288 </method>
290 <method name="getIndexOfItem">
291 <parameter name="item"/>
292 <body>
293 return this._getRadioChildren().indexOf(item);
294 </body>
295 </method>
297 <method name="getItemAtIndex">
298 <parameter name="index"/>
299 <body>
300 <![CDATA[
301 var children = this._getRadioChildren();
302 return (index >= 0 && index < children.length) ? children[index] : null;
303 ]]>
304 </body>
305 </method>
307 <method name="appendItem">
308 <parameter name="label"/>
309 <parameter name="value"/>
310 <body>
311 <![CDATA[
312 var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
313 var radio = document.createElementNS(XULNS, "radio");
314 radio.setAttribute("label", label);
315 radio.setAttribute("value", value);
316 this.appendChild(radio);
317 this._radioChildren = null;
318 return radio;
319 ]]>
320 </body>
321 </method>
323 <method name="insertItemAt">
324 <parameter name="index"/>
325 <parameter name="label"/>
326 <parameter name="value"/>
327 <body>
328 <![CDATA[
329 var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
330 var radio = document.createElementNS(XULNS, "radio");
331 radio.setAttribute("label", label);
332 radio.setAttribute("value", value);
333 var before = this.getItemAtIndex(index);
334 if (before)
335 before.parentNode.insertBefore(radio, before);
336 else
337 this.appendChild(radio);
338 this._radioChildren = null;
339 return radio;
340 ]]>
341 </body>
342 </method>
344 <method name="removeItemAt">
345 <parameter name="index"/>
346 <body>
347 <![CDATA[
348 var remove = this.getItemAtIndex(index);
349 if (remove) {
350 remove.parentNode.removeChild(remove);
351 this._radioChildren = null;
352 }
353 return remove;
354 ]]>
355 </body>
356 </method>
357 </implementation>
359 <handlers>
360 <handler event="mousedown">
361 if (this.disabled)
362 event.preventDefault();
363 </handler>
365 <!-- keyboard navigation -->
366 <!-- Here's how keyboard navigation works in radio groups on Windows:
367 The group takes 'focus'
368 The user is then free to navigate around inside the group
369 using the arrow keys. Accessing previous or following radio buttons
370 is done solely through the arrow keys and not the tab button. Tab
371 takes you to the next widget in the tab order -->
372 <handler event="keypress" key=" " phase="target">
373 this.selectedItem = this.focusedItem;
374 this.selectedItem.doCommand();
375 </handler>
376 <handler event="keypress" keycode="VK_UP" phase="target">
377 this.checkAdjacentElement(false);
378 event.stopPropagation();
379 </handler>
380 <handler event="keypress" keycode="VK_LEFT" phase="target">
381 // left arrow goes back when we are ltr, forward when we are rtl
382 this.checkAdjacentElement(document.defaultView.getComputedStyle(
383 this, "").direction == "rtl");
384 event.stopPropagation();
385 </handler>
386 <handler event="keypress" keycode="VK_DOWN" phase="target">
387 this.checkAdjacentElement(true);
388 event.stopPropagation();
389 </handler>
390 <handler event="keypress" keycode="VK_RIGHT" phase="target">
391 // right arrow goes forward when we are ltr, back when we are rtl
392 this.checkAdjacentElement(document.defaultView.getComputedStyle(
393 this, "").direction == "ltr");
394 event.stopPropagation();
395 </handler>
397 <!-- set a focused attribute on the selected item when the group
398 receives focus so that we can style it as if it were focused even though
399 it is not (Windows platform behaviour is for the group to receive focus,
400 not the item -->
401 <handler event="focus" phase="target">
402 <![CDATA[
403 this.setAttribute("focused", "true");
404 if (this.focusedItem)
405 return;
407 var val = this.selectedItem;
408 if (!val || val.disabled || val.hidden || val.collapsed) {
409 var children = this._getRadioChildren();
410 for (var i = 0; i < children.length; ++i) {
411 if (!children[i].hidden && !children[i].collapsed && !children[i].disabled) {
412 val = children[i];
413 break;
414 }
415 }
416 }
417 this.focusedItem = val;
418 ]]>
419 </handler>
420 <handler event="blur" phase="target">
421 this.removeAttribute("focused");
422 this.focusedItem = null;
423 </handler>
424 </handlers>
425 </binding>
427 <binding id="radio" role="xul:radiobutton"
428 extends="chrome://global/content/bindings/general.xml#control-item">
429 <resources>
430 <stylesheet src="chrome://global/skin/radio.css"/>
431 </resources>
433 <content>
434 <xul:image class="radio-check" xbl:inherits="disabled,selected"/>
435 <xul:hbox class="radio-label-box" align="center" flex="1">
436 <xul:image class="radio-icon" xbl:inherits="src"/>
437 <xul:label class="radio-label" xbl:inherits="xbl:text=label,accesskey,crop" flex="1"/>
438 </xul:hbox>
439 </content>
441 <implementation implements="nsIDOMXULSelectControlItemElement">
442 <constructor>
443 <![CDATA[
444 // Just clear out the parent's cached list of radio children
445 var control = this.control;
446 if (control)
447 control._radioChildren = null;
448 ]]>
449 </constructor>
450 <destructor>
451 <![CDATA[
452 if (!this.radioGroup)
453 return;
455 var radioList = this.radioGroup.mRadioChildren;
456 if (!radioList)
457 return;
458 for (var i = 0; i < radioList.length; ++i) {
459 if (radioList[i] == this) {
460 radioList.splice(i, 1);
461 return;
462 }
463 }
464 ]]>
465 </destructor>
466 <property name="selected" readonly="true">
467 <getter>
468 <![CDATA[
469 return this.hasAttribute('selected');
470 ]]>
471 </getter>
472 </property>
473 <property name="radioGroup" readonly="true" onget="return this.control"/>
474 <property name="control" readonly="true">
475 <getter>
476 <![CDATA[
477 const XUL_NS = "http://www.mozilla.org/keymaster/"
478 + "gatekeeper/there.is.only.xul";
479 var parent = this.parentNode;
480 while (parent) {
481 if ((parent.namespaceURI == XUL_NS) &&
482 (parent.localName == "radiogroup")) {
483 return parent;
484 }
485 parent = parent.parentNode;
486 }
488 var group = this.getAttribute("group");
489 if (!group) {
490 return null;
491 }
493 parent = this.ownerDocument.getElementById(group);
494 if (!parent ||
495 (parent.namespaceURI != XUL_NS) ||
496 (parent.localName != "radiogroup")) {
497 parent = null;
498 }
499 return parent;
500 ]]>
501 </getter>
502 </property>
503 </implementation>
504 <handlers>
505 <handler event="click" button="0">
506 <![CDATA[
507 if (!this.disabled)
508 this.control.selectedItem = this;
509 ]]>
510 </handler>
512 <handler event="mousedown" button="0">
513 <![CDATA[
514 if (!this.disabled)
515 this.control.focusedItem = this;
516 ]]>
517 </handler>
518 </handlers>
519 </binding>
520 </bindings>