button.js

/**
 * @file button.js
 */
import ClickableComponent from './clickable-component.js';
import Component from './component';
import log from './utils/log.js';
import keycode from 'keycode';
import {createEl} from './utils/dom.js';

/**
 * Base class for all buttons.
 *
 * @extends ClickableComponent
 */
class Button extends ClickableComponent {

  /**
   * Create the `Button`s DOM element.
   *
   * @param {string} [tag="button"]
   *        The element's node type. This argument is IGNORED: no matter what
   *        is passed, it will always create a `button` element.
   *
   * @param {Object} [props={}]
   *        An object of properties that should be set on the element.
   *
   * @param {Object} [attributes={}]
   *        An object of attributes that should be set on the element.
   *
   * @return {Element}
   *         The element that gets created.
   */
  createEl(tag, props = {}, attributes = {}) {
    tag = 'button';

    props = Object.assign({
      className: this.buildCSSClass()
    }, props);

    // Add attributes for button element
    attributes = Object.assign({

      // Necessary since the default button type is "submit"
      type: 'button'
    }, attributes);

    const el = createEl(tag, props, attributes);

    if (!this.player_.options_.experimentalSvgIcons) {
      el.appendChild(createEl('span', {
        className: 'vjs-icon-placeholder'
      }, {
        'aria-hidden': true
      }));
    }

    this.createControlTextEl(el);

    return el;
  }

  /**
   * Add a child `Component` inside of this `Button`.
   *
   * @param {string|Component} child
   *        The name or instance of a child to add.
   *
   * @param {Object} [options={}]
   *        The key/value store of options that will get passed to children of
   *        the child.
   *
   * @return {Component}
   *         The `Component` that gets added as a child. When using a string the
   *         `Component` will get created by this process.
   *
   * @deprecated since version 5
   */
  addChild(child, options = {}) {
    const className = this.constructor.name;

    log.warn(`Adding an actionable (user controllable) child to a Button (${className}) is not supported; use a ClickableComponent instead.`);

    // Avoid the error message generated by ClickableComponent's addChild method
    return Component.prototype.addChild.call(this, child, options);
  }

  /**
   * Enable the `Button` element so that it can be activated or clicked. Use this with
   * {@link Button#disable}.
   */
  enable() {
    super.enable();
    this.el_.removeAttribute('disabled');
  }

  /**
   * Disable the `Button` element so that it cannot be activated or clicked. Use this with
   * {@link Button#enable}.
   */
  disable() {
    super.disable();
    this.el_.setAttribute('disabled', 'disabled');
  }

  /**
   * This gets called when a `Button` has focus and `keydown` is triggered via a key
   * press.
   *
   * @param {KeyboardEvent} event
   *        The event that caused this function to get called.
   *
   * @listens keydown
   */
  handleKeyDown(event) {

    // Ignore Space or Enter key operation, which is handled by the browser for
    // a button - though not for its super class, ClickableComponent. Also,
    // prevent the event from propagating through the DOM and triggering Player
    // hotkeys. We do not preventDefault here because we _want_ the browser to
    // handle it.
    if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
      event.stopPropagation();
      return;
    }

    // Pass keypress handling up for unsupported keys
    super.handleKeyDown(event);
  }
}

Component.registerComponent('Button', Button);
export default Button;