Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 cr.define('cr.ui', function() {
      6   /** @const */ var Command = cr.ui.Command;
      7 
      8   /**
      9    * Creates a new menu item element.
     10    * @param {Object=} opt_propertyBag Optional properties.
     11    * @constructor
     12    * @extends {HTMLDivElement}
     13    */
     14   var MenuItem = cr.ui.define('div');
     15 
     16   /**
     17    * Creates a new menu separator element.
     18    * @return {cr.ui.MenuItem} The new separator element.
     19    */
     20   MenuItem.createSeparator = function() {
     21     var el = cr.doc.createElement('hr');
     22     MenuItem.decorate(el);
     23     return el;
     24   };
     25 
     26   MenuItem.prototype = {
     27     __proto__: HTMLButtonElement.prototype,
     28 
     29     /**
     30      * Initializes the menu item.
     31      */
     32     decorate: function() {
     33       var commandId;
     34       if ((commandId = this.getAttribute('command')))
     35         this.command = commandId;
     36 
     37       this.addEventListener('mouseup', this.handleMouseUp_);
     38 
     39       // Adding the 'custom-appearance' class prevents widgets.css from changing
     40       // the appearance of this element.
     41       this.classList.add('custom-appearance');
     42     },
     43 
     44     /**
     45      * The command associated with this menu item. If this is set to a string
     46      * of the form "#element-id" then the element is looked up in the document
     47      * of the command.
     48      * @type {cr.ui.Command}
     49      */
     50     command_: null,
     51     get command() {
     52       return this.command_;
     53     },
     54     set command(command) {
     55       if (this.command_) {
     56         this.command_.removeEventListener('labelChange', this);
     57         this.command_.removeEventListener('disabledChange', this);
     58         this.command_.removeEventListener('hiddenChange', this);
     59         this.command_.removeEventListener('checkedChange', this);
     60       }
     61 
     62       if (typeof command == 'string' && command[0] == '#') {
     63         command = this.ownerDocument.getElementById(command.slice(1));
     64         cr.ui.decorate(command, Command);
     65       }
     66 
     67       this.command_ = command;
     68       if (command) {
     69         if (command.id)
     70           this.setAttribute('command', '#' + command.id);
     71 
     72         this.label = command.label;
     73         this.disabled = command.disabled;
     74         this.hidden = command.hidden;
     75 
     76         this.command_.addEventListener('labelChange', this);
     77         this.command_.addEventListener('disabledChange', this);
     78         this.command_.addEventListener('hiddenChange', this);
     79         this.command_.addEventListener('checkedChange', this);
     80       }
     81     },
     82 
     83     /**
     84      * The text label.
     85      * @type {string}
     86      */
     87     get label() {
     88       return this.textContent;
     89     },
     90     set label(label) {
     91       this.textContent = label;
     92     },
     93 
     94     /**
     95      * @return {boolean} Whether the menu item is a separator.
     96      */
     97     isSeparator: function() {
     98       return this.tagName == 'HR';
     99     },
    100 
    101     /**
    102      * Handles mouseup events. This dispatches an active event and if there
    103      * is an assiciated command then that is executed.
    104      * @param {Event} The mouseup event object.
    105      * @private
    106      */
    107     handleMouseUp_: function(e) {
    108       if (!this.disabled && !this.isSeparator() && this.selected) {
    109         // Dispatch command event followed by executing the command object.
    110         if (cr.dispatchSimpleEvent(this, 'activate', true, true)) {
    111           var command = this.command;
    112           if (command)
    113             command.execute();
    114         }
    115       }
    116     },
    117 
    118     /**
    119      * Handles changes to the associated command.
    120      * @param {Event} e The event object.
    121      */
    122     handleEvent: function(e) {
    123       switch (e.type) {
    124         case 'disabledChange':
    125           this.disabled = this.command.disabled;
    126           break;
    127         case 'hiddenChange':
    128           this.hidden = this.command.hidden;
    129           break;
    130         case 'labelChange':
    131           this.label = this.command.label;
    132           break;
    133         case 'checkedChange':
    134           this.checked = this.command.checked;
    135           break;
    136       }
    137     }
    138   };
    139 
    140   /**
    141    * Whether the menu item is disabled or not.
    142    * @type {boolean}
    143    */
    144   cr.defineProperty(MenuItem, 'disabled', cr.PropertyKind.BOOL_ATTR);
    145 
    146   /**
    147    * Whether the menu item is hidden or not.
    148    * @type {boolean}
    149    */
    150   cr.defineProperty(MenuItem, 'hidden', cr.PropertyKind.BOOL_ATTR);
    151 
    152   /**
    153    * Whether the menu item is selected or not.
    154    * @type {boolean}
    155    */
    156   cr.defineProperty(MenuItem, 'selected', cr.PropertyKind.BOOL_ATTR);
    157 
    158   /**
    159    * Whether the menu item is checked or not.
    160    * @type {boolean}
    161    */
    162   cr.defineProperty(MenuItem, 'checked', cr.PropertyKind.BOOL_ATTR);
    163 
    164   // Export
    165   return {
    166     MenuItem: MenuItem
    167   };
    168 });
    169