Skip to content

Commit 91705ef

Browse files
DadUndeadValentinH
authored andcommitted
Added reversedControls option to reverse keyboard navigation. (#567)
1 parent f8fd4b6 commit 91705ef

File tree

10 files changed

+402
-14
lines changed

10 files changed

+402
-14
lines changed

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ The default options are:
244244
onChange: null,
245245
onEnd: null,
246246
rightToLeft: false,
247+
reversedControls: false,
247248
boundPointerLabels: true,
248249
mergeRangeLabelsIfSame: false,
249250
customTemplateScope: null,
@@ -399,6 +400,14 @@ _Changing this value at runtime is not currently supported._
399400
- Home: minimum value
400401
- End: maximum value
401402

403+
**reversedControls** - _Boolean (defaults to false)_: Set to true to reverse keyboard navigation:
404+
- Right/top arrows: -1
405+
- Left/bottom arrows: +1
406+
- Page-up: -10%
407+
- Page-down: +10%
408+
- End: minimum value
409+
- Home: maximum value
410+
402411
**customTemplateScope** - _Object (default to null)_: The properties defined in this object will be exposed in the slider template under `custom.X`.
403412

404413
**logScale** - _Boolean (defaults to false)_: Set to true to use a logarithmic scale to display the slider.

demo/index.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,8 @@ <h2>Slider with all options demo</h2>
420420
<label>Show ticks values <input type="checkbox" ng-model="slider_all_options.options.showTicksValues"></label><br/>
421421
<label>Disabled <input type="checkbox" ng-model="slider_all_options.options.disabled"></label><br/>
422422
<label>Read-Only <input type="checkbox" ng-model="slider_all_options.options.readOnly"></label><br />
423-
<label>Right to Left <input type="checkbox" ng-model="slider_all_options.options.rightToLeft"></label>
423+
<label>Right to Left <input type="checkbox" ng-model="slider_all_options.options.rightToLeft"></label><br />
424+
<label>Reversed Controls <input type="checkbox" ng-model="slider_all_options.options.reversedControls"></label>
424425
</div>
425426
</div>
426427
<rzslider

dist/rzslider.css

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/rzslider.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*! angularjs-slider - v6.4.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-
2017-08-18 */
4+
2017-09-07 */
55
/*jslint unparam: true */
66
/*global angular: false, console: false, define, module */
77
;(function(root, factory) {
@@ -75,6 +75,7 @@
7575
onChange: null,
7676
onEnd: null,
7777
rightToLeft: false,
78+
reversedControls: false,
7879
boundPointerLabels: true,
7980
mergeRangeLabelsIfSame: false,
8081
customTemplateScope: null,
@@ -2111,6 +2112,13 @@
21112112
increasePage = currentValue + this.valueRange / 10,
21122113
decreasePage = currentValue - this.valueRange / 10
21132114

2115+
if (this.options.reversedControls){
2116+
increaseStep = currentValue - this.step
2117+
decreaseStep = currentValue + this.step
2118+
increasePage = currentValue - this.valueRange / 10
2119+
decreasePage = currentValue + this.valueRange / 10
2120+
}
2121+
21142122
//Left to right default actions
21152123
var actions = {
21162124
UP: increaseStep,
@@ -2119,8 +2127,8 @@
21192127
RIGHT: increaseStep,
21202128
PAGEUP: increasePage,
21212129
PAGEDOWN: decreasePage,
2122-
HOME: this.minValue,
2123-
END: this.maxValue
2130+
HOME: this.options.reversedControls ? this.maxValue : this.minValue,
2131+
END: this.options.reversedControls ? this.minValue : this.maxValue
21242132
}
21252133
//right to left means swapping right and left arrows
21262134
if (this.options.rightToLeft) {

dist/rzslider.min.css

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/rzslider.min.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/rzslider.scss

+2-2
Large diffs are not rendered by default.

src/rzslider.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
onChange: null,
8080
onEnd: null,
8181
rightToLeft: false,
82+
reversedControls: false,
8283
boundPointerLabels: true,
8384
mergeRangeLabelsIfSame: false,
8485
customTemplateScope: null,
@@ -2115,6 +2116,13 @@
21152116
increasePage = currentValue + this.valueRange / 10,
21162117
decreasePage = currentValue - this.valueRange / 10
21172118

2119+
if (this.options.reversedControls) {
2120+
increaseStep = currentValue - this.step
2121+
decreaseStep = currentValue + this.step
2122+
increasePage = currentValue - this.valueRange / 10
2123+
decreasePage = currentValue + this.valueRange / 10
2124+
}
2125+
21182126
//Left to right default actions
21192127
var actions = {
21202128
UP: increaseStep,
@@ -2123,8 +2131,8 @@
21232131
RIGHT: increaseStep,
21242132
PAGEUP: increasePage,
21252133
PAGEDOWN: decreasePage,
2126-
HOME: this.minValue,
2127-
END: this.maxValue
2134+
HOME: this.options.reversedControls ? this.maxValue : this.minValue,
2135+
END: this.options.reversedControls ? this.minValue : this.maxValue
21282136
}
21292137
//right to left means swapping right and left arrows
21302138
if (this.options.rightToLeft) {

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

+249
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,253 @@
247247
expect(helper.scope.slider.value).to.equal(99)
248248
})
249249
})
250+
251+
describe('Keyboard controls - single slider with reversed controls flag', function() {
252+
var helper, RzSliderOptions, $rootScope, $timeout
253+
254+
beforeEach(module('test-helper'))
255+
256+
beforeEach(
257+
inject(function(TestHelper, _RzSliderOptions_, _$rootScope_, _$timeout_) {
258+
helper = TestHelper
259+
RzSliderOptions = _RzSliderOptions_
260+
$rootScope = _$rootScope_
261+
$timeout = _$timeout_
262+
})
263+
)
264+
265+
afterEach(function() {
266+
helper.clean()
267+
})
268+
269+
beforeEach(function() {
270+
var sliderConf = {
271+
value: 100,
272+
options: {
273+
floor: 0,
274+
ceil: 200,
275+
onStart: sinon.spy(),
276+
onChange: sinon.spy(),
277+
onEnd: sinon.spy(),
278+
reversedControls: true
279+
}
280+
}
281+
helper.createSlider(sliderConf)
282+
})
283+
284+
it('should call onStart on the first keydown but not after', function() {
285+
helper.slider.minH.triggerHandler('focus')
286+
helper.pressKeydown(helper.slider.minH, 'LEFT')
287+
helper.scope.slider.options.onStart.callCount === 1
288+
helper.pressKeydown(helper.slider.minH, 'LEFT')
289+
helper.scope.slider.options.onStart.callCount === 1
290+
})
291+
292+
it('should call onChange on each keydown but after a timeout', function() {
293+
helper.slider.minH.triggerHandler('focus')
294+
helper.pressKeydown(helper.slider.minH, 'LEFT', { timeout: false })
295+
$timeout.flush()
296+
helper.scope.slider.options.onChange.callCount === 1
297+
helper.pressKeydown(helper.slider.minH, 'LEFT', { timeout: false })
298+
$timeout.flush()
299+
helper.scope.slider.options.onChange.callCount === 1
300+
})
301+
302+
it('should call onEnd on keyup and recall onStart if key is down again', function() {
303+
helper.slider.minH.triggerHandler('focus')
304+
helper.pressKeydown(helper.slider.minH, 'LEFT')
305+
helper.slider.minH.triggerHandler({ type: 'keyup' })
306+
helper.scope.slider.options.onStart.callCount === 1
307+
helper.scope.slider.options.onEnd.callCount === 1
308+
309+
helper.pressKeydown(helper.slider.minH, 'LEFT')
310+
helper.slider.minH.triggerHandler({ type: 'keyup' })
311+
helper.scope.slider.options.onStart.callCount === 2
312+
helper.scope.slider.options.onEnd.callCount === 2
313+
})
314+
315+
it('should toggle active style when handle focused/blured', function() {
316+
helper.slider.minH.triggerHandler('focus')
317+
expect(helper.slider.minH.hasClass('rz-active')).to.be.true
318+
helper.slider.minH.triggerHandler('blur')
319+
expect(helper.slider.minH.hasClass('rz-active')).to.be.false
320+
})
321+
322+
it('should increment by 1 when RIGHT is pressed', function() {
323+
helper.slider.minH.triggerHandler('focus')
324+
helper.pressKeydown(helper.slider.minH, 'LEFT')
325+
expect(helper.scope.slider.value).to.equal(101)
326+
})
327+
328+
it('should increment by 1 when LEFT is pressed with oldAPI', function() {
329+
helper.slider.minH.triggerHandler('focus')
330+
helper.pressKeydown(helper.slider.minH, 'LEFT', { oldAPI: true })
331+
expect(helper.scope.slider.value).to.equal(101)
332+
})
333+
334+
it('should decrement by 1 when RIGHT is pressed', function() {
335+
helper.slider.minH.triggerHandler('focus')
336+
helper.pressKeydown(helper.slider.minH, 'RIGHT')
337+
expect(helper.scope.slider.value).to.equal(99)
338+
})
339+
340+
it('should increment by 1 when DOWN is pressed', function() {
341+
helper.slider.minH.triggerHandler('focus')
342+
helper.pressKeydown(helper.slider.minH, 'DOWN')
343+
expect(helper.scope.slider.value).to.equal(101)
344+
})
345+
346+
it('should decrement by 1 when UP is pressed', function() {
347+
helper.slider.minH.triggerHandler('focus')
348+
helper.pressKeydown(helper.slider.minH, 'UP')
349+
expect(helper.scope.slider.value).to.equal(99)
350+
})
351+
352+
it('should increment by 10% when PAGEDOWN is pressed', function() {
353+
helper.slider.minH.triggerHandler('focus')
354+
helper.pressKeydown(helper.slider.minH, 'PAGEDOWN')
355+
expect(helper.scope.slider.value).to.equal(120)
356+
})
357+
358+
it('should decrement by 10% when PAGEUP is pressed', function() {
359+
helper.slider.minH.triggerHandler('focus')
360+
helper.pressKeydown(helper.slider.minH, 'PAGEUP')
361+
expect(helper.scope.slider.value).to.equal(80)
362+
})
363+
364+
it('should set value to min when END is pressed', function() {
365+
helper.slider.minH.triggerHandler('focus')
366+
helper.pressKeydown(helper.slider.minH, 'END')
367+
expect(helper.scope.slider.value).to.equal(0)
368+
})
369+
370+
it('should set value to max when HOME is pressed', function() {
371+
helper.slider.minH.triggerHandler('focus')
372+
helper.pressKeydown(helper.slider.minH, 'HOME')
373+
expect(helper.scope.slider.value).to.equal(200)
374+
})
375+
376+
it('should do nothing when SPACE is pressed', function() {
377+
helper.slider.minH.triggerHandler('focus')
378+
helper.pressKeydown(helper.slider.minH, 'SPACE')
379+
expect(helper.scope.slider.value).to.equal(100)
380+
})
381+
382+
it('should not modify when keypress but not focused', function() {
383+
helper.slider.minH.triggerHandler('focus')
384+
helper.pressKeydown(helper.slider.minH, 'LEFT')
385+
expect(helper.scope.slider.value).to.equal(101)
386+
helper.slider.minH.triggerHandler('blur')
387+
helper.pressKeydown(helper.slider.minH, 'LEFT', { timeout: false })
388+
expect(helper.scope.slider.value).to.equal(101)
389+
})
390+
})
391+
392+
describe('Right to left Keyboard controls - single slider with reversed controls flag', function() {
393+
var helper, RzSliderOptions, $rootScope, $timeout
394+
395+
beforeEach(module('test-helper'))
396+
397+
beforeEach(
398+
inject(function(TestHelper, _RzSliderOptions_, _$rootScope_, _$timeout_) {
399+
helper = TestHelper
400+
RzSliderOptions = _RzSliderOptions_
401+
$rootScope = _$rootScope_
402+
$timeout = _$timeout_
403+
})
404+
)
405+
406+
afterEach(function() {
407+
helper.clean()
408+
})
409+
410+
beforeEach(function() {
411+
var sliderConf = {
412+
value: 100,
413+
options: {
414+
floor: 0,
415+
ceil: 200,
416+
rightToLeft: true,
417+
reversedControls: true
418+
}
419+
}
420+
helper.createSlider(sliderConf)
421+
})
422+
423+
it('should toggle active style when handle focused/blured', function() {
424+
helper.slider.minH.triggerHandler('focus')
425+
expect(helper.slider.minH.hasClass('rz-active')).to.be.true
426+
helper.slider.minH.triggerHandler('blur')
427+
expect(helper.slider.minH.hasClass('rz-active')).to.be.false
428+
})
429+
430+
it('should decrement by 1 when LEFT is pressed', function() {
431+
helper.slider.minH.triggerHandler('focus')
432+
helper.pressKeydown(helper.slider.minH, 'LEFT')
433+
expect(helper.scope.slider.value).to.equal(99)
434+
})
435+
436+
it('should decrement by 1 when LEFT is pressed with oldAPI', function() {
437+
helper.slider.minH.triggerHandler('focus')
438+
helper.pressKeydown(helper.slider.minH, 'LEFT', true)
439+
expect(helper.scope.slider.value).to.equal(99)
440+
})
441+
442+
it('should increment by 1 when RIGHT is pressed', function() {
443+
helper.slider.minH.triggerHandler('focus')
444+
helper.pressKeydown(helper.slider.minH, 'RIGHT')
445+
expect(helper.scope.slider.value).to.equal(101)
446+
})
447+
448+
it('should increment by 1 when DOWN is pressed', function() {
449+
helper.slider.minH.triggerHandler('focus')
450+
helper.pressKeydown(helper.slider.minH, 'DOWN')
451+
expect(helper.scope.slider.value).to.equal(101)
452+
})
453+
454+
it('should decrement by 1 when UP is pressed', function() {
455+
helper.slider.minH.triggerHandler('focus')
456+
helper.pressKeydown(helper.slider.minH, 'UP')
457+
expect(helper.scope.slider.value).to.equal(99)
458+
})
459+
460+
it('should increment by 10% when PAGEDOWN is pressed', function() {
461+
helper.slider.minH.triggerHandler('focus')
462+
helper.pressKeydown(helper.slider.minH, 'PAGEDOWN')
463+
expect(helper.scope.slider.value).to.equal(120)
464+
})
465+
466+
it('should decrement by 10% when PAGEUP is pressed', function() {
467+
helper.slider.minH.triggerHandler('focus')
468+
helper.pressKeydown(helper.slider.minH, 'PAGEUP')
469+
expect(helper.scope.slider.value).to.equal(80)
470+
})
471+
472+
it('should set value to min when END is pressed', function() {
473+
helper.slider.minH.triggerHandler('focus')
474+
helper.pressKeydown(helper.slider.minH, 'END')
475+
expect(helper.scope.slider.value).to.equal(0)
476+
})
477+
478+
it('should set value to max when HOME is pressed', function() {
479+
helper.slider.minH.triggerHandler('focus')
480+
helper.pressKeydown(helper.slider.minH, 'HOME')
481+
expect(helper.scope.slider.value).to.equal(200)
482+
})
483+
484+
it('should do nothing when SPACE is pressed', function() {
485+
helper.slider.minH.triggerHandler('focus')
486+
helper.pressKeydown(helper.slider.minH, 'SPACE')
487+
expect(helper.scope.slider.value).to.equal(100)
488+
})
489+
490+
it('should not modify when keypress but not focused', function() {
491+
helper.slider.minH.triggerHandler('focus')
492+
helper.pressKeydown(helper.slider.minH, 'LEFT')
493+
expect(helper.scope.slider.value).to.equal(99)
494+
helper.slider.minH.triggerHandler('blur')
495+
helper.pressKeydown(helper.slider.minH, 'LEFT', { timeout: false })
496+
expect(helper.scope.slider.value).to.equal(99)
497+
})
498+
})
250499
})()

0 commit comments

Comments
 (0)