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

Commit

Permalink
feat(slider): md-invert
Browse files Browse the repository at this point in the history
md-invert: make min value to top/right and max value to bottom/left

Closes #7666

Closes #7667
  • Loading branch information
soooooot authored and ThomasBurleson committed Jun 1, 2016
1 parent a55faa0 commit e85e1b9
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 6 deletions.
30 changes: 30 additions & 0 deletions src/components/slider/demoBasicUsage/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ <h3>
</md-input-container>
</md-slider-container>

<div style="margin-top: 50px;"></div>

<h3>Rating: {{rating}}/5 - demo of theming classes</h3>
<div layout>
<div flex="10" layout layout-align="center center">
Expand All @@ -56,6 +58,8 @@ <h3>Rating: {{rating}}/5 - demo of theming classes</h3>
</md-slider>
</div>

<div style="margin-top: 50px;"></div>

<h3>Disabled</h3>
<md-slider-container ng-disabled="isDisabled">
<md-icon md-svg-icon="device:brightness-low"></md-icon>
Expand All @@ -68,9 +72,35 @@ <h3>Disabled</h3>
<md-checkbox ng-model="isDisabled">Is disabled</md-checkbox>
<md-slider ng-model="disabled2" ng-disabled="true" aria-label="Disabled 2"></md-slider>

<div style="margin-top: 50px;"></div>

<h3>Disabled, Discrete, Read Only</h3>
<md-slider ng-model="disabled2" ng-disabled="true" step="3" md-discrete min="0" max="10" aria-label="Disabled discrete 2"></md-slider>
<md-slider ng-model="disabled3" ng-disabled="true" step="10" md-discrete aria-label="Disabled discrete 3" ng-readonly="readonly"></md-slider>
<md-checkbox ng-model="readonly">Read only</md-checkbox>

<div style="margin-top: 50px;"></div>
<h3>Invert</h3>
<md-slider-container>
<div flex="10" layout layout-align="center center">
<span class="md-body-1">Regular</span>
</div>
<md-slider ng-model="invert" min="0" max="100" aria-label="regular slider"></md-slider>

<md-input-container>
<input flex type="number" ng-model="invert" aria-label="regular-slider">
</md-input-container>
</md-slider-container>
<md-slider-container>
<div flex="10" layout layout-align="center center">
<span class="md-body-1">Invert</span>
</div>
<md-slider md-invert ng-model="invert" min="0" max="100" aria-label="invertd slider"></md-slider>

<md-input-container>
<input flex type="number" ng-model="invert" aria-label="invert-slider">
</md-input-container>
</md-slider-container>

</md-content>
</div>
2 changes: 2 additions & 0 deletions src/components/slider/demoBasicUsage/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ angular.module('sliderDemo1', ['ngMaterial'])
$scope.disabled2 = 0;
$scope.disabled3 = 70;

$scope.invert = Math.floor(Math.random() * 100);

$scope.isDisabled = true;
});
24 changes: 18 additions & 6 deletions src/components/slider/slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,14 @@ function SliderContainerDirective() {
* <md-slider md-discrete ng-model="myDiscreteValue" step="10" min="10" max="130">
* </md-slider>
* </hljs>
* <h4>Invert Mode</h4>
* <hljs lang="html">
* <md-slider md-invert ng-model="myValue" step="10" min="10" max="130">
* </md-slider>
* </hljs>
*
* @param {boolean=} md-discrete Whether to enable discrete mode.
* @param {boolean=} md-invert Whether to enable invert mode.
* @param {number=} step The distance between values the user is allowed to pick. Default 1.
* @param {number=} min The minimum value the user is allowed to pick. Default 0.
* @param {number=} max The maximum value the user is allowed to pick. Default 100.
Expand Down Expand Up @@ -206,6 +212,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
var DEFAULT_ROUND = 3;
var vertical = angular.isDefined(attr.mdVertical);
var discrete = angular.isDefined(attr.mdDiscrete);
var invert = angular.isDefined(attr.mdInvert);
angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(0);
angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(100);
angular.isDefined(attr.step)? attr.$observe('step', updateStep) : updateStep(1);
Expand Down Expand Up @@ -360,6 +367,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
} else if (vertical ? ev.keyCode === $mdConstant.KEY_CODE.UP_ARROW : ev.keyCode === $mdConstant.KEY_CODE.RIGHT_ARROW) {
changeAmount = step;
}
changeAmount = invert ? -changeAmount : changeAmount;
if (changeAmount) {
if (ev.metaKey || ev.ctrlKey || ev.altKey) {
changeAmount *= 4;
Expand Down Expand Up @@ -408,7 +416,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi

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

var percent = (ngModelCtrl.$viewValue - min) / (max - min);
var percent = valueToPercent(ngModelCtrl.$viewValue);
scope.modelValue = ngModelCtrl.$viewValue;
element.attr('aria-valuenow', ngModelCtrl.$viewValue);
setSliderPercent(percent);
Expand Down Expand Up @@ -447,12 +455,14 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
percent = clamp(percent);

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

thumbContainer.css(vertical ? 'bottom' : 'left', thumbPosition);
activeTrack.css(vertical ? 'height' : 'width', thumbPosition);

activeTrack.css(vertical ? 'height' : 'width', activeTrackPercent);

element.toggleClass('_md-min', percent === 0);
element.toggleClass('_md-max', percent === 1);
element.toggleClass((invert ? '_md-max' : '_md-min'), percent === 0);
element.toggleClass((invert ? '_md-min' : '_md-max'), percent === 1);
}

/**
Expand Down Expand Up @@ -562,11 +572,13 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
* @returns {*}
*/
function percentToValue( percent ) {
return (min + percent * (max - min));
var adjustedPercent = invert ? (1 - percent) : percent;
return (min + adjustedPercent * (max - min));
}

function valueToPercent( val ) {
return (val - min)/(max - min);
var percent = (val - min) / (max - min);
return invert ? (1 - percent) : percent;
}
}
}
12 changes: 12 additions & 0 deletions src/components/slider/slider.scss
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,18 @@ md-slider {
}
}
}
&[md-invert] {
&:not([md-vertical]) ._md-track-fill {
left: auto;
right: 0;
}
&[md-vertical] {
._md-track-fill {
bottom: auto;
top: 0;
}
}
}
}

md-slider-container {
Expand Down
226 changes: 226 additions & 0 deletions src/components/slider/slider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,232 @@ describe('md-slider', function() {
}));

});

describe('invert', function () {
it('should set model on press', function() {
var slider = setup('md-vertical md-invert ng-model="value" min="0" max="100"');
pageScope.$apply('value = 50');

var wrapper = getWrapper(slider);

wrapper.triggerHandler({type: '$md.pressdown', pointer: { y: 70 }});
wrapper.triggerHandler({type: '$md.dragstart', pointer: { y: 70 }});
$timeout.flush();
expect(pageScope.value).toBe(70);

// When going past max, it should clamp to max.
wrapper.triggerHandler({type: '$md.drag', pointer: { y: 0 }});
$timeout.flush();
expect(pageScope.value).toBe(0);

wrapper.triggerHandler({type: '$md.drag', pointer: { y: 50 }});
$timeout.flush();
expect(pageScope.value).toBe(50);
});

it('should decrement model on up arrow', function() {
var slider = setup('md-vertical md-invert min="100" max="104" step="2" ng-model="model"');
pageScope.$apply('model = 104');

var wrapper = getWrapper(slider);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.UP_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(102);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.UP_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(100);

// Stays at min.
wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.UP_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(100);

});

it('should increment model on down arrow', function() {
var slider = setup('md-vertical md-invert min="100" max="104" step="2" ng-model="model"');
pageScope.$apply('model = 100');

var wrapper = getWrapper(slider);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(102);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(104);

// Stays at max.
wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(104);
});

it('should update the thumb text', function() {
var slider = setup('md-vertical md-invert ng-model="value" md-discrete min="0" max="100" step="1"');
var wrapper = getWrapper(slider);

pageScope.$apply('value = 30');
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('30');

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.DOWN_ARROW
});
$timeout.flush();
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('31');

wrapper.triggerHandler({type: '$md.pressdown', pointer: { y: 70 }});
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('70');

wrapper.triggerHandler({type: '$md.dragstart', pointer: { y: 93 }});
wrapper.triggerHandler({type: '$md.drag', pointer: { y: 93 }});
expect(slider[0].querySelector('._md-thumb-text').textContent).toBe('93');
});

it('should add _md-min class only when at min value', function() {
var slider = setup('md-vertical md-invert ng-model="model" min="0" max="30"');
var wrapper = getWrapper(slider);

pageScope.$apply('model = 0');
expect(slider).toHaveClass('_md-min');

wrapper.triggerHandler({type: '$md.dragstart', pointer: {y: 0}});
wrapper.triggerHandler({type: '$md.drag', pointer: {y: 10}});
$timeout.flush();
expect(slider).not.toHaveClass('_md-min');
});

it('should add _md-max class only when at max value', function() {
var slider = setup('md-vertical md-invert ng-model="model" min="0" max="30"');
var wrapper = getWrapper(slider);

pageScope.$apply('model = 30');
expect(slider).toHaveClass('_md-max');

wrapper.triggerHandler({type: '$md.dragstart', pointer: {y: 30}});
wrapper.triggerHandler({type: '$md.drag', pointer: {y: 10}});
$timeout.flush();
expect(slider).not.toHaveClass('_md-max');
});

it('should increment at a predictable step', function() {

buildSlider(0.1, 0, 1).drag({y:30});
expect(pageScope.value).toBe(0.3);

buildSlider(0.25, 0, 1).drag({y:45});
expect(pageScope.value).toBe(0.5);

buildSlider(0.25, 0, 1).drag({y:75});
expect(pageScope.value).toBe(0.75);

buildSlider(1, 0, 100).drag({y:10});
expect(pageScope.value).toBe(10);

buildSlider(20, 5, 45).drag({y:50});
expect(pageScope.value).toBe(25);

function buildSlider(step, min, max) {
var slider = setup('md-vertical md-invert ng-model="value" min="' + min + '" max="' + max + '" step="' + step + '"');
pageScope.$apply('value = 0.5');

var wrapper = getWrapper(slider);

return {
drag : function simulateDrag(drag) {

wrapper.triggerHandler({type: '$md.pressdown', pointer: drag });
wrapper.triggerHandler({type: '$md.dragstart', pointer: drag });

$timeout.flush();
}
};
}

});

it('should increment model on left arrow', function() {
var slider = setup('md-invert min="100" max="104" step="2" ng-model="model"');
pageScope.$apply('model = 100');

var wrapper = getWrapper(slider);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.LEFT_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(102);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.LEFT_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(104);

// Stays at max.
wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.LEFT_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(104);
});

it('should decrement model on right arrow', function() {
var slider = setup('md-invert min="100" max="104" step="2" ng-model="model"');
pageScope.$apply('model = 104');

var wrapper = getWrapper(slider);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.RIGHT_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(102);

wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.RIGHT_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(100);

// Stays at min.
wrapper.triggerHandler({
type: 'keydown',
keyCode: $mdConstant.KEY_CODE.RIGHT_ARROW
});
$timeout.flush();
expect(pageScope.model).toBe(100);
});

});


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

0 comments on commit e85e1b9

Please sign in to comment.