Skip to content

Commit 0df94dd

Browse files
committed
feat(keyboardSupport): Consolidate onStart, onChange and onEnd for keyboard
Handle slideEnded event as well Closes #319
1 parent 5d9c66a commit 0df94dd

File tree

8 files changed

+142
-59
lines changed

8 files changed

+142
-59
lines changed

dist/rzslider.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*! angularjs-slider - v2.14.0 -
22
(c) Rafal Zajac <[email protected]>, Valentin Hervieu <[email protected]>, Jussi Saarivirta <[email protected]>, Angelin Sirbu <[email protected]> -
33
https://github.com/angular-slider/angularjs-slider -
4-
2016-05-22 */
4+
2016-05-25 */
55
rzslider {
66
position: relative;
77
display: inline-block;

dist/rzslider.js

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*! angularjs-slider - v2.14.0 -
22
(c) Rafal Zajac <[email protected]>, Valentin Hervieu <[email protected]>, Jussi Saarivirta <[email protected]>, Angelin Sirbu <[email protected]> -
33
https://github.com/angular-slider/angularjs-slider -
4-
2016-05-22 */
4+
2016-05-25 */
55
/*jslint unparam: true */
66
/*global angular: false, console: false, define, module */
77
(function(root, factory) {
@@ -267,6 +267,13 @@
267267
*/
268268
this.initHasRun = false;
269269

270+
/**
271+
* Used to call onStart on the first keydown event
272+
*
273+
* @type {boolean}
274+
*/
275+
this.firstKeyDown = false
276+
270277
/**
271278
* Internal flag to prevent watchers to be called when the sliders value are modified internally.
272279
* @type {boolean}
@@ -1519,7 +1526,6 @@
15191526
this.dragging.active = false;
15201527

15211528
$document.off(moveEventName, ehMove);
1522-
this.scope.$emit('slideEnded');
15231529
this.callOnEnd();
15241530
},
15251531

@@ -1531,11 +1537,19 @@
15311537
this.tracking = ref;
15321538
pointer.one('blur', angular.bind(this, this.onPointerBlur, pointer));
15331539
pointer.on('keydown', angular.bind(this, this.onKeyboardEvent));
1540+
pointer.on('keyup', angular.bind(this, this.onKeyUp));
1541+
this.firstKeyDown = true;
15341542
pointer.addClass('rz-active');
15351543
},
15361544

1545+
onKeyUp: function() {
1546+
this.firstKeyDown = true;
1547+
this.callOnEnd();
1548+
},
1549+
15371550
onPointerBlur: function(pointer) {
15381551
pointer.off('keydown');
1552+
pointer.off('keyup');
15391553
this.tracking = '';
15401554
pointer.removeClass('rz-active');
15411555
},
@@ -1596,29 +1610,37 @@
15961610
if (action == null || this.tracking === '') return;
15971611
event.preventDefault();
15981612

1599-
var newValue = this.roundStep(this.sanitizeValue(action));
1600-
if (!this.options.draggableRangeOnly) {
1601-
this.positionTrackingHandle(newValue);
1602-
} else {
1603-
var difference = this.scope.rzSliderHigh - this.scope.rzSliderModel,
1604-
newMinValue, newMaxValue;
1605-
if (this.tracking === 'rzSliderModel') {
1606-
newMinValue = newValue;
1607-
newMaxValue = newValue + difference;
1608-
if (newMaxValue > this.maxValue) {
1609-
newMaxValue = this.maxValue;
1610-
newMinValue = newMaxValue - difference;
1611-
}
1613+
if (this.firstKeyDown) {
1614+
this.firstKeyDown = false;
1615+
this.callOnStart();
1616+
}
1617+
1618+
var self = this;
1619+
$timeout(function() {
1620+
var newValue = self.roundStep(self.sanitizeValue(action));
1621+
if (!self.options.draggableRangeOnly) {
1622+
self.positionTrackingHandle(newValue);
16121623
} else {
1613-
newMaxValue = newValue;
1614-
newMinValue = newValue - difference;
1615-
if (newMinValue < this.minValue) {
1616-
newMinValue = this.minValue;
1617-
newMaxValue = newMinValue + difference;
1624+
var difference = self.scope.rzSliderHigh - self.scope.rzSliderModel,
1625+
newMinValue, newMaxValue;
1626+
if (self.tracking === 'rzSliderModel') {
1627+
newMinValue = newValue;
1628+
newMaxValue = newValue + difference;
1629+
if (newMaxValue > self.maxValue) {
1630+
newMaxValue = self.maxValue;
1631+
newMinValue = newMaxValue - difference;
1632+
}
1633+
} else {
1634+
newMaxValue = newValue;
1635+
newMinValue = newValue - difference;
1636+
if (newMinValue < self.minValue) {
1637+
newMinValue = self.minValue;
1638+
newMaxValue = newMinValue + difference;
1639+
}
16181640
}
1641+
self.positionTrackingBar(newMinValue, newMaxValue);
16191642
}
1620-
this.positionTrackingBar(newMinValue, newMaxValue);
1621-
}
1643+
});
16221644
},
16231645

16241646
/**
@@ -1889,6 +1911,7 @@
18891911
self.options.onEnd(self.options.id, self.scope.rzSliderModel, self.scope.rzSliderHigh);
18901912
});
18911913
}
1914+
this.scope.$emit('slideEnded');
18921915
}
18931916
};
18941917

dist/rzslider.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/rzslider.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/rzslider.js

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,13 @@
271271
*/
272272
this.initHasRun = false;
273273

274+
/**
275+
* Used to call onStart on the first keydown event
276+
*
277+
* @type {boolean}
278+
*/
279+
this.firstKeyDown = false
280+
274281
/**
275282
* Internal flag to prevent watchers to be called when the sliders value are modified internally.
276283
* @type {boolean}
@@ -1523,7 +1530,6 @@
15231530
this.dragging.active = false;
15241531

15251532
$document.off(moveEventName, ehMove);
1526-
this.scope.$emit('slideEnded');
15271533
this.callOnEnd();
15281534
},
15291535

@@ -1535,11 +1541,19 @@
15351541
this.tracking = ref;
15361542
pointer.one('blur', angular.bind(this, this.onPointerBlur, pointer));
15371543
pointer.on('keydown', angular.bind(this, this.onKeyboardEvent));
1544+
pointer.on('keyup', angular.bind(this, this.onKeyUp));
1545+
this.firstKeyDown = true;
15381546
pointer.addClass('rz-active');
15391547
},
15401548

1549+
onKeyUp: function() {
1550+
this.firstKeyDown = true;
1551+
this.callOnEnd();
1552+
},
1553+
15411554
onPointerBlur: function(pointer) {
15421555
pointer.off('keydown');
1556+
pointer.off('keyup');
15431557
this.tracking = '';
15441558
pointer.removeClass('rz-active');
15451559
},
@@ -1600,29 +1614,37 @@
16001614
if (action == null || this.tracking === '') return;
16011615
event.preventDefault();
16021616

1603-
var newValue = this.roundStep(this.sanitizeValue(action));
1604-
if (!this.options.draggableRangeOnly) {
1605-
this.positionTrackingHandle(newValue);
1606-
} else {
1607-
var difference = this.scope.rzSliderHigh - this.scope.rzSliderModel,
1608-
newMinValue, newMaxValue;
1609-
if (this.tracking === 'rzSliderModel') {
1610-
newMinValue = newValue;
1611-
newMaxValue = newValue + difference;
1612-
if (newMaxValue > this.maxValue) {
1613-
newMaxValue = this.maxValue;
1614-
newMinValue = newMaxValue - difference;
1615-
}
1617+
if (this.firstKeyDown) {
1618+
this.firstKeyDown = false;
1619+
this.callOnStart();
1620+
}
1621+
1622+
var self = this;
1623+
$timeout(function() {
1624+
var newValue = self.roundStep(self.sanitizeValue(action));
1625+
if (!self.options.draggableRangeOnly) {
1626+
self.positionTrackingHandle(newValue);
16161627
} else {
1617-
newMaxValue = newValue;
1618-
newMinValue = newValue - difference;
1619-
if (newMinValue < this.minValue) {
1620-
newMinValue = this.minValue;
1621-
newMaxValue = newMinValue + difference;
1628+
var difference = self.scope.rzSliderHigh - self.scope.rzSliderModel,
1629+
newMinValue, newMaxValue;
1630+
if (self.tracking === 'rzSliderModel') {
1631+
newMinValue = newValue;
1632+
newMaxValue = newValue + difference;
1633+
if (newMaxValue > self.maxValue) {
1634+
newMaxValue = self.maxValue;
1635+
newMinValue = newMaxValue - difference;
1636+
}
1637+
} else {
1638+
newMaxValue = newValue;
1639+
newMinValue = newValue - difference;
1640+
if (newMinValue < self.minValue) {
1641+
newMinValue = self.minValue;
1642+
newMaxValue = newMinValue + difference;
1643+
}
16221644
}
1645+
self.positionTrackingBar(newMinValue, newMaxValue);
16231646
}
1624-
this.positionTrackingBar(newMinValue, newMaxValue);
1625-
}
1647+
});
16261648
},
16271649

16281650
/**
@@ -1893,6 +1915,7 @@
18931915
self.options.onEnd(self.options.id, self.scope.rzSliderModel, self.scope.rzSliderHigh);
18941916
});
18951917
}
1918+
this.scope.$emit('slideEnded');
18961919
}
18971920
};
18981921

tests/specs/helper.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
var optionsExpression = sliderObj.optionsExpression || 'slider.options';
1515
if (sliderObj.options || sliderObj.optionsExpression)
1616
template = '<rzslider rz-slider-model="slider.value" rz-slider-options="' +
17-
optionsExpression + '"></rzslider>';
17+
optionsExpression + '"></rzslider>';
1818
else
1919
template = '<rzslider rz-slider-model="slider.value"></rzslider>';
2020
h.initSlider(sliderObj, template);
@@ -25,7 +25,7 @@
2525
var optionsExpression = sliderObj.optionsExpression || 'slider.options';
2626
if (sliderObj.options || sliderObj.optionsExpression)
2727
template = '<rzslider rz-slider-model="slider.min" rz-slider-high="slider.max"' +
28-
'rz-slider-options="' + optionsExpression + '"></rzslider>';
28+
'rz-slider-options="' + optionsExpression + '"></rzslider>';
2929
else
3030
template = '<rzslider rz-slider-model="slider.min" rz-slider-high="slider.max"></rzslider>';
3131
h.initSlider(sliderObj, template);
@@ -82,7 +82,8 @@
8282
$document.triggerHandler(event);
8383
};
8484

85-
h.pressKeydown = function(element, key, oldAPI) {
85+
h.pressKeydown = function(element, key, options) {
86+
options = options || {};
8687
key = key.toUpperCase();
8788
var event = {
8889
type: 'keydown'
@@ -99,10 +100,12 @@
99100
'SPACE': 32
100101
};
101102
var keyCode = keys[key];
102-
if (oldAPI)
103+
if (options.oldAPI)
103104
event.which = keyCode;
104105
else event.keyCode = keyCode;
105106
element.triggerHandler(event);
107+
if (options.timeout !== false)
108+
$timeout.flush();
106109
};
107110

108111
return h;

tests/specs/keyboard-controls/range-slider-test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@
136136
helper.pressKeydown(helper.slider.minH, 'RIGHT');
137137
expect(helper.scope.slider.min).to.equal(51);
138138
helper.slider.minH.triggerHandler('blur');
139-
helper.pressKeydown(helper.slider.minH, 'RIGHT');
139+
helper.pressKeydown(helper.slider.minH, 'RIGHT', {timeout: false});
140140
expect(helper.scope.slider.min).to.equal(51);
141141
});
142142

@@ -145,7 +145,7 @@
145145
helper.pressKeydown(helper.slider.maxH, 'RIGHT');
146146
expect(helper.scope.slider.max).to.equal(101);
147147
helper.slider.maxH.triggerHandler('blur');
148-
helper.pressKeydown(helper.slider.maxH, 'RIGHT');
148+
helper.pressKeydown(helper.slider.maxH, 'RIGHT', {timeout: false});
149149
expect(helper.scope.slider.max).to.equal(101);
150150
});
151151
});
@@ -273,7 +273,7 @@
273273
helper.pressKeydown(helper.slider.minH, 'RIGHT');
274274
expect(helper.scope.slider.min).to.equal(49);
275275
helper.slider.minH.triggerHandler('blur');
276-
helper.pressKeydown(helper.slider.minH, 'RIGHT');
276+
helper.pressKeydown(helper.slider.minH, 'RIGHT', {timeout: false});
277277
expect(helper.scope.slider.min).to.equal(49);
278278
});
279279

@@ -282,7 +282,7 @@
282282
helper.pressKeydown(helper.slider.maxH, 'RIGHT');
283283
expect(helper.scope.slider.max).to.equal(99);
284284
helper.slider.maxH.triggerHandler('blur');
285-
helper.pressKeydown(helper.slider.maxH, 'RIGHT');
285+
helper.pressKeydown(helper.slider.maxH, 'RIGHT', {timeout: false});
286286
expect(helper.scope.slider.max).to.equal(99);
287287
});
288288

tests/specs/keyboard-controls/single-slider-test.js

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,46 @@
2525
value: 100,
2626
options: {
2727
floor: 0,
28-
ceil: 200
28+
ceil: 200,
29+
onStart: sinon.spy(),
30+
onChange: sinon.spy(),
31+
onEnd: sinon.spy()
2932
}
3033
};
3134
helper.createSlider(sliderConf);
3235
});
3336

37+
it('should call onStart on the first keydown but not after', function() {
38+
helper.slider.minH.triggerHandler('focus');
39+
helper.pressKeydown(helper.slider.minH, 'RIGHT');
40+
helper.scope.slider.options.onStart.callCount === 1;
41+
helper.pressKeydown(helper.slider.minH, 'RIGHT');
42+
helper.scope.slider.options.onStart.callCount === 1;
43+
});
44+
45+
it('should call onChange on each keydown but after a timeout', function() {
46+
helper.slider.minH.triggerHandler('focus');
47+
helper.pressKeydown(helper.slider.minH, 'RIGHT', {timeout: false});
48+
$timeout.flush();
49+
helper.scope.slider.options.onChange.callCount === 1;
50+
helper.pressKeydown(helper.slider.minH, 'RIGHT', {timeout: false});
51+
$timeout.flush();
52+
helper.scope.slider.options.onChange.callCount === 1;
53+
});
54+
55+
it('should call onEnd on keyup and recall onStart if key is down again', function() {
56+
helper.slider.minH.triggerHandler('focus');
57+
helper.pressKeydown(helper.slider.minH, 'RIGHT');
58+
helper.slider.minH.triggerHandler({type: 'keyup'});
59+
helper.scope.slider.options.onStart.callCount === 1;
60+
helper.scope.slider.options.onEnd.callCount === 1;
61+
62+
helper.pressKeydown(helper.slider.minH, 'RIGHT');
63+
helper.slider.minH.triggerHandler({type: 'keyup'});
64+
helper.scope.slider.options.onStart.callCount === 2;
65+
helper.scope.slider.options.onEnd.callCount === 2;
66+
});
67+
3468
it('should toggle active style when handle focused/blured', function() {
3569
helper.slider.minH.triggerHandler('focus');
3670
expect(helper.slider.minH.hasClass('rz-active')).to.be.true;
@@ -46,7 +80,7 @@
4680

4781
it('should increment by 1 when RIGHT is pressed with oldAPI', function() {
4882
helper.slider.minH.triggerHandler('focus');
49-
helper.pressKeydown(helper.slider.minH, 'RIGHT', true);
83+
helper.pressKeydown(helper.slider.minH, 'RIGHT', {oldAPI: true});
5084
expect(helper.scope.slider.value).to.equal(101);
5185
});
5286

@@ -103,7 +137,7 @@
103137
helper.pressKeydown(helper.slider.minH, 'RIGHT');
104138
expect(helper.scope.slider.value).to.equal(101);
105139
helper.slider.minH.triggerHandler('blur');
106-
helper.pressKeydown(helper.slider.minH, 'RIGHT');
140+
helper.pressKeydown(helper.slider.minH, 'RIGHT', {timeout: false});
107141
expect(helper.scope.slider.value).to.equal(101);
108142
});
109143
});
@@ -211,7 +245,7 @@
211245
helper.pressKeydown(helper.slider.minH, 'RIGHT');
212246
expect(helper.scope.slider.value).to.equal(99);
213247
helper.slider.minH.triggerHandler('blur');
214-
helper.pressKeydown(helper.slider.minH, 'RIGHT');
248+
helper.pressKeydown(helper.slider.minH, 'RIGHT', {timeout: false});
215249
expect(helper.scope.slider.value).to.equal(99);
216250
});
217251
});

0 commit comments

Comments
 (0)