<!DOCTYPE html>
<!-- Modified from Chris Rebert's manual version -->
<!-- This documents the behavior according to blink's implementation -->
<html>
  <head>
    <meta charset="utf-8">
    <title>Focus-related events should fire in the correct order</title>
    <link rel="help" href="https://w3c.github.io/uievents/#events-focusevent-event-order">
    <script src="/resources/testharness.js"></script>
    <script src="/resources/testharnessreport.js"></script>
  </head>
  <body id="body">
    <input type="text" id="a" value="First">
    <input type="text" id="b" value="Second">
    <br>
    <input type="text" id="c" value="Third">
    <iframe id="iframe">
    </iframe>
    <br>
    <script>

    var test_id = 0;
    var tests = ['normal', 'iframe']

    function record(evt) {
      if (done && (evt.type == 'focusin' || evt.type == 'focus') && (evt.target == c)) {
          startNext();
      }
      if (!done) {
          var activeElement = document.activeElement ?
            (document.activeElement.tagName === 'IFRAME' ?
            document.activeElement.contentDocument.activeElement.id :
            document.activeElement.id) : null;
          events[tests[test_id]].push(evt.type);
          targets[tests[test_id]].push(evt.target.id);
          focusedElements[tests[test_id]].push(activeElement);
          relatedTargets[tests[test_id]].push(evt.relatedTarget ? evt.relatedTarget.id : null);
      }
    }
    function startNext() {
        done = false;
        test_id++;
    }
    function finish() {
        done = true;
    }
    var relevantEvents = [
      'focus',
      'blur',
      'focusin',
      'focusout'
    ];

    var iframe = document.getElementById('iframe');
    var a = document.getElementById('a');
    var b = document.getElementById('b');
    var c = document.getElementById('c');
    var d = document.createElement('input');

    d.setAttribute('id', 'd');
    d.setAttribute('type', 'text');
    d.setAttribute('value', 'Fourth');

    var events = {'normal': [], 'iframe': []};
    var targets = {'normal': [], 'iframe': []};
    var focusedElements = {'normal': [], 'iframe': []};
    var relatedTargets = {'normal': [], 'iframe': []};
    var done = false;

    var async_test_normal = async_test('Focus-related events should fire in the correct order (same DocumentOwner)');
    var async_test_iframe_static = async_test('Focus-related events should fire in the correct order (different DocumentOwner)');

    window.onload = function(evt) {

        iframe.contentDocument.body.appendChild(d);

        var inputs = [a, b, c, d];

        for (var i = 0; i < inputs.length; i++) {
          for (var k = 0; k < relevantEvents.length; k++) {
            inputs[i].addEventListener(relevantEvents[k], record, false);
          }
        }

        a.addEventListener('focusin', function() { b.focus(); }, false);
        b.addEventListener('focusin', function() {
            async_test_normal.step( function() {
                assert_array_equals(
                  events['normal'],
                  ['focus', 'focusin', 'blur', 'focusout', 'focus', 'focusin'],
                  'Focus-related events should fire in this order: focusin, focus, focusout, focusin, blur, focus'
                );

                assert_array_equals(
                  targets['normal'],
                  [      'a',     'a',        'a',       'a',    'b',     'b'],
                  'Focus-related events should fire at the correct targets'
                );

                assert_array_equals(
                  relatedTargets['normal'],
                  [    null,    null,         'b',       'b',    'a',     'a'],
                  'Focus-related events should reference correct relatedTargets'
                );

                assert_array_equals(
                  focusedElements['normal'],
                  [   'a',     'a',        'body',    'body',    'b',     'b'],
                  'Focus-related events should fire at the correct time relative to actual focus changes'
                );

                async_test_normal.done();
                });

            b.addEventListener('focusout', function() { finish(); c.focus(); });
            b.blur();

            }, false);

        c.addEventListener('focusin', function() {d.focus();});
        d.addEventListener('focusin', function() {
            async_test_iframe_static.step(function() {
                assert_array_equals(
                  events['iframe'],
                  ['focus', 'focusin', 'blur', 'focusout', 'focus', 'focusin'],
                  'Focus-related events should fire in this order: focusin, focus, focusout, focusin, blur, focus'
                );

                assert_array_equals(
                  targets['iframe'],
                  [      'c',     'c',        'c',       'c',    'd',     'd'],
                  'Focus-related events should fire at the correct targets'
                );

                assert_array_equals(
                  relatedTargets['iframe'],
                  [    null,    null,        null,      null,   null,    null],
                  'Focus-related events should reference correct relatedTargets'
                );

                assert_array_equals(
                  focusedElements['iframe'],
                  [   'c',     'c',        'body',      'body', 'd',     'd'],
                  'Focus-related events should fire at the correct time relative to actual focus changes'
                );

                async_test_iframe_static.done();
                });

            d.addEventListener('focusout', function() { finish();});

          }, false);

        a.focus();
    }

    </script>
  </body>
</html>
