/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

// Tests keyboard navigation of devtools tabbar.

const TEST_URL =
  "data:text/html;charset=utf8,test page for toolbar keyboard navigation";

function containsFocus(aDoc, aElm) {
  let elm = aDoc.activeElement;
  while (elm) {
    if (elm === aElm) {
      return true;
    }
    elm = elm.parentNode;
  }
  return false;
}

add_task(async function () {
  info("Create a test tab and open the toolbox");
  const toolbox = await openNewTabAndToolbox(TEST_URL, "webconsole");
  const doc = toolbox.doc;

  const toolbar = doc.querySelector(".devtools-tabbar");
  const toolbarControls = [
    ...toolbar.querySelectorAll(".devtools-tab, button"),
  ].filter(
    elm =>
      !elm.hidden &&
      doc.defaultView.getComputedStyle(elm).getPropertyValue("display") !==
        "none"
  );

  // Put the keyboard focus onto the first toolbar control.
  toolbarControls[0].focus();
  ok(containsFocus(doc, toolbar), "Focus is within the toolbar");

  // Move the focus away from toolbar to a next focusable element.
  EventUtils.synthesizeKey("KEY_Tab");
  ok(!containsFocus(doc, toolbar), "Focus is outside of the toolbar");

  // Move the focus back to the toolbar.
  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
  ok(containsFocus(doc, toolbar), "Focus is within the toolbar again");

  // Move through the toolbar forward using the right arrow key.
  for (let i = 0; i < toolbarControls.length; ++i) {
    is(doc.activeElement.id, toolbarControls[i].id, "New control is focused");
    if (i < toolbarControls.length - 1) {
      EventUtils.synthesizeKey("KEY_ArrowRight");
    }
  }

  // Move the focus away from toolbar to a next focusable element.
  EventUtils.synthesizeKey("KEY_Tab");
  ok(!containsFocus(doc, toolbar), "Focus is outside of the toolbar");

  // Move the focus back to the toolbar.
  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
  ok(containsFocus(doc, toolbar), "Focus is within the toolbar again");

  // Move through the toolbar backward using the left arrow key.
  for (let i = toolbarControls.length - 1; i >= 0; --i) {
    is(doc.activeElement.id, toolbarControls[i].id, "New control is focused");
    if (i > 0) {
      EventUtils.synthesizeKey("KEY_ArrowLeft");
    }
  }

  // Move focus to the 3rd (non-first) toolbar control.
  const expectedFocusedControl = toolbarControls[2];
  EventUtils.synthesizeKey("KEY_ArrowRight");
  EventUtils.synthesizeKey("KEY_ArrowRight");
  is(doc.activeElement.id, expectedFocusedControl.id, "New control is focused");

  // Move the focus away from toolbar to a next focusable element.
  EventUtils.synthesizeKey("KEY_Tab");
  ok(!containsFocus(doc, toolbar), "Focus is outside of the toolbar");

  // Move the focus back to the toolbar, ensure we land on the last active
  // descendant control.
  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
  is(doc.activeElement.id, expectedFocusedControl.id, "New control is focused");
});

// Test that moving the focus of tab button and selecting it.
add_task(async function () {
  info("Create a test tab and open the toolbox");
  const toolbox = await openNewTabAndToolbox(TEST_URL, "inspector");
  const doc = toolbox.doc;

  const toolbar = doc.querySelector(".toolbox-tabs");
  const tabButtons = toolbar.querySelectorAll(".devtools-tab, button");
  const win = tabButtons[0].ownerDocument.defaultView;

  // Put the keyboard focus onto the first tab button.
  tabButtons[0].focus();
  ok(containsFocus(doc, toolbar), "Focus is within the toolbox");
  is(doc.activeElement.id, tabButtons[0].id, "First tab button is focused.");

  // Move the focused tab and select it by using enter key.
  let onKeyEvent = once(win, "keydown");
  EventUtils.synthesizeKey("KEY_ArrowRight");
  await onKeyEvent;

  let onceSelected = toolbox.once("webconsole-selected");
  EventUtils.synthesizeKey("Enter");
  await onceSelected;
  is(
    doc.activeElement.id,
    "toolbox-panel-iframe-" + toolbox.currentToolId,
    "Selected tool frame is now focused."
  );

  // Webconsole steal the focus from button after sending "webconsole-selected"
  // event.
  tabButtons[1].focus();

  // Return the focused tab with space key.
  onKeyEvent = once(win, "keydown");
  EventUtils.synthesizeKey("KEY_ArrowLeft");
  await onKeyEvent;

  onceSelected = toolbox.once("inspector-selected");
  EventUtils.synthesizeKey(" ");
  await onceSelected;

  is(
    doc.activeElement.id,
    "toolbox-panel-iframe-" + toolbox.currentToolId,
    "Selected tool frame is now focused."
  );
});
