Home | History | Annotate | Download | only in webapp
      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 /**
      6  * @fileoverview
      7  * Class representing a menu button and its associated menu items.
      8  */
      9 
     10 'use strict';
     11 
     12 /** @suppress {duplicate} */
     13 var remoting = remoting || {};
     14 
     15 /**
     16  * @constructor
     17  * @param {Element} container The element containing the <button> and <ul>
     18  *     elements comprising the menu. It should have the "menu-button" class.
     19  * @param {function():void=} opt_onShow Optional callback invoked before the
     20  *     menu is shown.
     21  * @param {function():void=} opt_onHide Optional callback after before the
     22  *     menu is hidden.
     23  */
     24 remoting.MenuButton = function(container, opt_onShow, opt_onHide) {
     25   /**
     26    * @type {HTMLElement}
     27    * @private
     28    */
     29   this.button_ = /** @type {HTMLElement} */
     30       (container.querySelector('button,.menu-button-activator'));
     31 
     32   /**
     33    * @type {HTMLElement}
     34    * @private
     35    */
     36   this.menu_ = /** @type {HTMLElement} */ (container.querySelector('ul'));
     37 
     38   /**
     39    * @type {undefined|function():void}
     40    * @private
     41    */
     42   this.onShow_ = opt_onShow;
     43 
     44   /**
     45    * @type {undefined|function():void}
     46    * @private
     47    */
     48   this.onHide_ = opt_onHide;
     49 
     50   /**
     51    * Create a "click-trap" div covering the entire document, but below the
     52    * menu in the z-order. This ensures the the menu can be closed by clicking
     53    * anywhere. Note that adding this event handler to <body> is not enough,
     54    * because elements can prevent event propagation; specifically, the client
     55    * plugin element does this.
     56    *
     57    * @type {HTMLElement}
     58    * @private
     59    */
     60   this.clickTrap_ = /** @type {HTMLElement} */ (document.createElement('div'));
     61   this.clickTrap_.classList.add('menu-button-click-trap');
     62 
     63   /** @type {remoting.MenuButton} */
     64   var that = this;
     65 
     66   var closeHandler = function() {
     67     that.button_.classList.remove(remoting.MenuButton.BUTTON_ACTIVE_CLASS_);
     68     container.removeChild(that.clickTrap_);
     69     if (that.onHide_) {
     70       that.onHide_();
     71     }
     72   };
     73 
     74   var onClick = function() {
     75     if (that.onShow_) {
     76       that.onShow_();
     77     }
     78     that.button_.classList.add(remoting.MenuButton.BUTTON_ACTIVE_CLASS_);
     79     container.appendChild(that.clickTrap_);
     80   };
     81 
     82   this.button_.addEventListener('click', onClick, false);
     83   this.clickTrap_.addEventListener('click', closeHandler, false);
     84   this.menu_.addEventListener('click', closeHandler, false);
     85 };
     86 
     87 /**
     88  * @return {HTMLElement} The button that activates the menu.
     89  */
     90 remoting.MenuButton.prototype.button = function() {
     91   return this.button_;
     92 };
     93 
     94 /**
     95  * @return {HTMLElement} The menu.
     96  */
     97 remoting.MenuButton.prototype.menu = function() {
     98   return this.menu_;
     99 };
    100 
    101 /**
    102  * Set or unset the selected state of an <li> menu item.
    103  * @param {Element} item The menu item to update.
    104  * @param {boolean} selected True to select the item, false to deselect it.
    105  * @return {void} Nothing.
    106  */
    107 remoting.MenuButton.select = function(item, selected) {
    108   if (selected) {
    109     /** @type {DOMTokenList} */(item.classList).add('selected');
    110   } else {
    111     /** @type {DOMTokenList} */(item.classList).remove('selected');
    112   }
    113 };
    114 
    115 /** @const @private */
    116 remoting.MenuButton.BUTTON_ACTIVE_CLASS_ = 'active';
    117