toolkit/content/widgets/radio.xml

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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>

mercurial