/**
 *
 * Copyright 2016 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* eslint-env browser */

/**
 * Usage:
 * const detabinator = new Detabinator(element);
 * detabinator.inert = true;  // Sets all focusable children of
 * element to tabindex=-1
 * detabinator.inert = false; // Restores all focusable children of element
 * Limitations: Doesn't support Shadow DOM v0 :P
 */
class Detabinator {
  /**
   * The element to enable / disable tabs.
   * @param {DOMElement} element The element to detabinate.
   */
  constructor(element) {
    if (!element) {
      throw new Error('Missing required argument. new Detabinator needs an ' +
        'element reference');
    }
    this._inert = false;
    this._focusableElementsString = 'a[href], area[href], ' +
      'input:not([disabled]), select:not([disabled]), ' +
      'textarea:not([disabled]), button:not([disabled]), ' +
      'iframe, object, embed, [tabindex], [contenteditable]';
    this._focusableElements = Array.from(
      element.querySelectorAll(this._focusableElementsString)
    );
  }

  /**
   * Get the current inert state.
   * @return {boolean} Whether the element is inert or not.
   */
  get inert() {
    return this._inert;
  }

  /**
   * Set the inert state.
   * @param  {Boolean} isInert The new inert state.
   */
  set inert(isInert) {
    if (this._inert === isInert) {
      return;
    }

    this._inert = isInert;

    this._focusableElements.forEach((child) => {
      const _child = child;
      if (isInert && _child.hasAttribute('tabindex')) {
        _child.__savedTabindex = child.tabIndex;
        _child.setAttribute('tabindex', -1);
      } else if (!isInert) {
        // If the child has a saved tabindex, restore it
        // Because the value could be 0, explicitly check that it's not false
        if (_child.__savedTabindex === 0 || _child.__savedTabindex) {
          _child.setAttribute('tabindex', _child.__savedTabindex);
        } else {
          // Remove tabindex from ANY REMAINING children
          _child.removeAttribute('tabindex');
        }
      }
    });
  }
}

window.Detabinator = Detabinator;
