pointerevent_boundary_events_on_image_map.html (14290B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, user-scalable=no"> 6 <title>Event targets of boundary events over an image map</title> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script src="/resources/testdriver.js"></script> 10 <script src="/resources/testdriver-actions.js"></script> 11 <script src="/resources/testdriver-vendor.js"></script> 12 <script> 13 "use strict"; 14 15 addEventListener("load", () => { 16 const initialDiv = document.getElementById("init"); 17 const container = document.getElementById("container"); 18 const img1 = document.getElementById("img1"); 19 const img2 = document.getElementById("img2"); 20 const area1_1 = document.getElementById("area1-1"); 21 const area1_2 = document.createElement("area"); 22 area1_2.setAttribute("id", "area1-2"); 23 area1_2.setAttribute("shape", "rect"); 24 area1_2.setAttribute("coords", "0,0,100,100"); 25 area1_2.setAttribute("href", "#"); 26 const area2_1 = document.getElementById("area2-1"); 27 const map1 = document.getElementById("map1"); 28 const map2 = document.getElementById("map2"); 29 30 function stringifyEvents(arrayOfEvents) { 31 function stringifyEvent(event) { 32 return `${event.type}@${event.target.localName}${ 33 event.target.id ? `#${event.target.id}` : "" 34 }` 35 } 36 let str = "["; 37 for (const event of arrayOfEvents) { 38 if (str != "[") { 39 str += ", "; 40 } 41 str += stringifyEvent(event); 42 } 43 return str + "]"; 44 } 45 46 let events = []; 47 function pushEvent(event) { 48 events.push(event); 49 } 50 for (const type of ["pointermove", "pointerover", "pointerenter", "pointerout", "pointerleave"]) { 51 container.addEventListener(type, pushEvent, {capture: true}); 52 } 53 54 promise_test(async () => { 55 events = []; 56 await new test_driver.Actions() 57 .pointerMove(0, 0, {origin: initialDiv}) 58 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 59 .pointerMove(0, 0, {origin: initialDiv}) 60 .send(); 61 assert_equals( 62 stringifyEvents(events), 63 stringifyEvents([ 64 {type: "pointerover", target: area1_1}, 65 {type: "pointerenter", target: container}, 66 {type: "pointerenter", target: map1}, 67 {type: "pointerenter", target: area1_1}, 68 {type: "pointermove", target: area1_1}, 69 {type: "pointerout", target: area1_1}, 70 {type: "pointerleave", target: area1_1}, 71 {type: "pointerleave", target: map1}, 72 {type: "pointerleave", target: container}, 73 ]) 74 ); 75 }, "pointer boundary events when simple over/out"); 76 77 promise_test(async () => { 78 events = []; 79 await new test_driver.Actions() 80 .pointerMove(0, 0, {origin: initialDiv}) 81 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 82 .pointerMove(0, 0, {origin: img2}) // actually moved in area1-1 83 .pointerMove(0, 0, {origin: initialDiv}) 84 .send(); 85 assert_equals( 86 stringifyEvents(events), 87 stringifyEvents([ 88 {type: "pointerover", target: area1_1}, 89 {type: "pointerenter", target: container}, 90 {type: "pointerenter", target: map1}, 91 {type: "pointerenter", target: area1_1}, 92 {type: "pointermove", target: area1_1}, 93 // boundary events shouldn't be fired when moving from img1 to img2 94 {type: "pointermove", target: area1_1}, 95 {type: "pointerout", target: area1_1}, 96 {type: "pointerleave", target: area1_1}, 97 {type: "pointerleave", target: map1}, 98 {type: "pointerleave", target: container}, 99 ]) 100 ); 101 }, "pointer boundary events when moved from an <area> to the same <area> shared by another <img>"); 102 103 promise_test(async t => { 104 events = []; 105 function shrinkArea1_1() { 106 area1_1.setAttribute("coords", "0,0,10,10"); 107 t.add_cleanup(() => { 108 area1_1.setAttribute("coords", "0,0,100,100"); 109 }); 110 } 111 area1_1.addEventListener("pointermove", shrinkArea1_1, {once: true}); 112 t.add_cleanup(() => area1_1.removeEventListener("pointermove", shrinkArea1_1)); 113 await new test_driver.Actions() 114 .pointerMove(0, 0, {origin: initialDiv}) 115 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 116 .addTick(100) // now, over the <img> 117 .addTick() // for Firefox bug 1994340 118 .pointerMove(0, 0, {origin: initialDiv}) 119 .send(); 120 assert_equals( 121 stringifyEvents(events), 122 stringifyEvents([ 123 {type: "pointerover", target: area1_1}, 124 {type: "pointerenter", target: container}, 125 {type: "pointerenter", target: map1}, 126 {type: "pointerenter", target: area1_1}, 127 {type: "pointermove", target: area1_1}, 128 // Now, the <area> is shrunken and the cursor is not over the <area>. 129 {type: "pointerout", target: area1_1}, 130 {type: "pointerleave", target: area1_1}, 131 {type: "pointerleave", target: map1}, 132 {type: "pointerover", target: img1}, 133 {type: "pointerenter", target: img1}, 134 // Then, move out from the <img>. 135 {type: "pointerout", target: img1}, 136 {type: "pointerleave", target: img1}, 137 {type: "pointerleave", target: container}, 138 ]) 139 ); 140 }, "pointer boundary events when the <area> is resized"); 141 142 promise_test(async t => { 143 events = []; 144 function shrinkArea1_1() { 145 area1_1.setAttribute("coords", "0,0,10,10"); 146 img1.setAttribute("width", "200"); 147 img1.getBoundingClientRect(); 148 t.add_cleanup(() => { 149 img1.setAttribute("width", "100"); 150 area1_1.setAttribute("coords", "0,0,100,100"); 151 img1.getBoundingClientRect(); 152 }); 153 } 154 area1_1.addEventListener("pointermove", shrinkArea1_1, {once: true}); 155 t.add_cleanup(() => area1_1.removeEventListener("pointermove", shrinkArea1_1)); 156 await new test_driver.Actions() 157 .pointerMove(0, 0, {origin: initialDiv}) 158 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 159 .addTick() // now over the <img> 160 .pointerMove(0, 0, {origin: initialDiv}) 161 .send(); 162 assert_equals( 163 stringifyEvents(events), 164 stringifyEvents([ 165 {type: "pointerover", target: area1_1}, 166 {type: "pointerenter", target: container}, 167 {type: "pointerenter", target: map1}, 168 {type: "pointerenter", target: area1_1}, 169 {type: "pointermove", target: area1_1}, 170 // Now, the <area> is shrunken and the cursor is not over the <area>. 171 {type: "pointerout", target: area1_1}, 172 {type: "pointerleave", target: area1_1}, 173 {type: "pointerleave", target: map1}, 174 {type: "pointerover", target: img1}, 175 {type: "pointerenter", target: img1}, 176 // Then, move out from the <img>. 177 {type: "pointerout", target: img1}, 178 {type: "pointerleave", target: img1}, 179 {type: "pointerleave", target: container}, 180 ]) 181 ); 182 }, "pointer boundary events when both <area> and <img> are resized"); 183 184 promise_test(async t => { 185 events = []; 186 function switchMap() { 187 img1.setAttribute("usemap", "#map2"); 188 t.add_cleanup(() => { 189 img1.setAttribute("usemap", "#map1"); 190 }); 191 } 192 area1_1.addEventListener("pointermove", switchMap, {once: true}); 193 t.add_cleanup(() => area1_1.removeEventListener("pointermove", switchMap)); 194 await new test_driver.Actions() 195 .pointerMove(0, 0, {origin: initialDiv}) 196 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 197 .addTick(100) // now over area2-1 198 .addTick() // for Firefox bug 1994340 199 .pointerMove(0, 0, {origin: initialDiv}) 200 .send(); 201 assert_equals( 202 stringifyEvents(events), 203 stringifyEvents([ 204 {type: "pointerover", target: area1_1}, 205 {type: "pointerenter", target: container}, 206 {type: "pointerenter", target: map1}, 207 {type: "pointerenter", target: area1_1}, 208 {type: "pointermove", target: area1_1}, 209 // Now, the #map2 is the image map definition and over its area2-1 210 {type: "pointerout", target: area1_1}, 211 {type: "pointerleave", target: area1_1}, 212 {type: "pointerleave", target: map1}, 213 {type: "pointerover", target: area2_1}, 214 {type: "pointerenter", target: map2}, 215 {type: "pointerenter", target: area2_1}, 216 // Then, move out from the <area>. 217 {type: "pointerout", target: area2_1}, 218 {type: "pointerleave", target: area2_1}, 219 {type: "pointerleave", target: map2}, 220 {type: "pointerleave", target: container}, 221 ]) 222 ); 223 }, "pointer boundary events when usemap is modified"); 224 225 promise_test(async t => { 226 events = []; 227 function switchMap() { 228 img1.setAttribute("usemap", "#map2"); 229 img1.setAttribute("width", "200"); 230 img1.getBoundingClientRect(); 231 t.add_cleanup(() => { 232 img1.setAttribute("usemap", "#map1"); 233 img1.setAttribute("width", "100"); 234 img1.getBoundingClientRect(); 235 }); 236 } 237 area1_1.addEventListener("pointermove", switchMap, {once: true}); 238 t.add_cleanup(() => area1_1.removeEventListener("pointermove", switchMap)); 239 await new test_driver.Actions() 240 .pointerMove(0, 0, {origin: initialDiv}) 241 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 242 .addTick() // now over area2-1 243 .pointerMove(0, 0, {origin: initialDiv}) 244 .send(); 245 assert_equals( 246 stringifyEvents(events), 247 stringifyEvents([ 248 {type: "pointerover", target: area1_1}, 249 {type: "pointerenter", target: container}, 250 {type: "pointerenter", target: map1}, 251 {type: "pointerenter", target: area1_1}, 252 {type: "pointermove", target: area1_1}, 253 // Now, the #map2 is the image map definition and over its area2-1 254 {type: "pointerout", target: area1_1}, 255 {type: "pointerleave", target: area1_1}, 256 {type: "pointerleave", target: map1}, 257 {type: "pointerover", target: area2_1}, 258 {type: "pointerenter", target: map2}, 259 {type: "pointerenter", target: area2_1}, 260 // Then, move out from the <area>. 261 {type: "pointerout", target: area2_1}, 262 {type: "pointerleave", target: area2_1}, 263 {type: "pointerleave", target: map2}, 264 {type: "pointerleave", target: container}, 265 ]) 266 ); 267 }, "pointer boundary events when usemap is modified and <img> is resized"); 268 269 promise_test(async t => { 270 events = []; 271 function appendArea1_2() { 272 map1.insertBefore(area1_2, area1_1); 273 t.add_cleanup(() => { 274 area1_2.remove(); 275 }); 276 } 277 area1_1.addEventListener("pointermove", appendArea1_2, {once: true}); 278 t.add_cleanup(() => area1_1.removeEventListener("pointermove", appendArea1_2)); 279 await new test_driver.Actions() 280 .pointerMove(0, 0, {origin: initialDiv}) 281 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 282 .addTick(100) // now, over the area1-2 283 .addTick() // for Firefox bug 1994340 284 .pointerMove(0, 0, {origin: initialDiv}) 285 .send(); 286 assert_equals( 287 stringifyEvents(events), 288 stringifyEvents([ 289 {type: "pointerover", target: area1_1}, 290 {type: "pointerenter", target: container}, 291 {type: "pointerenter", target: map1}, 292 {type: "pointerenter", target: area1_1}, 293 {type: "pointermove", target: area1_1}, 294 // Now, new <area> is inserted and it's the top-most. 295 {type: "pointerout", target: area1_1}, 296 {type: "pointerleave", target: area1_1}, 297 {type: "pointerover", target: area1_2}, 298 {type: "pointerenter", target: area1_2}, 299 // Then, move out from the <img>. 300 {type: "pointerout", target: area1_2}, 301 {type: "pointerleave", target: area1_2}, 302 {type: "pointerleave", target: map1}, 303 {type: "pointerleave", target: container}, 304 ]) 305 ); 306 }, "pointer boundary events when new <area> is available"); 307 308 promise_test(async t => { 309 events = []; 310 function appendArea1_2() { 311 map1.insertBefore(area1_2, area1_1); 312 img1.setAttribute("width", "200"); 313 img1.getBoundingClientRect(); 314 t.add_cleanup(() => { 315 area1_2.remove(); 316 img1.setAttribute("width", "100"); 317 img1.getBoundingClientRect(); 318 }); 319 } 320 area1_1.addEventListener("pointermove", appendArea1_2, {once: true}); 321 t.add_cleanup(() => area1_1.removeEventListener("pointermove", appendArea1_2)); 322 await new test_driver.Actions() 323 .pointerMove(0, 0, {origin: initialDiv}) 324 .pointerMove(0, 0, {origin: img1}) // actually moved over area1-1 325 .addTick() // now, over the area1-2 326 .pointerMove(0, 0, {origin: initialDiv}) 327 .send(); 328 assert_equals( 329 stringifyEvents(events), 330 stringifyEvents([ 331 {type: "pointerover", target: area1_1}, 332 {type: "pointerenter", target: container}, 333 {type: "pointerenter", target: map1}, 334 {type: "pointerenter", target: area1_1}, 335 {type: "pointermove", target: area1_1}, 336 // Now, new <area> is inserted and it's the top-most. 337 {type: "pointerout", target: area1_1}, 338 {type: "pointerleave", target: area1_1}, 339 {type: "pointerover", target: area1_2}, 340 {type: "pointerenter", target: area1_2}, 341 // Then, move out from the <img>. 342 {type: "pointerout", target: area1_2}, 343 {type: "pointerleave", target: area1_2}, 344 {type: "pointerleave", target: map1}, 345 {type: "pointerleave", target: container}, 346 ]) 347 ); 348 }, "pointer boundary events when new <area> is available and the <img> is resized"); 349 }, {once: true}); 350 </script> 351 <style> 352 img { 353 margin: 0; 354 border: none; 355 } 356 div { 357 margin: 0; 358 width: 200px; 359 white-space: nowrap; 360 } 361 </style> 362 </head> 363 <body> 364 <div id="init">initial position</div> 365 <div id="container"> 366 <map id="map1"> 367 <area id="area1-1" shape="rect" coords="0,0,100,100" href="#"> 368 </map> 369 <map id="map2"> 370 <area id="area2-1" shape="rect" coords="0,0,100,100" href="#"> 371 </map> 372 <img id="img1" usemap="#map1" src="../images/green-16x16.png" width="100" height="100"> 373 <img id="img2" usemap="#map1" src="../images/green-16x16.png" width="100" height="100"> 374 </div> 375 </body> 376 </html>