DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (84bc52da6c3b)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
<!DOCTYPE html>
<html>
<head>
<title>Shadow DOM: Extensions to Event Interface</title>
<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
<meta name="assert" content="Event interface must have composedPath() as a method">
<link rel="help" href="http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/event-path-test-helpers.js"></script>
</head>
<body>
<div id="log"></div>
<script>

test(function () {
    var event = new Event('my-event');
    assert_array_equals(event.composedPath(), []);
}, 'composedPath() must return an empty array when the event has not been dispatched');

test(function () {
    var event = new Event('my-event');
    document.body.dispatchEvent(event);
    assert_array_equals(event.composedPath(), []);
}, 'composedPath() must return an empty array when the event is no longer dispatched');

test(function () {
    var event = new Event('my-event');
    assert_false(event.composed);
}, 'composed on EventInit must default to false');

test(function () {
    var event = new Event('my-event', {composed: true});
    assert_true(event.composed);

    event = new Event('my-event', {composed: false});
    assert_false(event.composed);
}, 'composed on EventInit must set the composed flag');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  *: indicates start  digit: event path order
A (4) --------------------------- A-SR (3)
+ B ------------ B-SR             + A1 (2) --- A1-SR (1)
  + C            + B1 --- B1-SR   + A2-S       + A1a (*; 0)
  + D --- D-SR     + B1a    + B1b --- B1b-SR
          + D1              + B1c-S   + B1b1
                                      + B1b2
*/

function testComposedEvent(mode) {
    test(function () {
        var nodes = createFixedTestTree(mode);
        var log = dispatchEventWithEventLog(nodes, nodes.A1a, new Event('my-event', {composed: true, bubbles: true}));

        var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR', 'A'];
        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], expectedPath);
        assert_array_equals(log.pathAtTargets[1], expectedPath);
        assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : ['A1', 'A-SR', 'A'],
            'composedPath must only contain unclosed nodes of the current target.');
    }, 'The event must propagate out of ' + mode + ' mode shadow boundaries when the composed flag is set');
}

testComposedEvent('open');
testComposedEvent('closed');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  *: indicates start  digit: event path order
A ------------------------------- A-SR
+ B ------------ B-SR             + A1 --- A1-SR (1)
  + C            + B1 --- B1-SR   + A2-S   + A1a (*; 0)
  + D --- D-SR     + B1a  + B1b --- B1b-SR
          + D1            + B1c-S   + B1b1
                                    + B1b2
*/

function testNonComposedEvent(mode) {
    test(function () {
        var nodes = createFixedTestTree(mode);
        var log = dispatchEventWithEventLog(nodes, nodes.A1a, new Event('my-event', {composed: false, bubbles: true}));

        var expectedPath = ['A1a', 'A1-SR'];
        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], expectedPath);
        assert_array_equals(log.pathAtTargets[1], expectedPath);
    }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the composed flag is unset');
}

testNonComposedEvent('open');
testNonComposedEvent('closed');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
A ------------------------------- A-SR
+ B ------------ B-SR             + A1 ----------- A1-SR (1)
  + C            + B1 --- B1-SR   + A2-S [*; 0-1]  + A1a (*; 0)
  + D --- D-SR     + B1a  + B1b --- B1b-SR
          + D1            + B1c-S   + B1b1
                                    + B1b2
*/

function testNonComposedEventWithRelatedTarget(mode) {
    test(function () {
        var nodes = createFixedTestTree(mode);
        var log = dispatchEventWithEventLog(nodes, nodes.A1a, new MouseEvent('foo', {composed: false, bubbles: true, relatedTarget: nodes['A2-S']}));

        var expectedPath = ['A1a', 'A1-SR'];
        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], expectedPath);
        assert_array_equals(log.pathAtTargets[1], expectedPath);
        assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S']);
    }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the composed flag is unset on an event with relatedTarget');
}

testNonComposedEventWithRelatedTarget('open');
testNonComposedEventWithRelatedTarget('closed');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
A ------------------------------------------------ A-SR
+ B ------------ B-SR (4)                          + A1 --- A1-SR
  + C            + B1 (3) [0,3-4] --- B1-SR (2)    + A2-S   + A1a
  + D --- D-SR     + B1a (*; 0)       + B1b [1-2] --- B1b-SR
          + D1                        + B1c-S (1)     + B1b1
                                                      + B1b2 [*]
*/

function testScopedEventWithUnscopedRelatedTargetThroughSlot(mode) {
    test(function () {
        var nodes = createFixedTestTree(mode);
        var log = dispatchEventWithEventLog(nodes, nodes.B1a, new MouseEvent('foo', {scoped: true, relatedTargetScoped: false, bubbles: true, relatedTarget: nodes['B1b2']}));

        var expectedPath = ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR'];
        var pathExposedToB1a = ['B1a', 'B1', 'B-SR'];
        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], mode == 'open' ? expectedPath : pathExposedToB1a);
        assert_array_equals(log.pathAtTargets[1], expectedPath);
        assert_array_equals(log.pathAtTargets[2], expectedPath);
        assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToB1a);
        assert_array_equals(log.pathAtTargets[4], mode == 'open' ? expectedPath : pathExposedToB1a);
        assert_array_equals(log.relatedTargets, ['B1', 'B1b', 'B1b', 'B1', 'B1']);
    }, 'The event must not propagate out of ' + mode + ' mode shadow tree of the target but must propagate out of inner shadow trees when the scoped flag is set');
}

testScopedEventWithUnscopedRelatedTargetThroughSlot('open');
testScopedEventWithUnscopedRelatedTargetThroughSlot('closed');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
A ------------------------------- A-SR (3)
+ B ------------ B-SR             + A1 (2) ------- A1-SR (1)
  + C            + B1 --- B1-SR   + A2-S [*; 0-3]  + A1a (*; 0)
  + D --- D-SR     + B1a  + B1b --- B1b-SR
          + D1            + B1c-S   + B1b1
                                    + B1b2
*/

function testComposedEventWithRelatedTarget(mode) {
    test(function () {
        var nodes = createFixedTestTree(mode);
        log = dispatchEventWithEventLog(nodes, nodes.A1a, new MouseEvent('foo', {composed: true, bubbles: true, relatedTarget: nodes['A2-S']}));

        var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR'];
        var pathExposedToA1 = ['A1', 'A-SR'];
        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], expectedPath);
        assert_array_equals(log.pathAtTargets[1], expectedPath);
        assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : pathExposedToA1);
        assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToA1);
        assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S', 'A2-S', 'A2-S']);
    }, 'The event must propagate out of ' + mode + ' mode shadow tree in which the relative target and the relative related target are the same');
}

testComposedEventWithRelatedTarget('open');
testComposedEventWithRelatedTarget('closed');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
A (8) [0-5,8] ---------------------------------------- A-SR (7)
+ B (5)  ------- B-SR (4)                              + A1 [6,7] --- A1-SR
  + C            + B1 (3) ------- B1-SR (2)            + A2-S (6)     + A1a [*]
  + D --- D-SR     + B1a (*; 0)   + B1b ------- B1b-SR
          + D1                    + B1c-S (1)   + B1b1
                                                + B1b2
*/

function testComposedEventThroughSlot(mode) {
    test(function () {
        var nodes = createFixedTestTree(mode);
        log = dispatchEventWithEventLog(nodes, nodes.B1a, new MouseEvent('foo', {composed: true, bubbles: true, relatedTarget: nodes.A1a}));

        var expectedPath =          ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'];
        var expectedRelatedTarget = ['A',   'A',     'A',     'A',   'A',   'A', 'A1',   'A1',   'A'];
        var pathExposedToB1a =      ['B1a',                   'B1', 'B-SR', 'B',                 'A'];
        var pathExposedToB1cS =     ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B',                 'A'];
        var pathExposedToB =        [                                       'B',                 'A'];
        var pathExposedToA1 =       [                                       'B', 'A2-S', 'A-SR', 'A'];

        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], mode == 'open' ? expectedPath : pathExposedToB1a);
        assert_array_equals(log.pathAtTargets[1], mode == 'open' ? expectedPath : pathExposedToB1cS);
        assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : pathExposedToB1cS);
        assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToB1a);
        assert_array_equals(log.pathAtTargets[4], mode == 'open' ? expectedPath : pathExposedToB1a);
        assert_array_equals(log.pathAtTargets[5], mode == 'open' ? expectedPath : pathExposedToB);
        assert_array_equals(log.pathAtTargets[6], mode == 'open' ? expectedPath : pathExposedToA1);
        assert_array_equals(log.pathAtTargets[7], mode == 'open' ? expectedPath : pathExposedToA1);
        assert_array_equals(log.pathAtTargets[8], mode == 'open' ? expectedPath : pathExposedToB);
        assert_array_equals(log.relatedTargets, expectedRelatedTarget);
    }, 'composedPath() must contain and only contain the unclosed nodes of target in ' + mode + ' mode shadow trees');
}

testComposedEventThroughSlot('open');
testComposedEventThroughSlot('closed');

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