<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Event.cancelBubble</title>
  <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
  <link rel="help" href="https://dom.spec.whatwg.org/#dom-event-cancelbubble">
  <meta name="flags" content="dom">
  <script src="/resources/testharness.js"></script>
  <script src="/resources/testharnessreport.js"></script>
</head>
<body>
  <div id="outer">
    <div id="middle">
      <div id="inner"></div>
    </div>
  </div>
  <script>
test(function () {
  // See https://dom.spec.whatwg.org/#stop-propagation-flag
  var e = document.createEvent('Event');
  assert_false(e.cancelBubble, "cancelBubble must be false after event creation.");
}, "cancelBubble must be false when an event is initially created.");

test(function () {
  // See https://dom.spec.whatwg.org/#concept-event-initialize

  // Event which bubbles.
  var one = document.createEvent('Event');
  one.cancelBubble = true;
  one.initEvent('foo', true/*bubbles*/, false/*cancelable*/);
  assert_false(one.cancelBubble, "initEvent() must set cancelBubble to false. [bubbles=true]");
  // Re-initialization.
  one.cancelBubble = true;
  one.initEvent('foo', true/*bubbles*/, false/*cancelable*/);
  assert_false(one.cancelBubble, "2nd initEvent() call must set cancelBubble to false. [bubbles=true]");

  // Event which doesn't bubble.
  var two = document.createEvent('Event');
  two.cancelBubble = true;
  two.initEvent('foo', false/*bubbles*/, false/*cancelable*/);
  assert_false(two.cancelBubble, "initEvent() must set cancelBubble to false. [bubbles=false]");
  // Re-initialization.
  two.cancelBubble = true;
  two.initEvent('foo', false/*bubbles*/, false/*cancelable*/);
  assert_false(two.cancelBubble, "2nd initEvent() call must set cancelBubble to false. [bubbles=false]");
}, "Initializing an event must set cancelBubble to false.");

test(function () {
  // See https://dom.spec.whatwg.org/#dom-event-stoppropagation
  var e = document.createEvent('Event');
  e.stopPropagation();
  assert_true(e.cancelBubble, "stopPropagation() must set cancelBubble to true.");
}, "stopPropagation() must set cancelBubble to true.");

test(function () {
  // See https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation
  var e = document.createEvent('Event');
  e.stopImmediatePropagation();
  assert_true(e.cancelBubble, "stopImmediatePropagation() must set cancelBubble to true.");
}, "stopImmediatePropagation() must set cancelBubble to true.");

test(function () {
  var one = document.createEvent('Event');
  one.stopPropagation();
  one.cancelBubble = false;
  assert_true(one.cancelBubble, "cancelBubble must still be true after attempting to set it to false.");
}, "Event.cancelBubble=false must have no effect.");

test(function (t) {
  var outer = document.getElementById('outer');
  var middle = document.getElementById('middle');
  var inner = document.getElementById('inner');

  outer.addEventListener('barbaz', t.step_func(function () {
    assert_unreached("Setting Event.cancelBubble=false after setting Event.cancelBubble=true should have no effect.");
  }), false/*useCapture*/);

  middle.addEventListener('barbaz', function (e) {
    e.cancelBubble = true;// Stop propagation.
    e.cancelBubble = false;// Should be a no-op.
  }, false/*useCapture*/);

  var barbazEvent = document.createEvent('Event');
  barbazEvent.initEvent('barbaz', true/*bubbles*/, false/*cancelable*/);
  inner.dispatchEvent(barbazEvent);
}, "Event.cancelBubble=false must have no effect during event propagation.");

test(function () {
  // See https://dom.spec.whatwg.org/#concept-event-dispatch
  // "14. Unset event’s [...] stop propagation flag,"
  var e = document.createEvent('Event');
  e.initEvent('foobar', true/*bubbles*/, true/*cancelable*/);
  document.body.addEventListener('foobar', function listener(e) {
    e.stopPropagation();
  });
  document.body.dispatchEvent(e);
  assert_false(e.cancelBubble, "cancelBubble must be false after an event has been dispatched.");
}, "cancelBubble must be false after an event has been dispatched.");

test(function (t) {
  var outer = document.getElementById('outer');
  var middle = document.getElementById('middle');
  var inner = document.getElementById('inner');

  var propagationStopper = function (e) {
    e.cancelBubble = true;
  };

  // Bubble phase
  middle.addEventListener('bar', propagationStopper, false/*useCapture*/);
  outer.addEventListener('bar', t.step_func(function listenerOne() {
    assert_unreached("Setting cancelBubble=true should stop the event from bubbling further.");
  }), false/*useCapture*/);

  var barEvent = document.createEvent('Event');
  barEvent.initEvent('bar', true/*bubbles*/, false/*cancelable*/);
  inner.dispatchEvent(barEvent);

  // Capture phase
  outer.addEventListener('qux', propagationStopper, true/*useCapture*/);
  middle.addEventListener('qux', t.step_func(function listenerTwo() {
    assert_unreached("Setting cancelBubble=true should stop the event from propagating further, including during the Capture Phase.");
  }), true/*useCapture*/);

  var quxEvent = document.createEvent('Event');
  quxEvent.initEvent('qux', false/*bubbles*/, false/*cancelable*/);
  inner.dispatchEvent(quxEvent);
}, "Event.cancelBubble=true must set the stop propagation flag.");
  </script>
</body>
</html>
