Source: js/context_menu_view.js

/* exported ContextMenuView */
/* global BaseUI, Service */
(function(exports) {
  'use strict';

  var _id = 0;
  /**
   * The ContextMenu UI for BrowserContextMenu.
   *
   * @class ContextMenuView
   * @param {BaseModule} parentModule The BrowserContextMenu instance
   *                                  where this dialog should popup.
   * @extends BaseUI
   */
  function ContextMenuView(parentModule) {
    this.parentModule = parentModule;
    this.containerElement = parentModule.containerElement;
    this.instanceID = _id++;
    this._injected = false;
  }

  ContextMenuView.prototype = Object.create(BaseUI.prototype);


  ContextMenuView.prototype.CLASS_NAME = 'BrowserContextMenu';

  ContextMenuView.prototype.ELEMENT_PREFIX = 'contextmenu-';

  ContextMenuView.prototype.TRANSITION_TIMEOUT = 350;

  ContextMenuView.prototype.customID = function am_customID() {
    return 'context-menu';
  };

  ContextMenuView.prototype._fetchElements = function bcm__fetchElements() {
    this.element = this.containerElement.querySelector('#' + this.CLASS_NAME +
                                                       this.instanceID);
    this.elements = {};

    var toCamelCase = function toCamelCase(str) {
      return str.replace(/\-(.)/g, function replacer(str, p1) {
        return p1.toUpperCase();
      });
    };

    this.elementClasses = ['header', 'list'];

    // Loop and add element with camel style name to Modal Dialog attribute.
    this.elementClasses.forEach(function createElementRef(name) {
      this.elements[toCamelCase(name)] =
        this.element.querySelector('.' + this.ELEMENT_PREFIX + name);
    }, this);
    var cancel = document.createElement('button');
    cancel.id = 'ctx-cancel-button';
    cancel.dataset.action = 'cancel';
    cancel.setAttribute('data-l10n-id', 'cancel');
    this.elements.cancel = cancel;
  };

  ContextMenuView.prototype._registerEvents = function() {
    this.elements.cancel.addEventListener('click', this.hide.bind(this));
  };

  ContextMenuView.prototype.view = function() {
    var id = this.CLASS_NAME + this.instanceID;
    var content = `<form class="contextmenu" role="dialog" tabindex="-1"
              data-type="action" id="${id}">
              <header class="contextmenu-header"></header>
              <menu class="contextmenu-list"></menu>
            </form>`;
    return content;
  };

  ContextMenuView.prototype.kill = function() {
    this.containerElement.removeChild(this.element);
  };

  ContextMenuView.prototype.show = function(menu) {
    if (!this._injected) {
      this.render();
      this._injected = true;
    }

    this.buildMenu(menu);
    this.element.classList.add('visible');
    this._requestFocus();
  };

  ContextMenuView.prototype.hide = function(evt) {
    if (!this.element) {
      return;
    }

    if (evt) {
      evt.preventDefault();
    }

    this.element.classList.remove('visible');
    this._requestFocus();
  };

  ContextMenuView.prototype.buildMenu = function(items) {
    this.elements.list.innerHTML = '';
    items.forEach(function traveseItems(item) {
      var action = document.createElement('button');
      action.dataset.id = item.id;
      action.dataset.value = item.value;
      action.textContent = item.label;

      if (item.icon) {
        action.classList.add(item.iconClass || 'icon');
        action.style.backgroundImage = 'url(' + item.icon + ')';
      }

      action.addEventListener('click', function(evt) {
        this.hide(evt);
        item.callback();
      }.bind(this));

      this.elements.list.appendChild(action);
    }, this);

    this.elements.list.appendChild(this.elements.cancel);
  };

  ContextMenuView.prototype.focus = function() {
    document.activeElement.blur();
    this.elements.cancel.focus();
  };

  ContextMenuView.prototype._requestFocus = function() {
    var transited = function() {
      this.element.removeEventListener('transitionend', transited);
      if (this.transitionTimeout) {
        clearTimeout(this.transitionTimeout);
        this.transitionTimeout = null;
      }
      // The focus switch should be after this module is already shown and
      // transited.
      Service.request('focus');
    }.bind(this);

    this.element.addEventListener('transitionend', transited);
    this.transitionTimeout = setTimeout(transited, this.TRANSITION_TIMEOUT);
  };

  exports.ContextMenuView = ContextMenuView;

})(window);