Skip to content

Commit 8908366

Browse files
devversionjelbourn
authored andcommitted
fix(slide-toggle): disabled theme not working and dragging works if disabled (#1268)
1 parent b91e983 commit 8908366

File tree

5 files changed

+122
-13
lines changed

5 files changed

+122
-13
lines changed

src/lib/slide-toggle/_slide-toggle-theme.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44

55
@mixin _md-slide-toggle-checked($palette) {
6-
&.md-checked {
6+
// Do not apply the checked colors if the toggle is disabled, because the specificity would be to high for
7+
// the disabled styles.
8+
&.md-checked:not(.md-disabled) {
79
.md-slide-toggle-thumb {
810
background-color: md-color($palette);
911
}

src/lib/slide-toggle/slide-toggle.scss

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ $md-slide-toggle-margin: 16px !default;
2424
line-height: $md-slide-toggle-height;
2525

2626
white-space: nowrap;
27+
28+
// Disable user selection to ensure that dragging is smooth without grabbing some elements
29+
// accidentally. Manually prefixing here, because the un-prefixed property is not supported yet.
30+
-webkit-user-select: none;
31+
-moz-user-select: none;
32+
-ms-user-select: none;
2733
user-select: none;
2834

2935
outline: none;
@@ -68,7 +74,6 @@ $md-slide-toggle-margin: 16px !default;
6874
height: $md-slide-toggle-height;
6975

7076
position: relative;
71-
user-select: none;
7277

7378
margin-right: 8px;
7479
}

src/lib/slide-toggle/slide-toggle.spec.ts

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2-
import {By} from '@angular/platform-browser';
1+
import {async, ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
2+
import {By, HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
33
import {Component} from '@angular/core';
44
import {MdSlideToggle, MdSlideToggleChange, MdSlideToggleModule} from './slide-toggle';
55
import {FormsModule, NgControl} from '@angular/forms';
6+
import {TestGestureConfig} from '../slider/test-gesture-config';
67

78
describe('MdSlideToggle', () => {
89

10+
let gestureConfig: TestGestureConfig;
11+
912
beforeEach(async(() => {
1013
TestBed.configureTestingModule({
1114
imports: [MdSlideToggleModule.forRoot(), FormsModule],
1215
declarations: [SlideToggleTestApp, SlideToggleFormsTestApp],
16+
providers: [
17+
{provide: HAMMER_GESTURE_CONFIG, useFactory: () => gestureConfig = new TestGestureConfig()}
18+
]
1319
});
1420

1521
TestBed.compileComponents();
@@ -392,6 +398,96 @@ describe('MdSlideToggle', () => {
392398

393399
});
394400

401+
describe('with dragging', () => {
402+
403+
let fixture: ComponentFixture<any>;
404+
405+
let testComponent: SlideToggleTestApp;
406+
let slideToggle: MdSlideToggle;
407+
let slideToggleElement: HTMLElement;
408+
let slideToggleControl: NgControl;
409+
let slideThumbContainer: HTMLElement;
410+
411+
beforeEach(async(() => {
412+
fixture = TestBed.createComponent(SlideToggleTestApp);
413+
414+
testComponent = fixture.debugElement.componentInstance;
415+
416+
fixture.detectChanges();
417+
418+
let slideToggleDebug = fixture.debugElement.query(By.css('md-slide-toggle'));
419+
let thumbContainerDebug = slideToggleDebug.query(By.css('.md-slide-toggle-thumb-container'));
420+
421+
slideToggle = slideToggleDebug.componentInstance;
422+
slideToggleElement = slideToggleDebug.nativeElement;
423+
slideToggleControl = slideToggleDebug.injector.get(NgControl);
424+
slideThumbContainer = thumbContainerDebug.nativeElement;
425+
}));
426+
427+
it('should drag from start to end', fakeAsync(() => {
428+
expect(slideToggle.checked).toBe(false);
429+
430+
gestureConfig.emitEventForElement('slidestart', slideThumbContainer);
431+
432+
expect(slideThumbContainer.classList).toContain('md-dragging');
433+
434+
gestureConfig.emitEventForElement('slide', slideThumbContainer, {
435+
deltaX: 200 // Arbitrary, large delta that will be clamped to the end of the slide-toggle.
436+
});
437+
438+
gestureConfig.emitEventForElement('slideend', slideThumbContainer);
439+
440+
// Flush the timeout for the slide ending.
441+
tick();
442+
443+
expect(slideToggle.checked).toBe(true);
444+
expect(slideThumbContainer.classList).not.toContain('md-dragging');
445+
}));
446+
447+
it('should drag from end to start', fakeAsync(() => {
448+
slideToggle.checked = true;
449+
450+
gestureConfig.emitEventForElement('slidestart', slideThumbContainer);
451+
452+
expect(slideThumbContainer.classList).toContain('md-dragging');
453+
454+
gestureConfig.emitEventForElement('slide', slideThumbContainer, {
455+
deltaX: -200 // Arbitrary, large delta that will be clamped to the end of the slide-toggle.
456+
});
457+
458+
gestureConfig.emitEventForElement('slideend', slideThumbContainer);
459+
460+
// Flush the timeout for the slide ending.
461+
tick();
462+
463+
expect(slideToggle.checked).toBe(false);
464+
expect(slideThumbContainer.classList).not.toContain('md-dragging');
465+
}));
466+
467+
it('should not drag when disbaled', fakeAsync(() => {
468+
slideToggle.disabled = true;
469+
470+
expect(slideToggle.checked).toBe(false);
471+
472+
gestureConfig.emitEventForElement('slidestart', slideThumbContainer);
473+
474+
expect(slideThumbContainer.classList).not.toContain('md-dragging');
475+
476+
gestureConfig.emitEventForElement('slide', slideThumbContainer, {
477+
deltaX: 200 // Arbitrary, large delta that will be clamped to the end of the slide-toggle.
478+
});
479+
480+
gestureConfig.emitEventForElement('slideend', slideThumbContainer);
481+
482+
// Flush the timeout for the slide ending.
483+
tick();
484+
485+
expect(slideToggle.checked).toBe(false);
486+
expect(slideThumbContainer.classList).not.toContain('md-dragging');
487+
}));
488+
489+
});
490+
395491
});
396492

397493
/**

src/lib/slide-toggle/slide-toggle.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,24 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
215215

216216
/** TODO: internal */
217217
_onDragStart() {
218-
this._slideRenderer.startThumbDrag(this.checked);
218+
if (!this.disabled) {
219+
this._slideRenderer.startThumbDrag(this.checked);
220+
}
219221
}
220222

221223
/** TODO: internal */
222224
_onDrag(event: HammerInput) {
223-
this._slideRenderer.updateThumbPosition(event.deltaX);
225+
if (this._slideRenderer.isDragging()) {
226+
this._slideRenderer.updateThumbPosition(event.deltaX);
227+
}
224228
}
225229

226230
/** TODO: internal */
227231
_onDragEnd() {
232+
if (!this._slideRenderer.isDragging()) {
233+
return;
234+
}
235+
228236
// Notice that we have to stop outside of the current event handler,
229237
// because otherwise the click event will be fired and will reset the new checked variable.
230238
setTimeout(() => {
@@ -258,7 +266,7 @@ class SlideToggleRenderer {
258266

259267
/** Initializes the drag of the slide-toggle. */
260268
startThumbDrag(checked: boolean) {
261-
if (!this._thumbBarWidth) {
269+
if (!this.isDragging()) {
262270
this._thumbBarWidth = this._thumbBarEl.clientWidth - this._thumbEl.clientWidth;
263271
this._checked = checked;
264272
this._thumbEl.classList.add('md-dragging');
@@ -267,7 +275,7 @@ class SlideToggleRenderer {
267275

268276
/** Stops the current drag and returns the new checked value. */
269277
stopThumbDrag(): boolean {
270-
if (this._thumbBarWidth) {
278+
if (this.isDragging()) {
271279
this._thumbBarWidth = null;
272280
this._thumbEl.classList.remove('md-dragging');
273281

@@ -279,10 +287,8 @@ class SlideToggleRenderer {
279287

280288
/** Updates the thumb containers position from the specified distance. */
281289
updateThumbPosition(distance: number) {
282-
if (this._thumbBarWidth) {
283-
this._percentage = this._getThumbPercentage(distance);
284-
applyCssTransform(this._thumbEl, `translate3d(${this._percentage}%, 0, 0)`);
285-
}
290+
this._percentage = this._getThumbPercentage(distance);
291+
applyCssTransform(this._thumbEl, `translate3d(${this._percentage}%, 0, 0)`);
286292
}
287293

288294
/** Retrieves the percentage of thumb from the moved distance. */

src/lib/slider/test-gesture-config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class TestGestureConfig extends MdGestureConfig {
3232
* The Angular event plugin for Hammer creates a new HammerManager instance for each listener,
3333
* so we need to apply our event on all instances to hit the correct listener.
3434
*/
35-
emitEventForElement(eventType: string, element: HTMLElement, eventData: Object) {
35+
emitEventForElement(eventType: string, element: HTMLElement, eventData = {}) {
3636
let instances = this.hammerInstances.get(element);
3737
instances.forEach(instance => instance.emit(eventType, eventData));
3838
}

0 commit comments

Comments
 (0)