Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit e85e1b9

Browse files
sooooootThomasBurleson
authored andcommitted
feat(slider): md-invert
md-invert: make min value to top/right and max value to bottom/left Closes #7666 Closes #7667
1 parent a55faa0 commit e85e1b9

File tree

5 files changed

+288
-6
lines changed

5 files changed

+288
-6
lines changed

src/components/slider/demoBasicUsage/index.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ <h3>
3333
</md-input-container>
3434
</md-slider-container>
3535

36+
<div style="margin-top: 50px;"></div>
37+
3638
<h3>Rating: {{rating}}/5 - demo of theming classes</h3>
3739
<div layout>
3840
<div flex="10" layout layout-align="center center">
@@ -56,6 +58,8 @@ <h3>Rating: {{rating}}/5 - demo of theming classes</h3>
5658
</md-slider>
5759
</div>
5860

61+
<div style="margin-top: 50px;"></div>
62+
5963
<h3>Disabled</h3>
6064
<md-slider-container ng-disabled="isDisabled">
6165
<md-icon md-svg-icon="device:brightness-low"></md-icon>
@@ -68,9 +72,35 @@ <h3>Disabled</h3>
6872
<md-checkbox ng-model="isDisabled">Is disabled</md-checkbox>
6973
<md-slider ng-model="disabled2" ng-disabled="true" aria-label="Disabled 2"></md-slider>
7074

75+
<div style="margin-top: 50px;"></div>
76+
7177
<h3>Disabled, Discrete, Read Only</h3>
7278
<md-slider ng-model="disabled2" ng-disabled="true" step="3" md-discrete min="0" max="10" aria-label="Disabled discrete 2"></md-slider>
7379
<md-slider ng-model="disabled3" ng-disabled="true" step="10" md-discrete aria-label="Disabled discrete 3" ng-readonly="readonly"></md-slider>
7480
<md-checkbox ng-model="readonly">Read only</md-checkbox>
81+
82+
<div style="margin-top: 50px;"></div>
83+
<h3>Invert</h3>
84+
<md-slider-container>
85+
<div flex="10" layout layout-align="center center">
86+
<span class="md-body-1">Regular</span>
87+
</div>
88+
<md-slider ng-model="invert" min="0" max="100" aria-label="regular slider"></md-slider>
89+
90+
<md-input-container>
91+
<input flex type="number" ng-model="invert" aria-label="regular-slider">
92+
</md-input-container>
93+
</md-slider-container>
94+
<md-slider-container>
95+
<div flex="10" layout layout-align="center center">
96+
<span class="md-body-1">Invert</span>
97+
</div>
98+
<md-slider md-invert ng-model="invert" min="0" max="100" aria-label="invertd slider"></md-slider>
99+
100+
<md-input-container>
101+
<input flex type="number" ng-model="invert" aria-label="invert-slider">
102+
</md-input-container>
103+
</md-slider-container>
104+
75105
</md-content>
76106
</div>

src/components/slider/demoBasicUsage/script.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ angular.module('sliderDemo1', ['ngMaterial'])
2020
$scope.disabled2 = 0;
2121
$scope.disabled3 = 70;
2222

23+
$scope.invert = Math.floor(Math.random() * 100);
24+
2325
$scope.isDisabled = true;
2426
});

src/components/slider/slider.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,14 @@ function SliderContainerDirective() {
120120
* <md-slider md-discrete ng-model="myDiscreteValue" step="10" min="10" max="130">
121121
* </md-slider>
122122
* </hljs>
123+
* <h4>Invert Mode</h4>
124+
* <hljs lang="html">
125+
* <md-slider md-invert ng-model="myValue" step="10" min="10" max="130">
126+
* </md-slider>
127+
* </hljs>
123128
*
124129
* @param {boolean=} md-discrete Whether to enable discrete mode.
130+
* @param {boolean=} md-invert Whether to enable invert mode.
125131
* @param {number=} step The distance between values the user is allowed to pick. Default 1.
126132
* @param {number=} min The minimum value the user is allowed to pick. Default 0.
127133
* @param {number=} max The maximum value the user is allowed to pick. Default 100.
@@ -206,6 +212,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
206212
var DEFAULT_ROUND = 3;
207213
var vertical = angular.isDefined(attr.mdVertical);
208214
var discrete = angular.isDefined(attr.mdDiscrete);
215+
var invert = angular.isDefined(attr.mdInvert);
209216
angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(0);
210217
angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(100);
211218
angular.isDefined(attr.step)? attr.$observe('step', updateStep) : updateStep(1);
@@ -360,6 +367,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
360367
} else if (vertical ? ev.keyCode === $mdConstant.KEY_CODE.UP_ARROW : ev.keyCode === $mdConstant.KEY_CODE.RIGHT_ARROW) {
361368
changeAmount = step;
362369
}
370+
changeAmount = invert ? -changeAmount : changeAmount;
363371
if (changeAmount) {
364372
if (ev.metaKey || ev.ctrlKey || ev.altKey) {
365373
changeAmount *= 4;
@@ -408,7 +416,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
408416

409417
ngModelCtrl.$viewValue = minMaxValidator(ngModelCtrl.$viewValue);
410418

411-
var percent = (ngModelCtrl.$viewValue - min) / (max - min);
419+
var percent = valueToPercent(ngModelCtrl.$viewValue);
412420
scope.modelValue = ngModelCtrl.$viewValue;
413421
element.attr('aria-valuenow', ngModelCtrl.$viewValue);
414422
setSliderPercent(percent);
@@ -447,12 +455,14 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
447455
percent = clamp(percent);
448456

449457
var thumbPosition = (percent * 100) + '%';
458+
var activeTrackPercent = invert ? (1 - percent) * 100 + '%' : thumbPosition;
450459

451460
thumbContainer.css(vertical ? 'bottom' : 'left', thumbPosition);
452-
activeTrack.css(vertical ? 'height' : 'width', thumbPosition);
461+
462+
activeTrack.css(vertical ? 'height' : 'width', activeTrackPercent);
453463

454-
element.toggleClass('_md-min', percent === 0);
455-
element.toggleClass('_md-max', percent === 1);
464+
element.toggleClass((invert ? '_md-max' : '_md-min'), percent === 0);
465+
element.toggleClass((invert ? '_md-min' : '_md-max'), percent === 1);
456466
}
457467

458468
/**
@@ -562,11 +572,13 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
562572
* @returns {*}
563573
*/
564574
function percentToValue( percent ) {
565-
return (min + percent * (max - min));
575+
var adjustedPercent = invert ? (1 - percent) : percent;
576+
return (min + adjustedPercent * (max - min));
566577
}
567578

568579
function valueToPercent( val ) {
569-
return (val - min)/(max - min);
580+
var percent = (val - min) / (max - min);
581+
return invert ? (1 - percent) : percent;
570582
}
571583
}
572584
}

src/components/slider/slider.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,18 @@ md-slider {
425425
}
426426
}
427427
}
428+
&[md-invert] {
429+
&:not([md-vertical]) ._md-track-fill {
430+
left: auto;
431+
right: 0;
432+
}
433+
&[md-vertical] {
434+
._md-track-fill {
435+
bottom: auto;
436+
top: 0;
437+
}
438+
}
439+
}
428440
}
429441

430442
md-slider-container {

src/components/slider/slider.spec.js

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,232 @@ describe('md-slider', function() {
553553
}));
554554

555555
});
556+
557+
describe('invert', function () {
558+
it('should set model on press', function() {
559+
var slider = setup('md-vertical md-invert ng-model="value" min="0" max="100"');
560+
pageScope.$apply('value = 50');
561+
562+
var wrapper = getWrapper(slider);
563+
564+
wrapper.triggerHandler({type: '$md.pressdown', pointer: { y: 70 }});
565+
wrapper.triggerHandler({type: '$md.dragstart', pointer: { y: 70 }});
566+
$timeout.flush();
567+
expect(pageScope.value).toBe(70);
568+
569+
// When going past max, it should clamp to max.
570+
wrapper.triggerHandler({type: '$md.drag', pointer: { y: 0 }});
571+
$timeout.flush();
572+
expect(pageScope.value).toBe(0);
573+
574+
wrapper.triggerHandler({type: '$md.drag', pointer: { y: 50 }});
575+
$timeout.flush();
576+
expect(pageScope.value).toBe(50);
577+
});
578+
579+
it('should decrement model on up arrow', function() {
580+
var slider = setup('md-vertical md-invert min="100" max="104" step="2" ng-model="model"');
581+
pageScope.$apply('model = 104');
582+
583+
var wrapper = getWrapper(slider);
584+
585+
wrapper.triggerHandler({
586+
type: 'keydown',
587+
keyCode: $mdConstant.KEY_CODE.UP_ARROW
588+
});
589+
$timeout.flush();
590+
expect(pageScope.model).toBe(102);
591+
592+
wrapper.triggerHandler({
593+
type: 'keydown',
594+
keyCode: $mdConstant.KEY_CODE.UP_ARROW
595+
});
596+
$timeout.flush();
597+
expect(pageScope.model).toBe(100);
598+
599+
// Stays at min.
600+
wrapper.triggerHandler({
601+
type: 'keydown',
602+
keyCode: $mdConstant.KEY_CODE.UP_ARROW
603+
});
604+
$timeout.flush();
605+
expect(pageScope.model).toBe(100);
606+
607+
});
608+
609+
it('should increment model on down arrow', function() {
610+
var slider = setup('md-vertical md-invert min="100" max="104" step="2" ng-model="model"');
611+
pageScope.$apply('model = 100');
612+
613+
var wrapper = getWrapper(slider);
614+
615+
wrapper.triggerHandler({
616+
type: 'keydown',
617+
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
618+
});
619+
$timeout.flush();
620+
expect(pageScope.model).toBe(102);
621+
622+
wrapper.triggerHandler({
623+
type: 'keydown',
624+
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
625+
});
626+
$timeout.flush();
627+
expect(pageScope.model).toBe(104);
628+
629+
// Stays at max.
630+
wrapper.triggerHandler({
631+
type: 'keydown',
632+
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
633+
});
634+
$timeout.flush();
635+
expect(pageScope.model).toBe(104);
636+
});
637+
638+
it('should update the thumb text', function() {
639+
var slider = setup('md-vertical md-invert ng-model="value" md-discrete min="0" max="100" step="1"');
640+
var wrapper = getWrapper(slider);
641+
642+
pageScope.$apply('value = 30');
643+
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('30');
644+
645+
wrapper.triggerHandler({
646+
type: 'keydown',
647+
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
648+
});
649+
$timeout.flush();
650+
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('31');
651+
652+
wrapper.triggerHandler({type: '$md.pressdown', pointer: { y: 70 }});
653+
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('70');
654+
655+
wrapper.triggerHandler({type: '$md.dragstart', pointer: { y: 93 }});
656+
wrapper.triggerHandler({type: '$md.drag', pointer: { y: 93 }});
657+
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('93');
658+
});
659+
660+
it('should add _md-min class only when at min value', function() {
661+
var slider = setup('md-vertical md-invert ng-model="model" min="0" max="30"');
662+
var wrapper = getWrapper(slider);
663+
664+
pageScope.$apply('model = 0');
665+
expect(slider).toHaveClass('_md-min');
666+
667+
wrapper.triggerHandler({type: '$md.dragstart', pointer: {y: 0}});
668+
wrapper.triggerHandler({type: '$md.drag', pointer: {y: 10}});
669+
$timeout.flush();
670+
expect(slider).not.toHaveClass('_md-min');
671+
});
672+
673+
it('should add _md-max class only when at max value', function() {
674+
var slider = setup('md-vertical md-invert ng-model="model" min="0" max="30"');
675+
var wrapper = getWrapper(slider);
676+
677+
pageScope.$apply('model = 30');
678+
expect(slider).toHaveClass('_md-max');
679+
680+
wrapper.triggerHandler({type: '$md.dragstart', pointer: {y: 30}});
681+
wrapper.triggerHandler({type: '$md.drag', pointer: {y: 10}});
682+
$timeout.flush();
683+
expect(slider).not.toHaveClass('_md-max');
684+
});
685+
686+
it('should increment at a predictable step', function() {
687+
688+
buildSlider(0.1, 0, 1).drag({y:30});
689+
expect(pageScope.value).toBe(0.3);
690+
691+
buildSlider(0.25, 0, 1).drag({y:45});
692+
expect(pageScope.value).toBe(0.5);
693+
694+
buildSlider(0.25, 0, 1).drag({y:75});
695+
expect(pageScope.value).toBe(0.75);
696+
697+
buildSlider(1, 0, 100).drag({y:10});
698+
expect(pageScope.value).toBe(10);
699+
700+
buildSlider(20, 5, 45).drag({y:50});
701+
expect(pageScope.value).toBe(25);
702+
703+
function buildSlider(step, min, max) {
704+
var slider = setup('md-vertical md-invert ng-model="value" min="' + min + '" max="' + max + '" step="' + step + '"');
705+
pageScope.$apply('value = 0.5');
706+
707+
var wrapper = getWrapper(slider);
708+
709+
return {
710+
drag : function simulateDrag(drag) {
711+
712+
wrapper.triggerHandler({type: '$md.pressdown', pointer: drag });
713+
wrapper.triggerHandler({type: '$md.dragstart', pointer: drag });
714+
715+
$timeout.flush();
716+
}
717+
};
718+
}
719+
720+
});
721+
722+
it('should increment model on left arrow', function() {
723+
var slider = setup('md-invert min="100" max="104" step="2" ng-model="model"');
724+
pageScope.$apply('model = 100');
725+
726+
var wrapper = getWrapper(slider);
727+
728+
wrapper.triggerHandler({
729+
type: 'keydown',
730+
keyCode: $mdConstant.KEY_CODE.LEFT_ARROW
731+
});
732+
$timeout.flush();
733+
expect(pageScope.model).toBe(102);
734+
735+
wrapper.triggerHandler({
736+
type: 'keydown',
737+
keyCode: $mdConstant.KEY_CODE.LEFT_ARROW
738+
});
739+
$timeout.flush();
740+
expect(pageScope.model).toBe(104);
741+
742+
// Stays at max.
743+
wrapper.triggerHandler({
744+
type: 'keydown',
745+
keyCode: $mdConstant.KEY_CODE.LEFT_ARROW
746+
});
747+
$timeout.flush();
748+
expect(pageScope.model).toBe(104);
749+
});
750+
751+
it('should decrement model on right arrow', function() {
752+
var slider = setup('md-invert min="100" max="104" step="2" ng-model="model"');
753+
pageScope.$apply('model = 104');
754+
755+
var wrapper = getWrapper(slider);
756+
757+
wrapper.triggerHandler({
758+
type: 'keydown',
759+
keyCode: $mdConstant.KEY_CODE.RIGHT_ARROW
760+
});
761+
$timeout.flush();
762+
expect(pageScope.model).toBe(102);
763+
764+
wrapper.triggerHandler({
765+
type: 'keydown',
766+
keyCode: $mdConstant.KEY_CODE.RIGHT_ARROW
767+
});
768+
$timeout.flush();
769+
expect(pageScope.model).toBe(100);
770+
771+
// Stays at min.
772+
wrapper.triggerHandler({
773+
type: 'keydown',
774+
keyCode: $mdConstant.KEY_CODE.RIGHT_ARROW
775+
});
776+
$timeout.flush();
777+
expect(pageScope.model).toBe(100);
778+
});
779+
780+
});
781+
556782

557783
it('should set a default tabindex', function() {
558784
var slider = setup();

0 commit comments

Comments
 (0)