<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" href="mailto:masonf@chromium.org">
<link rel=help href="https://open-ui.org/components/popover.research.explainer">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<div>
  <div popover>Popover</div>
  <div popover=hint>Hint</div>
  <div popover=manual>Async</div>
  <div popover=manual>Async</div>
  <script>
  {
    const auto = document.currentScript.parentElement.querySelector('[popover=""]');
    const hint = document.currentScript.parentElement.querySelector('[popover=hint]');
    const manual = document.currentScript.parentElement.querySelectorAll('[popover=manual]')[0];
    const manual2 = document.currentScript.parentElement.querySelectorAll('[popover=manual]')[1];
    function assert_state_1(autoOpen,hintOpen,manualOpen,manual2Open) {
      assert_equals(auto.matches(':popover-open'),autoOpen,'auto open state is incorrect');
      assert_equals(hint.matches(':popover-open'),hintOpen,'hint open state is incorrect');
      assert_equals(manual.matches(':popover-open'),manualOpen,'manual open state is incorrect');
      assert_equals(manual2.matches(':popover-open'),manual2Open,'manual2 open state is incorrect');
    }
    test(() => {
      assert_state_1(false,false,false,false);
      auto.showPopover();
      assert_state_1(true,false,false,false);
      hint.showPopover();
      assert_state_1(true,true,false,false);
      manual.showPopover();
      assert_state_1(true,true,true,false);
      manual2.showPopover();
      assert_state_1(true,true,true,true);
      hint.hidePopover();
      assert_state_1(true,false,true,true);
      auto.hidePopover();
      assert_state_1(false,false,true,true);
      auto.showPopover();
      hint.showPopover();
      assert_state_1(true,true,true,true);
      auto.hidePopover(); // Non-nested tooltips can stay open when unrelated popovers are hidden.
      assert_state_1(false,true,true,true);
      hint.hidePopover();
      manual.hidePopover();
      assert_state_1(false,false,false,true);
      manual2.hidePopover();
      assert_state_1(false,false,false,false);
    },'manuals do not close popovers');

    test(() => {
      assert_state_1(false,false,false,false);
      hint.showPopover();
      manual.showPopover();
      manual2.showPopover();
      assert_state_1(false,true,true,true);
      auto.showPopover();
      assert_state_1(true,false,true,true);
      auto.hidePopover();
      assert_state_1(false,false,true,true);
      manual.hidePopover();
      manual2.hidePopover();
      assert_state_1(false,false,false,false);
    },'autos close hints but not manuals');
  }
  </script>
</div>

<div>
  <div popover>popover 1
    <div popover>popover 2
      <p id=anchorid>Anchor</p>
      <div popover>popover 3</div>
    </div>
  </div>
  <div popover=hint anchor=anchorid>Hint anchored to popover</div>
  <script>
  {
    const popover1 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[0];
    const popover2 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[1];
    const popover3 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[2];
    const hint = document.currentScript.parentElement.querySelector('[popover=hint]');
    function assert_state_2(popover1Open,popover2Open,popover3Open,hintOpen) {
      assert_equals(popover1.matches(':popover-open'),popover1Open,'popover1 open state is incorrect');
      assert_equals(popover2.matches(':popover-open'),popover2Open,'popover2 open state is incorrect');
      assert_equals(popover3.matches(':popover-open'),popover3Open,'popover3 open state is incorrect');
      assert_equals(hint.matches(':popover-open'),hintOpen,'hint open state is incorrect');
    }
    test(() => {
      assert_state_2(false,false,false,false);
      popover1.showPopover();
      popover2.showPopover();
      popover3.showPopover();
      assert_state_2(true,true,true,false);
      hint.showPopover(); // Because hint is nested in popover2, popover3 should be hidden
      assert_state_2(true,true,false,true);
      popover1.hidePopover(); // Should close the hint, which is anchored to popover2
      assert_state_2(false,false,false,false);
    },'hint is not closed by pre-existing auto');
  }
  </script>
</div>

<div>
  <div popover=hint>Hint
    <div popover=hint>Nested hint</div>
  </div>
  <script>
  test(() => {
    const hint1 = document.currentScript.parentElement.querySelectorAll('[popover=hint]')[0];
    const hint2 = document.currentScript.parentElement.querySelectorAll('[popover=hint]')[1];
    hint1.showPopover();
    assert_true(hint1.matches(':popover-open'));
    assert_false(hint2.matches(':popover-open'));
    hint2.showPopover();
    assert_false(hint1.matches(':popover-open'));
    assert_true(hint2.matches(':popover-open'));
    hint2.hidePopover();
  },'If a popover=hint is shown, it should hide any other open popover=hint popovers, including ancestral popovers. (You can\'t nest popover=hint)');
  </script>
</div>

<div>
  <div popover="hint">Hint
    <div popover>Nested auto (note - never visible, since inside display:none subtree)</div>
  </div>
  <script>
  test(() => {
    const hint = document.currentScript.parentElement.querySelector('[popover=hint]');
    const auto = document.currentScript.parentElement.querySelector('[popover=""]');
    hint.showPopover();
    assert_true(hint.matches(':popover-open'));
    assert_false(auto.matches(':popover-open'));
    auto.showPopover();
    assert_false(hint.matches(':popover-open'));
    assert_true(auto.matches(':popover-open'));
    auto.hidePopover();
  },'If a popover=auto is shown, it should hide any open popover=hint, including if the popover=hint is an ancestral popover of the popover=auto. (You can\'t nest a popover=auto inside a popover=hint)');
  </script>
</div>

<div>
  <div popover>Auto
    <div popover>Nested Auto</div>
    <div popover=hint>Nested hint</div>
  </div>
  <script>
  test(() => {
    const auto = document.currentScript.parentElement.querySelectorAll('[popover=""]')[0];
    const auto2 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[1];
    const hint = document.currentScript.parentElement.querySelector('[popover=hint]');
    auto.showPopover();
    auto2.showPopover();
    assert_true(auto.matches(':popover-open'));
    assert_true(auto2.matches(':popover-open'));
    hint.showPopover(); // This should hide auto2, since it is nested in auto1.
    assert_true(auto.matches(':popover-open'));
    assert_false(auto2.matches(':popover-open'));
    assert_true(hint.matches(':popover-open'));
    auto.hidePopover(); // Should hide both auto and hint.
    assert_false(auto.matches(':popover-open'));
    assert_false(hint.matches(':popover-open'));
  },'If you: a) show a popover=auto (call it D), then b) show a descendent popover=hint of D (call it T), then c) hide D, then T should be hidden. (A popover=hint can be nested inside a popover=auto)');
  </script>
</div>

<div>
  <div popover>Auto</div>
  <div popover=hint>Non-Nested hint</div>
  <script>
  test(() => {
    const auto = document.currentScript.parentElement.querySelector('[popover=""]');
    const hint = document.currentScript.parentElement.querySelector('[popover=hint]');
    auto.showPopover();
    hint.showPopover();
    assert_true(auto.matches(':popover-open'));
    assert_true(hint.matches(':popover-open'));
    auto.hidePopover();
    assert_false(auto.matches(':popover-open'));
    assert_true(hint.matches(':popover-open'));
    hint.hidePopover();
  },'If you: a) show a popover=auto (call it D), then b) show a non-descendent popover=hint of D (call it T), then c) hide D, then T should be left showing. (Non-nested popover=hint can stay open when unrelated popover=autos are hidden)');
  </script>
</div>
