Skip to content

Commit 0cbc0bd

Browse files
authoredNov 24, 2020
fix(ui5-slider): add more tests, add cozy styles, fix input event, fix tickmarks display (#2508)
New tests are added to cover using 'effective' properties for calculation instead of normaliziations of the real ones. Added cozy styles and set as default while the compact css vars are now moved to sizes-parameters.css files. Input event is now fixed and fired only after the current value is changed by user interaction. Updating the labels based on the other properties is fixed - labels are now getting re-created if the one of the other component's properties is updated. Tick-marks bug when sometimes the tick-mars are hidden under the parent's background is fixed, the tick mark DOM element no longer has a z-index set to -1.
1 parent dba6525 commit 0cbc0bd

12 files changed

+241
-27
lines changed
 

‎packages/main/src/RangeSlider.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class RangeSlider extends SliderBase {
142142
}
143143

144144
// Calculate the new value from the press position of the event
145-
const newValue = this.handleDownBase(event, this._effectiveMin, this._effectiveMax);
145+
const newValue = this.handleDownBase(event);
146146

147147
// Determine the rest of the needed details from the start of the interaction.
148148
this._saveInteractionStartData(event, newValue);

‎packages/main/src/Slider.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class Slider extends SliderBase {
118118
return;
119119
}
120120

121-
const newValue = this.handleDownBase(event, this._effectiveMin, this._effectiveMax);
121+
const newValue = this.handleDownBase(event);
122122
this._valueOnInteractionStart = this.value;
123123

124124
// Do not yet update the Slider if press is over a handle. It will be updated if the user drags the mouse.

‎packages/main/src/SliderBase.hbs

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
dir="{{effectiveDir}}"
88
>
99
<div class="ui5-slider-inner">
10-
<div class="ui5-slider-progress-container">
11-
<div class="ui5-slider-progress" style="{{styles.progress}}"></div>
12-
</div>
13-
1410
{{#if step}}
1511
{{#if showTickmarks}}
1612
<div class="ui5-slider-tickmarks" style="{{styles.tickmarks}}"></div>
@@ -23,6 +19,10 @@
2319
{{/if}}
2420
{{/if}}
2521
{{/if}}
22+
23+
<div class="ui5-slider-progress-container">
24+
<div class="ui5-slider-progress" style="{{styles.progress}}"></div>
25+
</div>
2626
{{> handles}}
2727
</div>
2828
</div>

‎packages/main/src/SliderBase.js

+25-6
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ class SliderBase extends UI5Element {
166166
step: null,
167167
min: null,
168168
max: null,
169+
labelInterval: null,
169170
};
170171
}
171172

@@ -301,20 +302,26 @@ class SliderBase extends UI5Element {
301302
*
302303
* @protected
303304
*/
304-
handleDownBase(event, min, max) {
305+
handleDownBase(event) {
306+
const min = this._effectiveMin;
307+
const max = this._effectiveMax;
308+
const domRect = this.getBoundingClientRect();
309+
const directionStart = this.directionStart;
310+
const step = this._effectiveStep;
311+
const newValue = SliderBase.getValueFromInteraction(event, step, min, max, domRect, directionStart);
312+
305313
if (isPhone() && this.showTooltip) {
306314
this._tooltipVisibility = "visible";
307315
}
308316

317+
// Mark start of a user interaction
318+
this._isUserInteraction = true;
309319
// Only allow one type of move event to be listened to (the first one registered after the down event)
310320
this._moveEventType = !this._moveEventType ? SliderBase.MOVE_EVENT_MAP[event.type] : this._moveEventType;
311321

312322
SliderBase.UP_EVENTS.forEach(upEventType => window.addEventListener(upEventType, this._upHandler));
313323
window.addEventListener(this._moveEventType, this._moveHandler);
314324

315-
this._boundingClientRect = this.getBoundingClientRect();
316-
const newValue = SliderBase.getValueFromInteraction(event, this.step, min, max, this._boundingClientRect, this.directionStart);
317-
318325
return newValue;
319326
}
320327

@@ -333,6 +340,7 @@ class SliderBase extends UI5Element {
333340
window.removeEventListener(this._moveEventType, this._moveHandler);
334341

335342
this._moveEventType = null;
343+
this._isUserInteraction = false;
336344
}
337345

338346
/**
@@ -344,7 +352,9 @@ class SliderBase extends UI5Element {
344352
updateValue(valueType, value) {
345353
this[valueType] = value;
346354
this.storePropertyState(valueType);
347-
this.fireEvent("input");
355+
if (this._isUserInteraction) {
356+
this.fireEvent("input");
357+
}
348358
}
349359

350360
/**
@@ -446,7 +456,6 @@ class SliderBase extends UI5Element {
446456
// Recalculate the tickmarks and labels and update the stored state.
447457
if (this.isPropertyUpdated("min", "max", ...values)) {
448458
this.storePropertyState("min", "max");
449-
this._createLabels();
450459

451460
// Here the value props are changed programatically (not by user interaction)
452461
// and it won't be "stepified" (rounded to the nearest step). 'Clip' them within
@@ -457,6 +466,16 @@ class SliderBase extends UI5Element {
457466
this.storePropertyState(valueType);
458467
});
459468
}
469+
470+
// Labels must be updated if any of the min/max/step/labelInterval props are changed
471+
if (this.labelInterval && this.showTickmarks) {
472+
this._createLabels();
473+
}
474+
475+
// Update the stored state for the labelInterval, if changed
476+
if (this.isPropertyUpdated("labelInterval")) {
477+
this.storePropertyState("labelInterval");
478+
}
460479
}
461480

462481
/**

‎packages/main/src/themes/SliderBase.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
border: var(--_ui5_slider_progress_border);
3838
border-radius: var(--_ui5_slider_progress_border_radius);
3939
height: var(--_ui5_slider_inner_height);
40+
position: relative;
4041
}
4142

4243
.ui5-slider-progress {
@@ -53,7 +54,6 @@
5354
width: 100%;
5455
height: 1rem;
5556
top: var(--_ui5_slider_tickmark_top);
56-
z-index: -1;
5757
}
5858

5959
.ui5-slider-handle {

‎packages/main/src/themes/base/SliderBase-parameters.css

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
--_ui5_slider_inner_height: 0.25rem;
66
--_ui5_slider_progress_border_radius: 0.25rem;
77
--_ui5_slider_progress_background: var(--sapActiveColor);
8-
--_ui5_slider_handle_height: 1.25rem;
9-
--_ui5_slider_handle_width: 1.25rem;
8+
--_ui5_slider_handle_height: 1.625rem;
9+
--_ui5_slider_handle_width: 1.625rem;
1010
--_ui5_slider_handle_border: solid 0.125rem var(--sapField_BorderColor);
1111
--_ui5_slider_handle_background: var(--sapButton_Background);
1212
--_ui5_range_slider_handle_background: rgba(var(--sapButton_Background), 0.25);
13-
--_ui5_slider_handle_top: -0.6425rem;
14-
--_ui5_slider_handle_margin_left: -0.8125rem;
13+
--_ui5_slider_handle_top: -0.825rem;
14+
--_ui5_slider_handle_margin_left: -0.9725rem;
1515
--_ui5_slider_handle_hover_background: var(--sapButton_Hover_Background);
1616
--_ui5_slider_handle_hover_border: var(--sapButton_Hover_BorderColor);
1717
--_ui5_range_slider_handle_hover_background: rgba(var(--sapButton_Background), 0.25);
@@ -23,11 +23,11 @@
2323
--_ui5_slider_tooltip_background: var(--sapField_Background);
2424
--_ui5_slider_tooltip_border_radius: var(--sapElement_BorderCornerRadius);
2525
--_ui5_slider_tooltip_border_color: var(--sapField_BorderColor);
26-
--_ui5_slider_tooltip_padding: 0.25rem;
26+
--_ui5_slider_tooltip_padding: 0.4125rem;
2727
--_ui5_slider_tooltip_height: 1rem;
2828
--_ui5_slider_tooltip_box_shadow: none;
2929
--_ui5_slider_tooltip_min_width: 2rem;
30-
--_ui5_slider_tooltip_bottom: 1.825rem;
30+
--_ui5_slider_tooltip_bottom: 2rem;
3131
--_ui5_slider_label_fontsize: var(--sapFontSmallSize);
3232
--_ui5_slider_label_color: var(--sapContent_LabelColor);
3333
}

‎packages/main/src/themes/base/sizes-parameters.css

+9
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@
199199
/* Side Navigation */
200200
--ui5_side_navigation_item_height: 2rem;
201201

202+
/* Slider */
203+
--_ui5_slider_handle_height: 1.25rem;
204+
--_ui5_slider_handle_width: 1.25rem;
205+
--_ui5_slider_handle_top: -0.6425rem;
206+
--_ui5_slider_handle_margin_left: -0.7825rem;
207+
--_ui5_slider_tooltip_height: 1rem;
208+
--_ui5_slider_tooltip_padding: 0.25rem;
209+
--_ui5_slider_tooltip_bottom: 1.825rem;
210+
202211
/* Tree */
203212
--_ui5-tree-indent-step: 0.5rem;
204213
--_ui5-tree-toggle-box-width: 2rem;

‎packages/main/src/themes/sap_belize/SliderBase-parameters.css

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
--_ui5_slider_inner_height: 0.1875rem;
66
--_ui5_slider_progress_border-radius: 0;
77
--_ui5_slider_progress_background: var(--sapField_Active_BorderColor);
8-
--_ui5_slider_handle_height: 1.375rem;
9-
--_ui5_slider_handle_width: 1.375rem;
8+
--_ui5_slider_handle_height: 1.75rem;
9+
--_ui5_slider_handle_width: 1.75rem;
1010
--_ui5_slider_handle_border: solid 0.125rem #999;
1111
--_ui5_slider_handle_background: rgba(var(--sapField_Background), 0.1);
12-
--_ui5_slider_handle_top: -0.725rem;
12+
--_ui5_slider_handle_top: -0.8725rem;
1313
--_ui5_slider_handle_margin_left: -1rem;
1414
--_ui5_slider_handle_hover_background: rgba(217,217,217,0.6);
1515
--_ui5_slider_handle_hover_border: #999;
1616
--_ui5_slider_tickmark_color: #bfbfbf;
1717
--_ui5_slider_disabled_opacity: 0.5;
18-
--_ui5_slider_tooltip_padding: 0.25rem 0.50rem;
19-
--_ui5_slider_tooltip_height: 1.325rem;
18+
--_ui5_slider_tooltip_padding: 0.50rem;
19+
--_ui5_slider_tooltip_height: 1rem;
2020
--_ui5_slider_tooltip_box_shadow: 0 0.625rem 2rem 0 rgba(0, 0, 0, 0.15);
2121
--_ui5_slider_tooltip_border_radius: 0;
2222
}

‎packages/main/test/pages/RangeSlider.html

+20
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,25 @@ <h2>Disabled Range Slider</h2>
5959
<h2 style="text-align: center;">Range Slider with steps, tooltips, tickmarks and labels</h2>
6060
<ui5-range-slider id="range-slider-tickmarks-labels" min="0" max="44" step="2" start-value="2" end-value="12" show-tooltip label-interval="2" show-tickmarks style="width: 60%; margin-left: 20%; margin-top: 50px;"></ui5-range-slider>
6161
</section>
62+
63+
<section class="group">
64+
<h2>Event Testing Slider</h2>
65+
<ui5-range-slider id="test-slider" min="0" max="10" start-value="1" end-value="2"></ui5-range-slider>
66+
<h2>Event Testing Result Slider</h2>
67+
<ui5-range-slider id="test-result-slider" start-value="1" end-value="2"></ui5-range-slider>
68+
</section>
69+
70+
<script>
71+
const eventTargetSlider = document.getElementById("test-slider");
72+
const eventResultSlider = document.getElementById("test-result-slider");
73+
74+
eventTargetSlider.addEventListener("ui5-input", () => {
75+
eventResultSlider.setAttribute("end-value", parseInt(eventResultSlider.getAttribute("end-value")) + 1);
76+
});
77+
78+
eventTargetSlider.addEventListener("ui5-change", () => {
79+
eventResultSlider.setAttribute("end-value", parseInt(eventResultSlider.getAttribute("end-value")) + 1);
80+
});
81+
</script>
6282
</body>
6383
</html>

‎packages/main/test/pages/Slider.html

+20
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,25 @@ <h2 style="text-align: center;">Slider with steps, tooltips, tickmarks and label
6666
<h2>Slider with float number step (1.25), tooltips, tickmarks and labels between 3 steps (3.75 value)</h2>
6767
<ui5-slider id="slider-tickmarks-tooltips-labels" min="-12.5" max="47.5" step="1.25" value="10" show-tooltip label-interval="3" show-tickmarks></ui5-slider>
6868
</section>
69+
70+
<section class="group">
71+
<h2>Event Testing Slider</h2>
72+
<ui5-slider id="test-slider" min="0" max="10"></ui5-slider>
73+
<h2>Event Testing Result Slider</h2>
74+
<ui5-slider id="test-result-slider" value="1"></ui5-slider>
75+
</section>
76+
77+
<script>
78+
const eventTargetSlider = document.getElementById("test-slider");
79+
const eventResultSlider = document.getElementById("test-result-slider");
80+
81+
eventTargetSlider.addEventListener("ui5-input", () => {
82+
eventResultSlider.setAttribute("value", parseInt(eventResultSlider.getAttribute("value")) + 1);
83+
});
84+
85+
eventTargetSlider.addEventListener("ui5-change", () => {
86+
eventResultSlider.setAttribute("value", parseInt(eventResultSlider.getAttribute("value")) + 1);
87+
});
88+
</script>
6989
</body>
7090
</html>

‎packages/main/test/specs/RangeSlider.spec.js

+63
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,30 @@ describe("Properties synchronization and normalization", () => {
170170
assert.strictEqual(rangeSlider.getProperty("step"), 1, "Step value should be its default value");
171171
});
172172

173+
it("If a negative number is set to the step property its positive equivalent should be used as effective value", () => {
174+
const rangeSlider = browser.$("#range-slider-tickmarks-labels");
175+
176+
rangeSlider.setProperty("step", -7);
177+
178+
assert.strictEqual(rangeSlider.getProperty("step"), -7, "Step value should be a positive number");
179+
180+
rangeSlider.click();
181+
182+
assert.strictEqual(rangeSlider.getProperty("endValue"), 21, "The current value should be 'stepified' by 7");
183+
});
184+
185+
it("If min property is set to a greater number than the max property their effective values should be swapped, their real ones - not", () => {
186+
const rangeSlider = browser.$("#range-slider-tickmarks-labels");
187+
188+
rangeSlider.setProperty("startValue", 2);
189+
rangeSlider.setProperty("max", 10);
190+
rangeSlider.setProperty("min", 100);
191+
192+
assert.strictEqual(rangeSlider.getProperty("min"), 100, "min property itself should not be normalized");
193+
assert.strictEqual(rangeSlider.getProperty("max"), 10, "max property itself should not be normalized");
194+
assert.strictEqual(rangeSlider.getProperty("startValue"), 10, "startValue property should be within the boundaries of the effective (swapped) min and max props");
195+
});
196+
173197
it("Should keep the current values between the boundaries of min and max properties", () => {
174198
const rangeSlider = browser.$("#range-slider-tickmarks-labels");
175199

@@ -196,6 +220,45 @@ describe("Properties synchronization and normalization", () => {
196220

197221
assert.strictEqual(rangeSlider.getProperty("startValue"), 14, "startValue should not be stepped to the next step (15)");
198222
assert.strictEqual(rangeSlider.getProperty("endValue"), 24, "endValue should not be stepped to the next step (25)");
223+
});
224+
225+
it("If the step property or the labelInterval are changed, the tickmarks and labels must be updated also", () => {
226+
const rangeSlider = browser.$("#range-slider-tickmarks-labels");
227+
228+
rangeSlider.setProperty("max", 0);
229+
rangeSlider.setProperty("min", 40);
230+
rangeSlider.setProperty("step", 1);
231+
232+
assert.strictEqual(rangeSlider.getProperty("_labels").length, 21, "Labels must be 21 - 1 for every 2 tickmarks (and steps)");
233+
234+
rangeSlider.setProperty("step", 2);
235+
236+
assert.strictEqual(rangeSlider.getProperty("_labels").length, 11, "Labels must be 12 - 1 for every 2 tickmarks (and 4 current value points)");
237+
238+
rangeSlider.setProperty("labelInterval", 4);
239+
240+
assert.strictEqual(rangeSlider.getProperty("_labels").length, 6, "Labels must be 6 - 1 for every 4 tickmarks (and 8 current value points)");
241+
});
242+
});
243+
244+
describe("Testing events", () => {
245+
246+
it("Should fire input event on use interaction and change event after user interaction finish", () => {
247+
const rangeSlider = browser.$("#test-slider");
248+
const eventResultRangeSlider = browser.$("#test-result-slider");
249+
250+
rangeSlider.click();
251+
252+
assert.strictEqual(eventResultRangeSlider.getProperty("endValue") , 4, "Both input event and change event are fired after user interaction");
253+
});
254+
255+
it("Should not fire change event after user interaction is finished if the current value is the same as the one at the start of the action", () => {
256+
const rangeSlider = browser.$("#test-slider");
257+
const eventResultRangeSlider = browser.$("#test-result-slider");
258+
259+
rangeSlider.click();
260+
261+
assert.strictEqual(eventResultRangeSlider.getProperty("endValue") , 4, "Change event is not fired if the value is the same as before the start of the action");
199262
});
200263
});
201264

‎packages/main/test/specs/Slider.spec.js

+86-3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,71 @@ describe("Slider basic interactions", () => {
6363
});
6464
});
6565

66+
describe("Properties synchronization and normalization", () => {
67+
68+
it("If a negative number is set to the step property its positive equivalent should be used as effective value", () => {
69+
const slider = browser.$("#slider-tickmarks-labels");
70+
71+
slider.setProperty("step", -7);
72+
73+
assert.strictEqual(slider.getProperty("step"), -7, "The step property should not be changed itself");
74+
75+
slider.click();
76+
77+
assert.strictEqual(slider.getProperty("value"), 1, "The current value should be 'stepified' by 7");
78+
});
79+
80+
it("If step property is not a valid number its value should fallback to 1", () => {
81+
const slider = browser.$("#slider-tickmarks-labels");
82+
83+
slider.setProperty("step", 2);
84+
slider.setProperty("step", "String value");
85+
slider.click();
86+
87+
assert.strictEqual(slider.getProperty("step"), 1, "Step property should be set to its defaut value");
88+
assert.strictEqual(slider.getProperty("value"), 0, "The current value should be 'stepified' by 1");
89+
});
90+
91+
it("If the step property or the labelInterval are changed, the tickmarks and labels must be updated also", () => {
92+
const slider = browser.$("#slider-tickmarks-labels");
93+
94+
assert.strictEqual(slider.getProperty("_labels").length, 21, "Labels must be 21 - 1 for every 2 tickmarks (and steps)");
95+
96+
slider.setProperty("step", 2);
97+
98+
assert.strictEqual(slider.getProperty("_labels").length, 11, "Labels must be 12 - 1 for every 2 tickmarks (and 4 current value points)");
99+
100+
slider.setProperty("labelInterval", 4);
101+
102+
assert.strictEqual(slider.getProperty("_labels").length, 6, "Labels must be 6 - 1 for every 4 tickmarks (and 8 current value points)");
103+
});
104+
105+
it("If min property is set to a greater number than the max property their effective values should be swapped, their real ones - not", () => {
106+
const slider = browser.$("#basic-slider");
107+
108+
slider.setProperty("value", 2);
109+
slider.setProperty("max", 10);
110+
slider.setProperty("min", 100);
111+
112+
assert.strictEqual(slider.getProperty("max"), 10, "min property itself should not be normalized");
113+
assert.strictEqual(slider.getProperty("min"), 100, "max property itself should not be normalized");
114+
assert.strictEqual(slider.getProperty("value"), 10, "value property should be within the boundaries of the normalized 'effective' min and max values");
115+
});
116+
117+
it("Should keep the current value between the boundaries of min and max properties", () => {
118+
const slider = browser.$("#basic-slider");
119+
120+
slider.setProperty("min", 100);
121+
slider.setProperty("max", 200);
122+
slider.setProperty("value", 300);
123+
124+
assert.strictEqual(slider.getProperty("value"), 200, "value prop should always be lower than the max value");
125+
126+
slider.setProperty("value", 99);
127+
128+
assert.strictEqual(slider.getProperty("value"), 100, "value prop should always be greater than the min value");
129+
});
130+
});
66131

67132
describe("Slider elements - tooltip, step, tickmarks, labels", () => {
68133

@@ -89,9 +154,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => {
89154

90155
assert.strictEqual(numberOfLabels, 17, "17 labels should be rendered, 1 between each 3 tickmarks");
91156
});
92-
});
93157

94-
describe("Properties synchronization and normalization", () => {
95158
it("Should not 'stepify' current value if it is not in result of user interaction", () => {
96159
const slider = browser.$("#tickmarks-slider");
97160

@@ -101,6 +164,27 @@ describe("Properties synchronization and normalization", () => {
101164
});
102165
});
103166

167+
describe("Testing events", () => {
168+
169+
it("Should fire input event on use interaction and change event after user interaction finish", () => {
170+
const slider = browser.$("#test-slider");
171+
const eventResultSlider = browser.$("#test-result-slider");
172+
173+
slider.click();
174+
175+
assert.strictEqual(eventResultSlider.getProperty("value") , 3, "Both input event and change event are fired after user interaction");
176+
});
177+
178+
it("Should not fire change event after user interaction is finished if the current value is the same as the one at the start of the action", () => {
179+
const slider = browser.$("#test-slider");
180+
const eventResultSlider = browser.$("#test-result-slider");
181+
182+
slider.click();
183+
184+
assert.strictEqual(eventResultSlider.getProperty("value") , 3, "Change event is not fired if the value is the same as before the start of the action");
185+
});
186+
});
187+
104188
describe("Testing resize handling and RTL support", () => {
105189
it("Testing RTL support", () => {
106190
const slider = browser.$("#basic-slider");
@@ -118,7 +202,6 @@ describe("Testing resize handling and RTL support", () => {
118202

119203
assert.strictEqual(sliderHandle.getAttribute("style"), "right: 30%;", "Slider handle should be 30% from the right");
120204

121-
slider.moveTo();
122205
slider.click();
123206

124207
assert.strictEqual(sliderHandle.getAttribute("style"), "right: 50%;", "Slider handle should be in the middle of the slider");

0 commit comments

Comments
 (0)