|
1 <!DOCTYPE HTML> |
|
2 <html id="html" style="height:100%"> |
|
3 <!-- |
|
4 https://bugzilla.mozilla.org/show_bug.cgi?id=780847 |
|
5 --> |
|
6 <head> |
|
7 <title>Test radii for mouse events</title> |
|
8 <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
|
9 <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> |
|
10 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> |
|
11 <style> |
|
12 .target { position:absolute; left:100px; top:100px; width:100px; height:100px; background:blue; } |
|
13 </style> |
|
14 </head> |
|
15 <body id="body" onload="setTimeout(startTest, 0)" style="margin:0; width:100%; height:100%; overflow:hidden"> |
|
16 <p id="display"></p> |
|
17 <div id="content"> |
|
18 <div id="ruler" style="position:absolute; left:0; top:0; width:1mozmm; height:0;"></div> |
|
19 |
|
20 <div class="target" id="t" onmousedown="x=1"></div> |
|
21 |
|
22 <div class="target" id="t2" hidden></div> |
|
23 |
|
24 <input class="target" id="t3_1" hidden></input> |
|
25 <a href="#" class="target" id="t3_2" hidden></a> |
|
26 <label class="target" id="t3_3" hidden></label> |
|
27 <button class="target" id="t3_4" hidden></button> |
|
28 <select class="target" id="t3_5" hidden></select> |
|
29 <textarea class="target" id="t3_6" hidden></textarea> |
|
30 <div role="button" class="target" id="t3_7" hidden></div> |
|
31 <div role="key" class="target" id="t3_8" hidden></div> |
|
32 <img class="target" id="t3_9" hidden></img> |
|
33 |
|
34 <div class="target" style="transform:translate(-80px,0);" id="t4" onmousedown="x=1" hidden></div> |
|
35 |
|
36 <div class="target" style="left:0; z-index:1" id="t5_left" onmousedown="x=1" hidden></div> |
|
37 <div class="target" style="left:106px;" id="t5_right" onmousedown="x=1" hidden></div> |
|
38 <div class="target" style="left:0; top:210px;" id="t5_below" onmousedown="x=1" hidden></div> |
|
39 |
|
40 <div class="target" id="t6" onmousedown="x=1" hidden> |
|
41 <div id="t6_inner" style="position:absolute; left:-20px; top:20px; width:60px; height:60px; background:yellow;"></div> |
|
42 </div> |
|
43 |
|
44 <div class="target" id="t7" onmousedown="x=1" hidden></div> |
|
45 <div class="target" id="t7_over" hidden></div> |
|
46 |
|
47 <div id="t8" contenteditable="true" class="target" hidden></div> |
|
48 |
|
49 <div id="t9" class="target" ontouchend="x=1" hidden></div> |
|
50 |
|
51 <div id="t10_left" class="target" style="left:-50px;" onmousedown="x=1" hidden></div> |
|
52 <div id="t10_right" class="target" style="left:auto;right:-50px" onmousedown="x=1" hidden></div> |
|
53 <div id="t10_top" class="target" style="top:-50px;" onmousedown="x=1" hidden></div> |
|
54 <div id="t10_bottom" class="target" style="top:auto;bottom:-50px;" onmousedown="x=1" hidden></div> |
|
55 <div id="t10_over" style="position:absolute; left:0; top:0; width:100%; height:100%; background:yellow;" hidden></div> |
|
56 </div> |
|
57 <pre id="test"> |
|
58 <script type="application/javascript"> |
|
59 function startTest() { |
|
60 SpecialPowers.pushPrefEnv({"set": [["ui.mouse.radius.enabled", true], |
|
61 ["ui.mouse.radius.inputSource.touchOnly", false], |
|
62 ["ui.mouse.radius.leftmm", 12], |
|
63 ["ui.mouse.radius.topmm", 8], |
|
64 ["ui.mouse.radius.rightmm", 4], |
|
65 ["ui.mouse.radius.bottommm", 4], |
|
66 ["ui.mouse.radius.visitedweight", 50]]}, runTest); |
|
67 } |
|
68 |
|
69 |
|
70 SimpleTest.waitForExplicitFinish(); |
|
71 |
|
72 function endTest() { |
|
73 SimpleTest.finish(); |
|
74 } |
|
75 |
|
76 var eventTarget; |
|
77 window.onmousedown = function(event) { eventTarget = event.target; }; |
|
78 |
|
79 function testMouseClick(idPosition, dx, dy, idTarget, msg, options) { |
|
80 eventTarget = null; |
|
81 synthesizeMouse(document.getElementById(idPosition), dx, dy, options || {}); |
|
82 try { |
|
83 is(eventTarget.id, idTarget, |
|
84 "checking '" + idPosition + "' offset " + dx + "," + dy + " [" + msg + "]"); |
|
85 } catch (ex) { |
|
86 ok(false, "checking '" + idPosition + "' offset " + dx + "," + dy + " [" + msg + "]; got " + eventTarget); |
|
87 } |
|
88 } |
|
89 |
|
90 function setShowing(id, show) { |
|
91 var e = document.getElementById(id); |
|
92 e.hidden = !show; |
|
93 } |
|
94 |
|
95 var mm; |
|
96 function runTest() { |
|
97 mm = document.getElementById("ruler").getBoundingClientRect().width; |
|
98 ok(4*mm >= 10, "WARNING: mm " + mm + " too small in this configuration. Test results will be bogus"); |
|
99 |
|
100 // Test basic functionality: clicks sufficiently close to the element |
|
101 // should be allowed to hit the element. We test points just inside and |
|
102 // just outside the edges we set up in the prefs. |
|
103 testMouseClick("t", 100 + 13*mm, 10, "body", "basic functionality"); |
|
104 testMouseClick("t", 100 + 11*mm, 10, "t", "basic functionality"); |
|
105 testMouseClick("t", 10, 100 + 9*mm, "body", "basic functionality"); |
|
106 testMouseClick("t", 10, 100 + 7*mm, "t", "basic functionality"); |
|
107 testMouseClick("t", -5*mm, 10, "body", "basic functionality"); |
|
108 testMouseClick("t", -3*mm, 10, "t", "basic functionality"); |
|
109 testMouseClick("t", 10, -5*mm, "body", "basic functionality"); |
|
110 testMouseClick("t", 10, -3*mm, "t", "basic functionality"); |
|
111 |
|
112 // When inputSource.touchOnly is true, mouse input is not retargeted. |
|
113 SpecialPowers.pushPrefEnv({"set": [["ui.mouse.radius.inputSource.touchOnly", true]]}, test2); |
|
114 } |
|
115 |
|
116 function test2() { |
|
117 testMouseClick("t", 100 + 11*mm, 10, "body", "disabled for mouse input"); |
|
118 testMouseClick("t", 100 + 11*mm, 10, "t", "enabled for touch input", { |
|
119 inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH |
|
120 }); |
|
121 testMouseClick("t", 100 + 13*mm, 10, "body", "basic functionality for touch", { |
|
122 inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH |
|
123 }); |
|
124 SpecialPowers.pushPrefEnv({"set": [["ui.mouse.radius.inputSource.touchOnly", false]]}, test3); |
|
125 } |
|
126 |
|
127 function test3() { |
|
128 setShowing("t", false); |
|
129 |
|
130 // Now test the criteria we use to determine which elements are hittable |
|
131 // this way. |
|
132 |
|
133 setShowing("t2", true); |
|
134 var t2 = document.getElementById("t2"); |
|
135 // Unadorned DIVs are not click radius targets |
|
136 testMouseClick("t2", 100 + 11*mm, 10, "body", "unadorned DIV"); |
|
137 // DIVs with the right event handlers are click radius targets |
|
138 t2.onmousedown = function() {}; |
|
139 testMouseClick("t2", 100 + 11*mm, 10, "t2", "DIV with onmousedown"); |
|
140 t2.onmousedown = null; |
|
141 testMouseClick("t2", 100 + 11*mm, 10, "body", "DIV with onmousedown removed"); |
|
142 t2.onmouseup = function() {}; |
|
143 testMouseClick("t2", 100 + 11*mm, 10, "t2", "DIV with onmouseup"); |
|
144 t2.onmouseup = null; |
|
145 t2.onclick = function() {}; |
|
146 testMouseClick("t2", 100 + 11*mm, 10, "t2", "DIV with onclick"); |
|
147 t2.onclick = null; |
|
148 // Keypresses don't make click radius targets |
|
149 t2.onkeypress = function() {}; |
|
150 testMouseClick("t2", 100 + 11*mm, 10, "body", "DIV with onkeypress"); |
|
151 t2.onkeypress = null; |
|
152 setShowing("t2", false); |
|
153 |
|
154 // Now check that certain elements are click radius targets and others are not |
|
155 for (var i = 1; i <= 9; ++i) { |
|
156 var id = "t3_" + i; |
|
157 var shouldHit = i <= 8; |
|
158 setShowing(id, true); |
|
159 testMouseClick(id, 100 + 11*mm, 10, shouldHit ? id : "body", |
|
160 "<" + document.getElementById(id).tagName + "> element"); |
|
161 setShowing(id, false); |
|
162 } |
|
163 |
|
164 // Check that our targeting computations take into account the effects of |
|
165 // CSS transforms |
|
166 setShowing("t4", true); |
|
167 testMouseClick("t4", -1, 10, "t4", "translated DIV"); |
|
168 setShowing("t4", false); |
|
169 |
|
170 // Test the prioritization of multiple targets based on distance to |
|
171 // the target. |
|
172 setShowing("t5_left", true); |
|
173 setShowing("t5_right", true); |
|
174 setShowing("t5_below", true); |
|
175 testMouseClick("t5_left", 102, 10, "t5_left", "closest DIV is left"); |
|
176 testMouseClick("t5_left", 102.5, 10, "t5_left", |
|
177 "closest DIV to midpoint is left because of its higher z-index"); |
|
178 testMouseClick("t5_left", 104, 10, "t5_right", "closest DIV is right"); |
|
179 testMouseClick("t5_left", 10, 104, "t5_left", "closest DIV is left"); |
|
180 testMouseClick("t5_left", 10, 105, "t5_left", |
|
181 "closest DIV to midpoint is left because of its higher z-index"); |
|
182 testMouseClick("t5_left", 10, 106, "t5_below", "closest DIV is below"); |
|
183 setShowing("t5_left", false); |
|
184 setShowing("t5_right", false); |
|
185 setShowing("t5_below", false); |
|
186 |
|
187 // Test behavior of nested elements. |
|
188 // The following behaviors are questionable and may need to be changed. |
|
189 setShowing("t6", true); |
|
190 testMouseClick("t6_inner", -1, 10, "t6_inner", |
|
191 "inner element is clickable because its parent is, even when it sticks outside parent"); |
|
192 testMouseClick("t6_inner", 19, -1, "t6_inner", |
|
193 "when outside both inner and parent, but in range of both, the inner is selected"); |
|
194 testMouseClick("t6_inner", 25, -1, "t6", |
|
195 "clicking in clickable parent close to inner activates parent, not inner"); |
|
196 setShowing("t6", false); |
|
197 |
|
198 setShowing("t7", true); |
|
199 setShowing("t7_over", true); |
|
200 testMouseClick("t7", 100 + 11*mm, 10, "body", "covered div is not clickable"); |
|
201 testMouseClick("t7", 10, 10, "t7_over", "covered div is not clickable even within its bounds"); |
|
202 setShowing("t7", false); |
|
203 setShowing("t7_over", false); |
|
204 |
|
205 // Check that contenteditable elements are considered clickable for fluffing. |
|
206 setShowing("t8", true); |
|
207 var rect = document.getElementById("t8").getBoundingClientRect(); |
|
208 testMouseClick("t8", rect.left + 1, rect.top + 1, "t8", "content editable enabled for mouse input"); |
|
209 testMouseClick("t8", rect.left + 1, rect.top + 1, "t8", "content editable enabled for touch input", { |
|
210 inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH |
|
211 }); |
|
212 setShowing("t8", false); |
|
213 |
|
214 // Check that elements are touchable |
|
215 setShowing("t9", true); |
|
216 var rect = document.getElementById("t9").getBoundingClientRect(); |
|
217 testMouseClick("t9", rect.left + 1, rect.top + 1, "t9", "div enabled with mouse input"); |
|
218 testMouseClick("t9", rect.left + 1, rect.top + 1, "t9", "div enabled with touch input", { |
|
219 inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH |
|
220 }); |
|
221 setShowing("t9", false); |
|
222 |
|
223 setShowing("t10_over", true); |
|
224 setShowing("t10_left", true); |
|
225 setShowing("t10_right", true); |
|
226 setShowing("t10_top", true); |
|
227 setShowing("t10_bottom", true); |
|
228 testMouseClick("t10_left", 51, 10, "t10_over", "element outside of visible area is not selected"); |
|
229 if (self.frameElement && |
|
230 (self.frameElement.offsetLeft + self.innerWidth > |
|
231 SpecialPowers.wrap(top).innerWidth)) { |
|
232 info("WARNING: Window is too narrow, can't test t10_right"); |
|
233 } else { |
|
234 testMouseClick("t10_right", 49, 10, "t10_over", "element outside of visible area is not selected"); |
|
235 } |
|
236 testMouseClick("t10_top", 10, 51, "t10_over", "element outside of visible area is not selected"); |
|
237 if (self.frameElement && |
|
238 (self.frameElement.offsetTop + self.innerHeight > |
|
239 SpecialPowers.wrap(top).innerHeight)) { |
|
240 info("WARNING: Window is too short, can't test t10_bottom"); |
|
241 } else { |
|
242 testMouseClick("t10_bottom", 10, 49, "t10_over", "element outside of visible area is not selected"); |
|
243 } |
|
244 setShowing("t10_over", false); |
|
245 setShowing("t10_left", false); |
|
246 setShowing("t10_right", false); |
|
247 setShowing("t10_top", false); |
|
248 setShowing("t10_bottom", false); |
|
249 |
|
250 // Not yet tested: |
|
251 // -- visited link weight |
|
252 // -- "Closest" using Euclidean distance |
|
253 endTest(); |
|
254 } |
|
255 </script> |
|
256 </pre> |
|
257 </body> |
|
258 </html> |