toolkit/content/widgets/radio.xml

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial