toolkit/content/widgets/menulist.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="menulistBindings"
     8    xmlns="http://www.mozilla.org/xbl"
     9    xmlns:html="http://www.w3.org/1999/xhtml"
    10    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    11    xmlns:xbl="http://www.mozilla.org/xbl">
    13   <binding id="menulist-base" extends="chrome://global/content/bindings/general.xml#basecontrol">
    14     <resources>
    15       <stylesheet src="chrome://global/content/menulist.css"/>
    16       <stylesheet src="chrome://global/skin/menulist.css"/>
    17     </resources>
    18   </binding>
    20   <binding id="menulist" display="xul:menu" role="xul:menulist"
    21            extends="chrome://global/content/bindings/menulist.xml#menulist-base">
    22     <content sizetopopup="pref">
    23       <xul:hbox class="menulist-label-box" flex="1">
    24         <xul:image class="menulist-icon" xbl:inherits="src=image,src"/>
    25         <xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
    26       </xul:hbox>
    27       <xul:dropmarker class="menulist-dropmarker" type="menu" xbl:inherits="disabled,open"/>
    28       <children includes="menupopup"/>
    29     </content>
    31     <handlers>
    32       <handler event="command" phase="capturing"
    33         action="if (event.target.parentNode.parentNode == this) this.selectedItem = event.target;"/>
    35       <handler event="popupshowing">
    36         <![CDATA[
    37           if (event.target.parentNode == this) {
    38             this.menuBoxObject.activeChild = null;
    39             if (this.selectedItem)
    40               // Not ready for auto-setting the active child in hierarchies yet.
    41               // For now, only do this when the outermost menupopup opens.
    42               this.menuBoxObject.activeChild = this.mSelectedInternal;
    43           }
    44         ]]>
    45       </handler>
    47       <handler event="keypress" modifiers="shift any" group="system">
    48         <![CDATA[
    49           if (!event.defaultPrevented &&
    50               (event.keyCode == KeyEvent.DOM_VK_UP ||
    51                event.keyCode == KeyEvent.DOM_VK_DOWN ||
    52                event.keyCode == KeyEvent.DOM_VK_PAGE_UP ||
    53                event.keyCode == KeyEvent.DOM_VK_PAGE_DOWN ||
    54                event.keyCode == KeyEvent.DOM_VK_HOME ||
    55                event.keyCode == KeyEvent.DOM_VK_END ||
    56                event.keyCode == KeyEvent.DOM_VK_BACK_SPACE ||
    57                event.charCode > 0)) {
    58             // Moving relative to an item: start from the currently selected item
    59             this.menuBoxObject.activeChild = this.mSelectedInternal;
    60             if (this.menuBoxObject.handleKeyPress(event)) {
    61               this.menuBoxObject.activeChild.doCommand();
    62               event.preventDefault();
    63             }
    64           }
    65         ]]>
    66       </handler>
    67     </handlers>
    69     <implementation implements="nsIDOMXULMenuListElement, nsIDOMEventListener">
    70       <constructor>
    71         this.mInputField = null;
    72         this.mSelectedInternal = null;
    73         this.menuBoxObject = this.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject);
    74         this.setInitialSelection();
    75       </constructor>
    77       <method name="setInitialSelection">
    78         <body>
    79           <![CDATA[
    80             var popup = this.menupopup;
    81             if (popup) {
    82               var arr = popup.getElementsByAttribute('selected', 'true');
    84               var editable = this.editable;
    85               var value = this.value;
    86               if (!arr.item(0) && value)
    87                 arr = popup.getElementsByAttribute(editable ? 'label' : 'value', value);
    89               if (arr.item(0))
    90                 this.selectedItem = arr[0];
    91               else if (!editable)
    92                 this.selectedIndex = 0;
    93             }
    94           ]]>
    95         </body>
    96       </method>
    98       <property name="value" onget="return this.getAttribute('value');">
    99         <setter>
   100           <![CDATA[
   101             // if the new value is null, we still need to remove the old value
   102             if (val == null)
   103               return this.selectedItem = val;
   105             var arr = null;
   106             var popup = this.menupopup;
   107             if (popup)
   108               arr = popup.getElementsByAttribute('value', val);
   110             if (arr && arr.item(0))
   111               this.selectedItem = arr[0];
   112             else {
   113               this.selectedItem = null;
   114               this.setAttribute('value', val);
   115             }
   117             return val;
   118           ]]>
   119         </setter>
   120       </property>
   122       <property name="inputField" readonly="true" onget="return null;"/>
   124       <property name="crop" onset="this.setAttribute('crop',val); return val;"
   125                             onget="return this.getAttribute('crop');"/>
   126       <property name="image"  onset="this.setAttribute('image',val); return val;"
   127                               onget="return this.getAttribute('image');"/>
   128       <property name="label" readonly="true" onget="return this.getAttribute('label');"/>
   129       <property name="description" onset="this.setAttribute('description',val); return val;"
   130                                    onget="return this.getAttribute('description');"/>
   131       <property name="editable"  onset="this.setAttribute('editable',val); return val;"
   132                                  onget="return this.getAttribute('editable') == 'true';"/>
   134       <property name="open" onset="this.menuBoxObject.openMenu(val);
   135                                    return val;"
   136                             onget="return this.hasAttribute('open');"/>
   138       <property name="itemCount" readonly="true"
   139                 onget="return this.menupopup ? this.menupopup.childNodes.length : 0"/>
   141       <property name="menupopup" readonly="true">
   142         <getter>
   143           <![CDATA[
   144             var popup = this.firstChild;
   145             while (popup && popup.localName != "menupopup")
   146               popup = popup.nextSibling;
   147             return popup;
   148           ]]>
   149         </getter>
   150       </property>
   152       <method name="contains">
   153         <parameter name="item"/>
   154         <body>
   155           <![CDATA[
   156             if (!item)
   157               return false;
   159             var parent = item.parentNode;
   160             return (parent && parent.parentNode == this);
   161           ]]>
   162         </body>
   163       </method>
   165       <property name="selectedIndex">
   166         <getter>
   167           <![CDATA[
   168             // Quick and dirty. We won't deal with hierarchical menulists yet.
   169             if (!this.selectedItem ||
   170                 !this.mSelectedInternal.parentNode ||
   171                 this.mSelectedInternal.parentNode.parentNode != this)
   172               return -1;
   174             var children = this.mSelectedInternal.parentNode.childNodes;
   175             var i = children.length;
   176             while (i--)
   177               if (children[i] == this.mSelectedInternal)
   178                 break;
   180             return i;
   181           ]]>
   182         </getter>
   183         <setter>
   184           <![CDATA[
   185             var popup = this.menupopup;
   186             if (popup && 0 <= val) {
   187               if (val < popup.childNodes.length)
   188                 this.selectedItem = popup.childNodes[val];
   189             }
   190             else
   191               this.selectedItem = null;
   192             return val;
   193           ]]>
   194         </setter>
   195       </property>
   197       <property name="selectedItem">
   198         <getter>
   199           <![CDATA[
   200             return this.mSelectedInternal;
   201           ]]>
   202         </getter>
   203         <setter>
   204           <![CDATA[
   205             var oldval = this.mSelectedInternal;
   206             if (oldval == val)
   207               return val;
   209             if (val && !this.contains(val))
   210               return val;
   212             if (oldval) {
   213               oldval.removeAttribute('selected');
   214               if (document instanceof Components.interfaces.nsIDOMXULDocument) {
   215                 document.removeBroadcastListenerFor(oldval, this, "value");
   216                 document.removeBroadcastListenerFor(oldval, this, "label");
   217                 document.removeBroadcastListenerFor(oldval, this, "image");
   218                 document.removeBroadcastListenerFor(oldval, this, "description");
   219               }
   220               else
   221                 oldval.removeEventListener("DOMAttrModified", this, false);
   222             }
   224             this.mSelectedInternal = val;
   225             if (val) {
   226               val.setAttribute('selected', 'true');
   227               this.setAttribute('value', val.getAttribute('value'));
   228               this.setAttribute('image', val.getAttribute('image'));
   229               this.setAttribute('label', val.getAttribute('label'));
   230               this.setAttribute('description', val.getAttribute('description'));
   231               // DOMAttrModified listeners slow down setAttribute calls within
   232               // the document, see bug 395496
   233               if (document instanceof Components.interfaces.nsIDOMXULDocument) {
   234                 document.addBroadcastListenerFor(val, this, "value");
   235                 document.addBroadcastListenerFor(val, this, "label");
   236                 document.addBroadcastListenerFor(val, this, "image");
   237                 document.addBroadcastListenerFor(val, this, "description");
   238               }
   239               else
   240                 val.addEventListener("DOMAttrModified", this, false);
   241             }
   242             else {
   243               this.removeAttribute('value');
   244               this.removeAttribute('image');
   245               this.removeAttribute('label');
   246               this.removeAttribute('description');
   247             }
   249             var event = document.createEvent("Events");
   250             event.initEvent("select", true, true);
   251             this.dispatchEvent(event);
   253             var event = document.createEvent("Events");
   254             event.initEvent("ValueChange", true, true);
   255             this.dispatchEvent(event);
   257             return val;
   258           ]]>
   259         </setter>
   260       </property>
   262       <method name="handleEvent">
   263         <parameter name="aEvent"/>
   264         <body>
   265           <![CDATA[
   266             if (aEvent.type == "DOMAttrModified" &&
   267                 aEvent.target == this.mSelectedInternal) {
   268               var attrName = aEvent.attrName;
   269               switch (attrName) {
   270                 case "value":
   271                 case "label":
   272                 case "image":
   273                 case "description":
   274                   this.setAttribute(attrName, aEvent.newValue);
   275               }
   276             }
   277           ]]>
   278         </body>
   279       </method>
   281       <method name="getIndexOfItem">
   282         <parameter name="item"/>
   283         <body>
   284         <![CDATA[
   285           var popup = this.menupopup;
   286           if (popup) {
   287             var children = popup.childNodes;
   288             var i = children.length;
   289             while (i--)
   290               if (children[i] == item)
   291                 return i;
   292           }
   293           return -1;
   294         ]]>
   295         </body>
   296       </method>
   298       <method name="getItemAtIndex">
   299         <parameter name="index"/>
   300         <body>
   301         <![CDATA[
   302           var popup = this.menupopup;
   303           if (popup) {
   304             var children = popup.childNodes;
   305             if (index >= 0 && index < children.length)
   306               return children[index];
   307           }
   308           return null;
   309         ]]>
   310         </body>
   311       </method>
   313       <method name="appendItem">
   314         <parameter name="label"/>
   315         <parameter name="value"/>
   316         <parameter name="description"/>
   317         <body>
   318         <![CDATA[
   319           const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
   320           var popup = this.menupopup ||
   321                       this.appendChild(document.createElementNS(XULNS, "menupopup"));
   322           var item = document.createElementNS(XULNS, "menuitem");
   323           item.setAttribute("label", label);
   324           item.setAttribute("value", value);
   325           if (description)
   326             item.setAttribute("description", description);
   328           popup.appendChild(item);
   329           return item;
   330         ]]>
   331         </body>
   332       </method>
   334       <method name="insertItemAt">
   335         <parameter name="index"/>
   336         <parameter name="label"/>
   337         <parameter name="value"/>
   338         <parameter name="description"/>
   339         <body>
   340         <![CDATA[
   341           const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
   342           var popup = this.menupopup ||
   343                       this.appendChild(document.createElementNS(XULNS, "menupopup"));
   344           var item = document.createElementNS(XULNS, "menuitem");
   345           item.setAttribute("label", label);
   346           item.setAttribute("value", value);
   347           if (description)
   348             item.setAttribute("description", description);
   350           if (index >= 0 && index < popup.childNodes.length)
   351             popup.insertBefore(item, popup.childNodes[index]);
   352           else
   353             popup.appendChild(item);
   354           return item;
   355         ]]>
   356         </body>
   357       </method>
   359       <method name="removeItemAt">
   360         <parameter name="index"/>
   361         <body>
   362         <![CDATA[
   363           var popup = this.menupopup;
   364           if (popup && 0 <= index && index < popup.childNodes.length) {
   365             var remove = popup.childNodes[index];
   366             popup.removeChild(remove);
   367             return remove;
   368           }
   369           return null;
   370         ]]>
   371         </body>
   372       </method>
   374       <method name="removeAllItems">
   375         <body>
   376         <![CDATA[
   377           this.selectedItem = null;
   378           var popup = this.menupopup;
   379           if (popup)
   380             this.removeChild(popup);
   381         ]]>
   382         </body>
   383       </method>
   385       <destructor>
   386         <![CDATA[
   387           if (this.mSelectedInternal) {
   388             if (document instanceof Components.interfaces.nsIDOMXULDocument) {
   389               document.removeBroadcastListenerFor(this.mSelectedInternal, this, "value");
   390               document.removeBroadcastListenerFor(this.mSelectedInternal, this, "label");
   391               document.removeBroadcastListenerFor(this.mSelectedInternal, this, "image");
   392               document.removeBroadcastListenerFor(this.mSelectedInternal, this, "description");
   393             }
   394             else
   395               this.mSelectedInternal.removeEventListener("DOMAttrModified", this, false);
   396           }
   397         ]]>
   398       </destructor>
   399     </implementation>
   400   </binding>
   402   <binding id="menulist-editable" extends="chrome://global/content/bindings/menulist.xml#menulist">
   403     <content sizetopopup="pref">
   404       <xul:hbox class="menulist-editable-box textbox-input-box" xbl:inherits="context,disabled,readonly,focused" flex="1">
   405         <html:input class="menulist-editable-input" anonid="input" allowevents="true"
   406                     xbl:inherits="value=label,value,disabled,tabindex,readonly,placeholder"/>
   407       </xul:hbox>
   408       <xul:dropmarker class="menulist-dropmarker" type="menu"
   409                       xbl:inherits="open,disabled,parentfocused=focused"/>
   410       <children includes="menupopup"/>
   411     </content>
   413     <implementation>
   414       <method name="_selectInputFieldValueInList">
   415         <body>
   416         <![CDATA[
   417           if (this.hasAttribute("disableautoselect"))
   418             return;
   420           // Find and select the menuitem that matches inputField's "value"
   421           var arr = null;
   422           var popup = this.menupopup;
   424           if (popup)
   425             arr = popup.getElementsByAttribute('label', this.inputField.value);
   427           this.setSelectionInternal(arr ? arr.item(0) : null);
   428         ]]>
   429         </body>
   430       </method>
   432       <method name="setSelectionInternal">
   433         <parameter name="val"/>
   434         <body>
   435           <![CDATA[
   436             // This is called internally to set selected item
   437             //  without triggering infinite loop
   438             //  when using selectedItem's setter
   439             if (this.mSelectedInternal == val)
   440               return val;
   442             if (this.mSelectedInternal)
   443               this.mSelectedInternal.removeAttribute('selected');
   445             this.mSelectedInternal = val;
   447             if (val)
   448               val.setAttribute('selected', 'true');
   450             //Do NOT change the "value", which is owned by inputField
   451             return val;
   452           ]]>
   453         </body>
   454       </method>
   456       <property name="inputField" readonly="true">
   457         <getter><![CDATA[
   458           if (!this.mInputField)
   459             this.mInputField = document.getAnonymousElementByAttribute(this, "anonid", "input");
   460           return this.mInputField;
   461         ]]></getter>
   462       </property>
   464       <property name="label"      onset="this.inputField.value = val; return val;"
   465                                   onget="return this.inputField.value;"/>
   467       <property name="value"      onget="return this.inputField.value;">
   468         <setter>
   469         <![CDATA[
   470           // Override menulist's value setter to refer to the inputField's value
   471           // (Allows using "menulist.value" instead of "menulist.inputField.value")
   472           this.inputField.value = val;
   473           this.setAttribute('value', val);
   474           this.setAttribute('label', val);
   475           this._selectInputFieldValueInList();
   476           return val;
   477         ]]>
   478         </setter>
   479       </property>
   481       <property name="selectedItem">
   482         <getter>
   483           <![CDATA[
   484             // Make sure internally-selected item
   485             //  is in sync with inputField.value
   486             this._selectInputFieldValueInList();
   487             return this.mSelectedInternal;
   488           ]]>
   489         </getter>
   490         <setter>
   491           <![CDATA[
   492             var oldval = this.mSelectedInternal;
   493             if (oldval == val)
   494               return val;
   496             if (val && !this.contains(val))
   497               return val;
   499             // This doesn't touch inputField.value or "value" and "label" attributes
   500             this.setSelectionInternal(val);
   501             if (val) {
   502               // Editable menulist uses "label" as its "value"
   503               var label = val.getAttribute('label');
   504               this.inputField.value = label;
   505               this.setAttribute('value', label);
   506               this.setAttribute('label', label);
   507             }
   508             else {
   509               this.inputField.value = "";
   510               this.removeAttribute('value');
   511               this.removeAttribute('label');
   512             }
   514             var event = document.createEvent("Events");
   515             event.initEvent("select", true, true);
   516             this.dispatchEvent(event);
   518             var event = document.createEvent("Events");
   519             event.initEvent("ValueChange", true, true);
   520             this.dispatchEvent(event);
   522             return val;
   523           ]]>
   524         </setter>
   525       </property>
   526       <property name="disableautoselect"
   527                 onset="if (val) this.setAttribute('disableautoselect','true');
   528                        else this.removeAttribute('disableautoselect'); return val;"
   529                 onget="return this.hasAttribute('disableautoselect');"/>
   531       <property name="editor" readonly="true">
   532         <getter><![CDATA[
   533           const nsIDOMNSEditableElement = Components.interfaces.nsIDOMNSEditableElement;
   534           return this.inputField.QueryInterface(nsIDOMNSEditableElement).editor;
   535         ]]></getter>
   536       </property>
   538       <property name="readOnly"   onset="this.inputField.readOnly = val;
   539                                          if (val) this.setAttribute('readonly', 'true');
   540                                          else this.removeAttribute('readonly'); return val;"
   541                                   onget="return this.inputField.readOnly;"/>
   543       <method name="select">
   544         <body>
   545           this.inputField.select();
   546         </body>
   547       </method>
   548     </implementation>
   550     <handlers>
   551       <handler event="focus" phase="capturing">
   552         <![CDATA[
   553           this.setAttribute('focused','true');
   554         ]]>
   555       </handler>
   557       <handler event="blur" phase="capturing">
   558         <![CDATA[
   559           this.removeAttribute('focused');
   560         ]]>
   561       </handler>
   563       <handler event="popupshowing">
   564         <![CDATA[
   565           // editable menulists elements aren't in the focus order,
   566           // so when the popup opens we need to force the focus to the inputField
   567           if (event.target.parentNode == this) {
   568             if (document.commandDispatcher.focusedElement != this.inputField)
   569               this.inputField.focus();
   571             this.menuBoxObject.activeChild = null;
   572             if (this.selectedItem)
   573               // Not ready for auto-setting the active child in hierarchies yet.
   574               // For now, only do this when the outermost menupopup opens.
   575               this.menuBoxObject.activeChild = this.mSelectedInternal;
   576           }
   577         ]]>
   578       </handler>
   580       <handler event="keypress">
   581         <![CDATA[
   582           // open popup if key is up arrow, down arrow, or F4
   583           if (!event.ctrlKey && !event.shiftKey) {
   584             if (event.keyCode == KeyEvent.DOM_VK_UP ||
   585                 event.keyCode == KeyEvent.DOM_VK_DOWN ||
   586                 (event.keyCode == KeyEvent.DOM_VK_F4 && !event.altKey)) {
   587               event.preventDefault();
   588               this.open = true;
   589             }
   590           }
   591         ]]>
   592       </handler>
   593     </handlers>
   594   </binding>
   596   <binding id="menulist-compact" display="xul:menu"
   597            extends="chrome://global/content/bindings/menulist.xml#menulist">
   598     <content sizetopopup="false">
   599       <xul:dropmarker class="menulist-dropmarker" type="menu" xbl:inherits="disabled,open"/>
   600       <xul:image class="menulist-icon" xbl:inherits="src=image,src"/>
   601       <xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
   602       <children includes="menupopup"/>
   603     </content>
   604   </binding>
   606   <binding id="menulist-description" display="xul:menu"
   607            extends="chrome://global/content/bindings/menulist.xml#menulist">
   608     <content sizetopopup="pref">
   609       <xul:hbox class="menulist-label-box" flex="1">
   610         <xul:image class="menulist-icon" xbl:inherits="src=image,src"/>
   611         <xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
   612         <xul:label class="menulist-label menulist-description" xbl:inherits="value=description" crop="right" flex="10000"/>
   613       </xul:hbox>
   614       <xul:dropmarker class="menulist-dropmarker" type="menu" xbl:inherits="disabled,open"/>
   615       <children includes="menupopup"/>
   616     </content>
   617   </binding>
   618 </bindings>

mercurial