<!DOCTYPE html>
<meta charset=utf-8>
<title>dialog element: showModal()</title>
<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
<link rel=help href="https://html.spec.whatwg.org/multipage/#the-dialog-element">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<button id="b0">OK</button>
<dialog id="d1">
  <p>foobar</p>
  <button id="b1">OK</button>
</dialog>
<dialog id="d2" open>
  <p>foobar</p>
  <button>OK</button>
</dialog>
<dialog id="d3">
  <p>foobar</p>
  <button id="b3">OK</button>
</dialog>
<dialog id="d4">
  <p>foobar</p>
  <button id="b4">OK</button>
</dialog>
<dialog id="d5">
  <p>foobar</p>
  <button id="b5">OK</button>
</dialog>
<dialog id="d6"></dialog>
<dialog id="d7">
  <input id="i71" value="foobar">
  <input id="i72" value="foobar">
  <button id="b7">OK</button>
</dialog>
<dialog id="d8">
  <input id="i81" value="foobar">
  <input id="i82" value="foobar" autofocus>
  <button id="b8">OK</button>
</dialog>
<dialog id="d9"></dialog>
<dialog id="d10"></dialog>
<dialog id="d11"></dialog>
<script>
  var d1 = document.getElementById('d1'),
      d2 = document.getElementById('d2'),
      d3 = document.getElementById('d3'),
      d4 = document.getElementById('d4'),
      d5 = document.getElementById('d5'),
      d6 = document.getElementById('d6'),
      d7 = document.getElementById('d7'),
      d8 = document.getElementById('d8'),
      d9 = document.getElementById('d9'),
      d10 = document.getElementById('d10'),
      d11 = document.getElementById('d11'),
      b0 = document.getElementById('b0'),
      b1 = document.getElementById('b1'),
      b3 = document.getElementById('b3'),
      b4 = document.getElementById('b4'),
      b5 = document.getElementById('b5');

  test(function(){
    assert_false(d1.open);
    assert_false(d1.hasAttribute("open"));
    assert_equals(getComputedStyle(d1).display, "none");
    d1.showModal();
    this.add_cleanup(function() { d1.close(); });
    assert_true(d1.open);
    assert_equals(d1.getAttribute("open"), "");
    assert_equals(getComputedStyle(d1).display, "block");
    assert_equals(document.activeElement, b1);
  });

  test(function(){
    this.add_cleanup(function() { d2.close(); });
    assert_throws_dom("INVALID_STATE_ERR", function() {
      d2.showModal();
    });
  }, "showModal() on a <dialog> that already has an open attribute throws an InvalidStateError exception");

  test(function(){
    d9.showModal();
    this.add_cleanup(function() { d9.close(); });
    assert_true(d9.open);
    d9.removeAttribute("open");
    assert_false(d9.open);
    d9.showModal();
    assert_true(d9.open);
  }, "showModal() on a <dialog> after initial showModal() and removing the open attribute");

  test(function(){
    var d = document.createElement("dialog");
    this.add_cleanup(function() { d.close(); });
    assert_throws_dom("INVALID_STATE_ERR", function() {
      d.showModal();
    });
  }, "showModal() on a <dialog> not in a Document throws an InvalidStateError exception");

  test(function(){
    assert_false(d3.open);
    assert_false(d4.open);
    assert_false(d5.open);
    d3.showModal();
    this.add_cleanup(function() { d3.close(); });
    d4.showModal();
    this.add_cleanup(function() { d4.close(); });
    d5.showModal();
    this.add_cleanup(function() { d5.close(); });
    assert_true(d3.open);
    assert_true(d4.open);
    assert_true(d5.open);
  }, "when opening multiple dialogs, only the newest one is non-inert");

  test(function(){
    assert_false(d6.open);
    d6.showModal();
    this.add_cleanup(function() { d6.close(); });
    assert_true(d6.open);
    assert_equals(document.activeElement, d6);
  }, "opening dialog without focusable children");

  test(function(){
    assert_false(d7.open);
    d7.showModal();
    this.add_cleanup(function() { d7.close(); });
    assert_true(d7.open);
    assert_equals(document.activeElement, document.getElementById("i71"));
  }, "opening dialog with multiple focusable children");

  test(function(){
    assert_false(d8.open);
    d8.showModal();
    this.add_cleanup(function() { d8.close(); });
    assert_true(d8.open);
    assert_equals(document.activeElement, document.getElementById("i82"));
  }, "opening dialog with multiple focusable children, one having the autofocus attribute");

  test(function(){
    assert_false(d10.open);
    assert_false(d11.open);
    d10.showModal();
    this.add_cleanup(function() { d10.close(); });
    d11.showModal();
    this.add_cleanup(function() { d11.close(); });
    var rect10 = d10.getBoundingClientRect();
    var rect11 = d11.getBoundingClientRect();

    // The two <dialog>s are both in top layer, with the same position/size.
    assert_equals(rect10.left, rect11.left);
    assert_equals(rect10.top, rect11.top);
    assert_equals(rect10.width, rect11.width);
    assert_equals(rect10.height, rect11.height);

    var pointX = rect10.left + rect10.width / 2,
        pointY = rect10.top + rect10.height / 2;
    function topElement() {
      return document.elementFromPoint(pointX, pointY);
    }

    // d11 was most recently openened, and thus on top.
    assert_equals(topElement(), d11);

    // Removing the open attribute and running through the showModal() algorithm
    // again should not promote d10 to the top.
    d10.removeAttribute("open");
    assert_equals(topElement(), d11);
    d10.showModal();
    assert_equals(topElement(), d11);

    // Closing d11 with close() should cause d10 to be the topmost element.
    d11.close();
    assert_equals(topElement(), d10);
  }, "when opening multiple dialogs, the most recently opened is rendered on top");

  test(function() {
    assert_false(d11.open);
    d11.parentNode.removeChild(d11);
    assert_throws_dom("INVALID_STATE_ERR", () => d11.showModal());

    const doc = document.implementation.createHTMLDocument();
    doc.body.appendChild(d11);
    this.add_cleanup(() => document.body.append(d11));
    assert_false(d11.open);
    d11.showModal();
    assert_true(d11.open);
    this.add_cleanup(() => d11.close());
  }, "Although the document is not attached to any pages, showModal() should execute as normal.");
</script>
