text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  // clang-format off
  // #import {MenuItem} from 'chrome://resources/js/cr/ui/menu_item.m.js';
  // #import {util} from '../../../common/js/util.m.js';
  // #import {FilesMenuItem} from './files_menu.m.js';
  // #import {decorate} from 'chrome://resources/js/cr/ui.m.js';
  // #import {MultiMenuButton} from './multi_menu_button.m.js';
  // #import {getPropertyDescriptor, PropertyKind} from 'chrome://resources/js/cr.m.js';
  // clang-format on
  
  /**
   * @fileoverview This implements a combobutton control.
   */
  cr.define('cr.ui', () => {
    /**
     * Creates a new combo button element.
     */
    /* #export */ class ComboButton extends cr.ui.MultiMenuButton {
      constructor() {
        super();
  
        /** @private {?cr.ui.MenuItem} */
        this.defaultItem_ = null;
  
        /** @private {?Element} */
        this.trigger_ = null;
  
        /** @private {?Element} */
        this.actionNode_ = null;
  
        /** @private {?Element} */
        this.filesToggleRipple_ = null;
  
        /** @private {boolean} */
        this.disabled = false;
  
        /** @private {boolean} */
        this.multiple = false;
      }
  
      /**
       * Truncates drop-down list.
       */
      clear() {
        this.menu.clear();
        this.multiple = false;
      }
  
      addDropDownItem(item) {
        this.multiple = true;
        const menuitem = this.menu.addMenuItem(item);
  
        // If menu is files-menu, decorate menu item as FilesMenuItem.
        if (this.menu.classList.contains('files-menu')) {
          cr.ui.decorate(menuitem, cr.ui.FilesMenuItem);
        }
  
        menuitem.data = item;
        if (item.iconType) {
          menuitem.style.backgroundImage = '';
          menuitem.setAttribute('file-type-icon', item.iconType);
        }
        if (item.bold) {
          menuitem.style.fontWeight = 'bold';
        }
        return menuitem;
      }
  
      /**
       * Adds separator to drop-down list.
       */
      addSeparator() {
        this.menu.addSeparator();
      }
  
      /**
       * Default item to fire on combobox click
       */
      get defaultItem() {
        return this.defaultItem_;
      }
      setDefaultItem_(defaultItem) {
        this.defaultItem_ = defaultItem;
        this.actionNode_.textContent = defaultItem.label || '';
      }
      set defaultItem(defaultItem) {
        this.setDefaultItem_(defaultItem);
      }
  
      /**
       * Utility function to set a boolean property get/setter.
       * @param {string} property Name of the property.
       */
      addBooleanProperty_(property) {
        Object.defineProperty(this, property, {
          get() {
            return this.getAttribute(property);
          },
          set(value) {
            if (value) {
              this.setAttribute(property, property);
            } else {
              this.removeAttribute(property);
            }
          },
          enumerable: true,
          configurable: true
        });
      }
  
      /**
       * cr.ui.decorate expects a static |decorate| method.
       *
       * @param {!Element} el Element to be decorated.
       * @return {!cr.ui.ComboButton} Decorated element.
       * @public
       */
      static decorate(el) {
        // Add the ComboButton methods to the element we're
        // decorating, leaving it's prototype chain intact.
        // Don't copy 'constructor' or property get/setters.
        Object.getOwnPropertyNames(ComboButton.prototype).forEach(name => {
          if (name !== 'constructor' && name !== 'multiple' &&
              name !== 'disabled') {
            el[name] = ComboButton.prototype[name];
          }
        });
        Object.getOwnPropertyNames(cr.ui.MultiMenuButton.prototype)
            .forEach(name => {
              if (name !== 'constructor' &&
                  !Object.getOwnPropertyDescriptor(el, name)) {
                el[name] = cr.ui.MultiMenuButton.prototype[name];
              }
            });
        // Set up the 'menu, defaultItem, multiple and disabled'
        // properties & setter/getters.
        Object.defineProperty(el, 'menu', {
          get() {
            return this.menu_;
          },
          set(menu) {
            this.setMenu_(menu);
          },
          enumerable: true,
          configurable: true
        });
        Object.defineProperty(el, 'defaultItem', {
          get() {
            return this.defaultItem_;
          },
          set(defaultItem) {
            this.setDefaultItem_(defaultItem);
          },
          enumerable: true,
          configurable: true
        });
        el.addBooleanProperty_('multiple');
        el.addBooleanProperty_('disabled');
        el = /** @type {!cr.ui.ComboButton} */ (el);
        el.decorate();
        return el;
      }
  
      /**
       * Initializes the element.
       */
      decorate() {
        cr.ui.MultiMenuButton.prototype.decorate.call(this);
  
        this.classList.add('combobutton');
  
        const buttonLayer = this.ownerDocument.createElement('div');
        buttonLayer.classList.add('button');
        this.appendChild(buttonLayer);
  
        this.actionNode_ = this.ownerDocument.createElement('div');
        this.actionNode_.classList.add('action');
        buttonLayer.appendChild(this.actionNode_);
  
        const triggerIcon = this.ownerDocument.createElement('iron-icon');
        triggerIcon.setAttribute('icon', 'files:arrow-drop-down');
        this.trigger_ = this.ownerDocument.createElement('div');
        this.trigger_.classList.add('trigger');
        this.trigger_.appendChild(triggerIcon);
  
        buttonLayer.appendChild(this.trigger_);
  
        const ripplesLayer = this.ownerDocument.createElement('div');
        ripplesLayer.classList.add('ripples');
        this.appendChild(ripplesLayer);
        if (util.isFilesNg()) {
          ripplesLayer.setAttribute('hidden', '');
        }
  
        this.filesToggleRipple_ =
            this.ownerDocument.createElement('files-toggle-ripple');
        ripplesLayer.appendChild(this.filesToggleRipple_);
  
        /** @private {!PaperRipple} */
        this.paperRipple_ = /** @type {!PaperRipple} */
            (this.ownerDocument.createElement('paper-ripple'));
        ripplesLayer.appendChild(this.paperRipple_);
  
        this.addEventListener('click', this.handleButtonClick_.bind(this));
        this.addEventListener('menushow', this.handleMenuShow_.bind(this));
        this.addEventListener('menuhide', this.handleMenuHide_.bind(this));
  
        this.trigger_.addEventListener(
            'click', this.handleTriggerClicked_.bind(this));
  
        this.menu.addEventListener(
            'activate', this.handleMenuActivate_.bind(this));
  
        // Remove mousedown event listener created by MultiMenuButton::decorate,
        // and move it down to trigger_.
        this.removeEventListener('mousedown', this);
        this.trigger_.addEventListener('mousedown', this);
      }
  
      /**
       * Handles the keydown event for the menu button.
       */
      handleKeyDown(e) {
        switch (e.key) {
          case 'ArrowDown':
          case 'ArrowUp':
            if (!this.isMenuShown()) {
              this.showMenu(false);
            }
            e.preventDefault();
            break;
          case 'Escape':  // Maybe this is remote desktop playing a prank?
            this.hideMenu();
            break;
        }
      }
  
      handleTriggerClicked_(event) {
        event.stopPropagation();
      }
  
      handleMenuActivate_(event) {
        this.dispatchSelectEvent(event.target.data);
      }
  
      handleButtonClick_(event) {
        if (this.multiple) {
          // When there are multiple choices just show/hide menu.
          if (this.isMenuShown()) {
            this.hideMenu();
          } else {
            this.showMenu(true);
          }
        } else {
          // When there is only 1 choice, just dispatch to open.
          this.paperRipple_.simulatedRipple();
          this.blur();
          this.dispatchSelectEvent(this.defaultItem_);
        }
      }
  
      handleMenuShow_() {
        this.filesToggleRipple_.activated = true;
      }
  
      handleMenuHide_() {
        this.filesToggleRipple_.activated = false;
      }
  
      dispatchSelectEvent(item) {
        const selectEvent = new Event('select');
        selectEvent.item = item;
        this.dispatchEvent(selectEvent);
      }
    }
  
    // #cr_define_end
    return {
      ComboButton: ComboButton,
    };
  });
  