summaryrefslogtreecommitdiffstats
path: root/dom/html/test/forms/test_input_range_mouse_and_touch_events.html
blob: 92cd1b3095f39b9bc6e27a104d33c6db552ad9de (plain)
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
225
226
227
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=846380
-->
<head>
  <title>Test mouse and touch events for range</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/EventUtils.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    /* synthesizeMouse and synthesizeFunc uses getBoundingClientRect. We set
     * the following properties to avoid fractional values in the rect returned
     * by getBoundingClientRect in order to avoid rounding that would occur
     * when event coordinates are internally converted to be relative to the
     * top-left of the element. (Such rounding would make it difficult to
     * predict exactly what value the input should take on for events at
     * certain coordinates.)
     */
    input { margin: 0 ! important; width: 200px ! important; }
  </style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=846380">Mozilla Bug 846380</a>
<p id="display"></p>
<div id="content">
  <input id="range" type="range">
</div>
<pre id="test">
<script type="application/javascript">

/**
 * Test for Bug 846380
 * This test checks how the value of <input type=range> changes in response to
 * various mouse and touch events.
 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
  test(synthesizeMouse, "click", "mousedown", "mousemove", "mouseup");
  test(synthesizeTouch, "tap", "touchstart", "touchmove", "touchend");
  SimpleTest.finish();
});

const MIDDLE_OF_RANGE = "50";
const MINIMUM_OF_RANGE = "0";
const MAXIMUM_OF_RANGE = "100";
const QUARTER_OF_RANGE = "25";
const THREE_QUARTERS_OF_RANGE = "75";

function flush() {
  // Flush style, specifically to flush the 'direction' property so that the
  // browser uses the new value for thumb positioning.
  document.body.clientWidth;
}

function test(synthesizeFunc, clickOrTap, startName, moveName, endName) {
  var elem = document.getElementById("range");
  elem.focus();
  flush();

  var width = parseFloat(window.getComputedStyle(elem).width);
  var height = parseFloat(window.getComputedStyle(elem).height);
  var borderLeft = parseFloat(window.getComputedStyle(elem).borderLeftWidth);
  var borderTop = parseFloat(window.getComputedStyle(elem).borderTopWidth);
  var paddingLeft = parseFloat(window.getComputedStyle(elem).paddingLeft);
  var paddingTop = parseFloat(window.getComputedStyle(elem).paddingTop);

  // Extrema for mouse/touch events:
  var midY = height / 2 + borderTop + paddingTop;
  var minX = borderLeft + paddingLeft;
  var midX = minX + width / 2;
  var maxX = minX + width;

  // Test click/tap in the middle of the range:
  elem.value = QUARTER_OF_RANGE;
  synthesizeFunc(elem, midX, midY, {});
  is(elem.value, MIDDLE_OF_RANGE, "Test " + clickOrTap + " in middle of range");

  // Test mouse/touch dragging of ltr range:
  elem.value = QUARTER_OF_RANGE;
  synthesizeFunc(elem, midX, midY, { type: startName });
  is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range");
  synthesizeFunc(elem, minX, midY, { type: moveName });
  is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to left of ltr range");

  synthesizeFunc(elem, maxX, midY, { type: moveName });
  is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to right of ltr range (" + moveName + ")");

  synthesizeFunc(elem, maxX, midY, { type: endName });
  is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to right of ltr range (" + endName + ")");

  // Test mouse/touch dragging of rtl range:
  elem.value = QUARTER_OF_RANGE;
  elem.style.direction = "rtl";
  flush();
  synthesizeFunc(elem, midX, midY, { type: startName });
  is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of rtl range");
  synthesizeFunc(elem, minX, midY, { type: moveName });
  is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to left of rtl range");

  synthesizeFunc(elem, maxX, midY, { type: moveName });
  is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to right of rtl range (" + moveName + ")");

  synthesizeFunc(elem, maxX, midY, { type: endName });
  is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to right of rtl range (" + endName + ")");

  elem.style.direction = "ltr"; // reset direction
  flush();

  // Test mouse/touch capturing by moving pointer to a position outside the range:
  elem.value = QUARTER_OF_RANGE;
  synthesizeFunc(elem, midX, midY, { type: startName });
  is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range");
  synthesizeFunc(elem, maxX+100, midY, { type: moveName });
  is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to position outside range (" + moveName + ")");

  synthesizeFunc(elem, maxX+100, midY, { type: endName });
  is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to position outside range (" + endName + ")");

  // Test mouse/touch capturing by moving pointer to a position outside a rtl range:
  elem.value = QUARTER_OF_RANGE;
  elem.style.direction = "rtl";
  flush();
  synthesizeFunc(elem, midX, midY, { type: startName });
  is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of rtl range");
  synthesizeFunc(elem, maxX+100, midY, { type: moveName });
  is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to position outside range (" + moveName + ")");

  synthesizeFunc(elem, maxX+100, midY, { type: endName });
  is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to position outside range (" + endName + ")");

  elem.style.direction = "ltr"; // reset direction
  flush();

  // Test mouse/touch events with certain modifiers are ignored:
  var modifiersIgnore = ["ctrlKey", "altGrKey", "fnKey", "osKey"];
  for (var modifier of modifiersIgnore) {
    elem.value = QUARTER_OF_RANGE;
    var eventParams = {};
    eventParams[modifier] = true;
    synthesizeFunc(elem, midX, midY, eventParams);
    is(elem.value, QUARTER_OF_RANGE, "Test " + clickOrTap + " in the middle of range with " + modifier + " modifier key is ignored");
  }

  // Test mouse/touch events with certain modifiers are allowed:
  var modifiersAllow = ["shiftKey", "altKey", "metaKey"];
  for (var modifier of modifiersAllow) {
    elem.value = QUARTER_OF_RANGE;
    var eventParams = {};
    eventParams[modifier] = true;
    synthesizeFunc(elem, midX, midY, eventParams);
    is(elem.value, MIDDLE_OF_RANGE, "Test " + clickOrTap + " in the middle of range with " + modifier + " modifier key is allowed");
  }

  // Test that preventDefault() works:
  function preventDefault(e) {
    e.preventDefault();
  }
  elem.value = QUARTER_OF_RANGE;
  elem.addEventListener(startName, preventDefault);
  synthesizeFunc(elem, midX, midY, {});
  is(elem.value, QUARTER_OF_RANGE, "Test that preventDefault() works");
  elem.removeEventListener(startName, preventDefault);

  // Test that changing the input type in the middle of a drag cancels the drag:
  elem.value = QUARTER_OF_RANGE;
  synthesizeFunc(elem, midX, midY, { type: startName });
  is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range");
  elem.type = "text";
  is(elem.value, QUARTER_OF_RANGE, "Test that changing the input type cancels a drag");
  synthesizeFunc(elem, midX, midY, { type: endName });
  is(elem.value, QUARTER_OF_RANGE, "Test that changing the input type cancels a drag (after " + endName + ")");
  elem.type = "range";

  // Check that we do not drag when the mousedown/touchstart occurs outside the range:
  elem.value = QUARTER_OF_RANGE;
  synthesizeFunc(elem, maxX+100, midY, { type: startName });
  is(elem.value, QUARTER_OF_RANGE, "Test " + startName + " outside range doesn't change its value");
  synthesizeFunc(elem, midX, midY, { type: moveName });
  is(elem.value, QUARTER_OF_RANGE, "Test dragging is not occurring when " + startName + " was outside range");

  synthesizeFunc(elem, midX, midY, { type: endName });
  is(elem.value, QUARTER_OF_RANGE, "Test dragging is not occurring when " + startName + " was outside range");

  elem.focus(); // RESTORE FOCUS SO WE GET THE FOCUSED STYLE FOR TESTING OR ELSE minX/midX/maxX may be wrong!

  // Check what happens when a value changing key is pressed during a drag:
  elem.value = QUARTER_OF_RANGE;
  synthesizeFunc(elem, midX, midY, { type: startName });
  is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range");
  synthesizeKey("KEY_Home");
  // The KEY_Home tests are disabled until I can figure out why they fail on Android -jwatt
  //is(elem.value, MINIMUM_OF_RANGE, "Test KEY_Home during a drag sets the value to the minimum of the range");
  synthesizeFunc(elem, midX+100, midY, { type: moveName });
  is(elem.value, MAXIMUM_OF_RANGE, "Test " + moveName + " outside range after key press that occurred during a drag changes the value");
  synthesizeFunc(elem, midX, midY, { type: moveName });
  is(elem.value, MIDDLE_OF_RANGE, "Test " + moveName + " in middle of range");
  synthesizeKey("KEY_Home");
  //is(elem.value, MINIMUM_OF_RANGE, "Test KEY_Home during a drag sets the value to the minimum of the range (second time)");
  synthesizeFunc(elem, maxX+100, midY, { type: endName });
  is(elem.value, MAXIMUM_OF_RANGE, "Test " + endName + " outside range after key press that occurred during a drag changes the value");

  function hideElement() {
    elem.parentNode.style.display = 'none';
    elem.parentNode.offsetLeft;
  }

  if (clickOrTap == "click") {
    elem.addEventListener("mousedown", hideElement);
  } else if (clickOrTap == "tap") {
    elem.addEventListener("touchstart", hideElement);
  }
  synthesizeFunc(elem, midX, midY, { type: startName });
  synthesizeFunc(elem, midX, midY, { type: endName });
  elem.removeEventListener("mousedown", hideElement);
  elem.removeEventListener("touchstart", hideElement);
  ok(true, "Hiding the element during mousedown/touchstart shouldn't crash the process.");
  elem.parentNode.style.display = "block";
  elem.parentNode.offsetLeft;
}

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