tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

imperative-slot-api.html (11892B)


      1 <!DOCTYPE html>
      2 <title>Shadow DOM: Imperative Slot API</title>
      3 <meta name="author" title="Yu Han" href="mailto:yuzhehan@chromium.org">
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script src="resources/shadow-dom.js"></script>
      7 
      8 <div id="test_basic">
      9  <div id="host1"></div>
     10  <div id="host2"></div>
     11  <div id="host3"></div>
     12 </div>
     13 <script>
     14 test(() => {
     15  let tTree = createTestTree(test_basic);
     16  const shadow1 = tTree.host1.attachShadow({ mode: 'open', slotAssignment: 'manual'});
     17  assert_not_equals(shadow1, null, 'slot assignment manual should work');
     18  assert_equals(shadow1.slotAssignment, "manual", 'slotAssignment should return "manual"');
     19  const shadow2 = tTree.host2.attachShadow({ mode: 'open', slotAssignment: 'named'});
     20  assert_not_equals(shadow2, null, 'slot assignment named should work');
     21  assert_equals(shadow2.slotAssignment, "named", 'slotAssignment should return "named"');
     22  assert_throws_js(TypeError, () => {
     23    tTree.host3.attachShadow({ mode: 'open', slotAssignment: 'exceptional' })},
     24                'others should throw exception');
     25 }, 'attachShadow can take slotAssignment parameter.');
     26 </script>
     27 
     28 <div id="test_assign">
     29  <div id="host">
     30    <template id="shadow_root" data-mode="open" data-slot-assignment="manual">
     31      <slot id="s1"></slot>
     32      <slot id="s2"></slot>
     33      <slot id="s3"></slot>
     34    </template>
     35    <div id="c1"></div>
     36    <div id="c2"></div>
     37    <div id="c3"></div>
     38    <div id="nested">
     39       <div id="ns1"></div>
     40    </div>
     41  </div>
     42  <div id="c4"></div>
     43  <div id="host4">
     44    <template id="shadow_root4" data-mode="open" data-slot-assignment="manual">
     45      <slot id="s4" name="s4"></slot>
     46    </template>
     47  </div>
     48 </div>
     49 <script>
     50 test(() => {
     51  let tTree = createTestTree(test_assign);
     52  tTree.s1.assign(c1,c2); // Should work
     53  assert_throws_js(TypeError, () => {
     54    tTree.s1.assign([c1,c2])
     55  }, 'sequence not allowed');
     56  assert_throws_js(TypeError, () => {
     57    tTree.s1.assign([])
     58  }, 'including empty sequences');
     59 }, 'slot.attach() should take variadic not sequence.');
     60 
     61 test(() => {
     62  let tTree = createTestTree(test_assign);
     63  assert_array_equals(tTree.s2.assignedElements(), []);
     64  assert_equals(tTree.c1.assignedSlot, null);
     65 
     66  tTree.s1.assign(tTree.c1);
     67  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
     68  assert_equals(tTree.c1.assignedSlot, tTree.s1);
     69 
     70  tTree.s2.assign(tTree.c2, tTree.c3);
     71  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
     72  assert_array_equals(tTree.s2.assignedNodes(), [tTree.c2, tTree.c3]);
     73 }, 'Imperative slot API can assign nodes in manual slot assignment.');
     74 
     75 test(() => {
     76  let tTree = createTestTree(test_assign);
     77 
     78  tTree.s1.assign(tTree.c2, tTree.c3, tTree.c1);
     79  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c3, tTree.c1]);
     80  assert_equals(tTree.c1.assignedSlot, tTree.s1);
     81  assert_equals(tTree.c2.assignedSlot, tTree.s1);
     82  assert_equals(tTree.c3.assignedSlot, tTree.s1);
     83 
     84  tTree.s1.assign(tTree.c1, tTree.c2);
     85  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
     86  assert_equals(tTree.c1.assignedSlot, tTree.s1);
     87  assert_equals(tTree.c2.assignedSlot, tTree.s1);
     88  assert_equals(tTree.c3.assignedSlot, null);
     89 
     90  tTree.s1.assign(tTree.c3, tTree.c2, tTree.c1);
     91  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c3, tTree.c2, tTree.c1]);
     92  assert_equals(tTree.c1.assignedSlot, tTree.s1);
     93  assert_equals(tTree.c2.assignedSlot, tTree.s1);
     94  assert_equals(tTree.c3.assignedSlot, tTree.s1);
     95 }, 'Order of slottables is preserved in manual slot assignment.');
     96 
     97 test(() => {
     98  let tTree = createTestTree(test_assign);
     99 
    100  tTree.s1.assign(tTree.c2, tTree.c3, tTree.c1);
    101  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c3, tTree.c1]);
    102 
    103  tTree.s2.assign(tTree.c2);
    104  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c3, tTree.c1]);
    105  assert_array_equals(tTree.s2.assignedNodes(), [tTree.c2]);
    106  assert_equals(tTree.c1.assignedSlot, tTree.s1);
    107  assert_equals(tTree.c2.assignedSlot, tTree.s2);
    108  assert_equals(tTree.c3.assignedSlot, tTree.s1);
    109 
    110  tTree.s3.assign(tTree.c3);
    111  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
    112  assert_array_equals(tTree.s2.assignedNodes(), [tTree.c2]);
    113  assert_array_equals(tTree.s3.assignedNodes(), [tTree.c3]);
    114  assert_equals(tTree.c1.assignedSlot, tTree.s1);
    115  assert_equals(tTree.c2.assignedSlot, tTree.s2);
    116  assert_equals(tTree.c3.assignedSlot, tTree.s3);
    117 }, 'Previously assigned slottable is moved to new slot when it\'s reassigned.');
    118 
    119 test(() => {
    120 let tTree = createTestTree(test_assign);
    121 
    122  tTree.s1.assign(tTree.c1);
    123  tTree.s2.assign(tTree.c2, tTree.c1);
    124  tTree.s3.assign(tTree.c1, tTree.c3);
    125 
    126  assert_array_equals(tTree.s1.assignedNodes(), []);
    127  assert_array_equals(tTree.s2.assignedNodes(), [tTree.c2]);
    128  assert_array_equals(tTree.s3.assignedNodes(), [tTree.c1, tTree.c3]);
    129  assert_equals(tTree.c1.assignedSlot, tTree.s3);
    130  assert_equals(tTree.c2.assignedSlot, tTree.s2);
    131  assert_equals(tTree.c3.assignedSlot, tTree.s3);
    132 }, 'Order and assignment of nodes are preserved during multiple assignment in a row.');
    133 
    134 test(() => {
    135  let tTree = createTestTree(test_assign);
    136 
    137  // tTree.c4 is invalid for tTree.host slot assignment.
    138  // No exception should be thrown here.
    139  tTree.s1.assign(tTree.c1, tTree.c4, tTree.c2);
    140 
    141  // All observable assignments should skip c4.
    142  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
    143  assert_equals(tTree.c1.assignedSlot, tTree.s1);
    144  assert_equals(tTree.c2.assignedSlot, tTree.s1);
    145  assert_equals(tTree.c4.assignedSlot, null);
    146 
    147  // Moving c4 into place should reveal the assignment.
    148  tTree.host.append(tTree.c4);
    149  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c4, tTree.c2]);
    150  assert_equals(tTree.c1.assignedSlot, tTree.s1);
    151  assert_equals(tTree.c2.assignedSlot, tTree.s1);
    152  assert_equals(tTree.c4.assignedSlot, tTree.s1);
    153 
    154  // Moving c4 into a different shadow host and back should
    155  // also not break the assignment.
    156  tTree.host4.append(tTree.c4)
    157  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
    158  assert_equals(tTree.c4.assignedSlot, null);
    159  tTree.host.append(tTree.c4);
    160  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c4, tTree.c2]);
    161  assert_equals(tTree.c4.assignedSlot, tTree.s1);
    162 }, 'Assigning invalid nodes should be allowed.');
    163 
    164 test(() => {
    165  let tTree = createTestTree(test_assign);
    166 
    167  tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3);
    168  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2, tTree.c3]);
    169 
    170  tTree.host4.append(tTree.s1);
    171  assert_array_equals(tTree.s1.assignedNodes(), []);
    172 }, 'Moving a slot to a new host, the slot loses its previously assigned slottables.');
    173 
    174 test(() => {
    175  let tTree = createTestTree(test_assign);
    176 
    177  tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3);
    178  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2, tTree.c3]);
    179 
    180  tTree.shadow_root.insertBefore(tTree.s2, tTree.s1);
    181  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2, tTree.c3]);
    182  assert_array_equals(tTree.s2.assignedNodes(), []);
    183 
    184  tTree.shadow_root.insertBefore(tTree.s4, tTree.s1);
    185  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2, tTree.c3]);
    186  assert_array_equals(tTree.s4.assignedNodes(), []);
    187 
    188  tTree.ns1.append(tTree.s1);
    189  assert_array_equals(tTree.s1.assignedNodes(), []);
    190 }, 'Moving a slot\'s tree order position within a shadow host has no impact on its assigned slottables.');
    191 
    192 test(() => {
    193  let tTree = createTestTree(test_assign);
    194 
    195  tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3);
    196  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2, tTree.c3]);
    197 
    198  tTree.host4.append(tTree.c1);
    199  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c2, tTree.c3]);
    200  assert_array_equals(tTree.s4.assignedNodes(), []);
    201  assert_equals(tTree.c1.assignedSlot, null);
    202 
    203  tTree.s4.assign(tTree.c1);
    204  assert_array_equals(tTree.s4.assignedNodes(), [tTree.c1]);
    205  assert_equals(tTree.c1.assignedSlot, tTree.s4);
    206 }, 'Appending slottable to different host, it loses slot assignment. It can be re-assigned within a new host.');
    207 
    208 test(() => {
    209  let tTree = createTestTree(test_assign);
    210 
    211  tTree.s1.assign(tTree.c1);
    212  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
    213 
    214  tTree.shadow_root4.insertBefore(tTree.s1, tTree.s4);
    215  assert_array_equals(tTree.s1.assignedNodes(), []);
    216  // Trigger slot assignment on previous shadow root.
    217  assert_array_equals(tTree.s2.assignedNodes(), []);
    218 
    219  tTree.shadow_root.insertBefore(tTree.s1, tTree.s2);
    220  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
    221 }, 'Previously assigned node should not be assigned if slot moved to a new shadow root. The node is re-assigned when moved back.');
    222 
    223 test(() => {
    224  let tTree = createTestTree(test_assign);
    225 
    226  tTree.s1.assign(tTree.c1, tTree.c1, tTree.c1);
    227  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1]);
    228 
    229  tTree.s1.assign(tTree.c1, tTree.c1, tTree.c2, tTree.c2, tTree.c1);
    230  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
    231 }, 'Assignment with the same node in parameters should be ignored, first one wins.');
    232 
    233 test(() => {
    234  let tTree = createTestTree(test_assign);
    235 
    236  tTree.s1.assign(tTree.c1, tTree.c2, tTree.c3);
    237  tTree.s1.remove();
    238 
    239  assert_equals(tTree.c1.assignedSlot, null);
    240  assert_equals(tTree.c2.assignedSlot, null);
    241  assert_equals(tTree.c3.assignedSlot, null);
    242 }, 'Removing a slot from DOM resets its slottable\'s slot assignment.');
    243 
    244 test(() => {
    245  let tTree = createTestTree(test_assign);
    246 
    247  const isolatedDocNode = document.implementation.createHTMLDocument("").body;
    248  isolatedDocNode.appendChild(tTree.c1);
    249  const isolatedDocNode2 = document.implementation.createHTMLDocument("").body;
    250  isolatedDocNode2.appendChild(tTree.s1);
    251 
    252  tTree.s1.assign(tTree.c1, tTree.c2);
    253  assert_array_equals(tTree.s1.assignedNodes(), [], 's1 not inside shadow root');
    254  assert_equals(tTree.c1.assignedSlot, null);
    255  assert_equals(tTree.c2.assignedSlot, null);
    256 
    257  tTree.shadow_root.appendChild(tTree.s1);
    258  tTree.host.appendChild(tTree.c1);
    259  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
    260  assert_equals(tTree.c1.assignedSlot, tTree.s1);
    261  assert_equals(tTree.c2.assignedSlot, tTree.s1);
    262 }, 'Nodes can be assigned even if slots or nodes aren\'t in the same tree.');
    263 
    264 test(() => {
    265  let tTree = createTestTree(test_assign);
    266 
    267  tTree.s1.assign(tTree.c1, tTree.c2);
    268  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
    269  assert_equals(tTree.c1.assignedSlot, tTree.s1);
    270  assert_equals(tTree.c2.assignedSlot, tTree.s1);
    271 
    272  const isolatedDocNode = document.implementation.createHTMLDocument("").body;
    273  isolatedDocNode.appendChild(tTree.c1);
    274  const isolatedDocNode2 = document.implementation.createHTMLDocument("").body;
    275  isolatedDocNode2.appendChild(tTree.s1);
    276 
    277  assert_array_equals(tTree.s1.assignedNodes(), [], 's1 not inside shadow root');
    278  assert_equals(tTree.c1.assignedSlot, null);
    279  assert_equals(tTree.c2.assignedSlot, null);
    280 
    281  tTree.shadow_root.appendChild(tTree.s1);
    282  tTree.host.appendChild(tTree.c1);
    283  assert_array_equals(tTree.s1.assignedNodes(), [tTree.c1, tTree.c2]);
    284  assert_equals(tTree.c1.assignedSlot, tTree.s1);
    285  assert_equals(tTree.c2.assignedSlot, tTree.s1);
    286 }, 'Removing a node from the document does not break manually assigned slot linkage.');
    287 
    288 test(() => {
    289  const inputValues = [
    290    ['Attr', document.createAttribute('bar')],
    291    ['Comment', document.createComment('bar')],
    292    ['DocumentFragment', document.createDocumentFragment()],
    293    ['DocumentType', document.implementation.createDocumentType('html', '', '')]
    294  ];
    295  for (const [label, input] of inputValues) {
    296    assert_throws_js(TypeError, () => {
    297      const slot = document.createElement('slot');
    298      slot.assign(input);
    299    }, label);
    300  }
    301 }, 'throw TypeError if the passed values are neither Element nor Text');
    302 
    303 </script>