@@ -13,8 +13,9 @@ import {
1313 ControlValueAccessor ,
1414 NG_VALUE_ACCESSOR
1515} from '@angular/forms' ;
16- import { BooleanFieldValue } from '@angular2-material/core/annotations/field-value' ;
17- import { Observable } from 'rxjs/Observable' ;
16+ import { BooleanFieldValue } from '@angular2-material/core/annotations/field-value' ;
17+ import { Observable } from 'rxjs/Observable' ;
18+ import { applyCssTransform } from '@angular2-material/core/style/apply-transform' ;
1819
1920export const MD_SLIDE_TOGGLE_VALUE_ACCESSOR : any = {
2021 provide : NG_VALUE_ACCESSOR ,
@@ -58,6 +59,13 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
5859 private _hasFocus : boolean = false ;
5960 private _isMousedown : boolean = false ;
6061 private _isInitialized : boolean = false ;
62+ private _slideRenderer : MdSlideToggleRenderer = null ;
63+
64+ // State of the current drag, which holds required variables for the drag.
65+ private _dragState : {
66+ barWidth : number ;
67+ percentage ?: number ;
68+ } ;
6169
6270 @Input ( ) @BooleanFieldValue ( ) disabled : boolean = false ;
6371 @Input ( ) name : string = null ;
@@ -74,6 +82,7 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
7482
7583 constructor ( private _elementRef : ElementRef ,
7684 private _renderer : Renderer ) {
85+ this . _slideRenderer = new MdSlideToggleRenderer ( this . _elementRef ) ;
7786 }
7887
7988 /** TODO: internal */
@@ -95,7 +104,8 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
95104 // emit its event object to the component's `change` output.
96105 event . stopPropagation ( ) ;
97106
98- if ( ! this . disabled ) {
107+ // Once a drag is currently in progress, we do not want to toggle the slide-toggle on a click.
108+ if ( ! this . disabled && ! this . _dragState ) {
99109 this . toggle ( ) ;
100110 }
101111 }
@@ -202,13 +212,101 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
202212 }
203213 }
204214
215+ /** Emits the change event to the `change` output EventEmitter */
205216 private _emitChangeEvent ( ) {
206217 let event = new MdSlideToggleChange ( ) ;
207218 event . source = this ;
208219 event . checked = this . checked ;
209220 this . _change . emit ( event ) ;
210221 }
211222
223+
224+ /** TODO: internal */
225+ _onDragStart ( ) {
226+ if ( this . _dragState ) {
227+ return ;
228+ }
229+
230+ let thumbBarRect = this . _slideRenderer . getThumbBarClientRect ( ) ;
231+ let thumbRect = this . _slideRenderer . getThumbClientRect ( ) ;
232+
233+ this . _dragState = {
234+ barWidth : thumbBarRect . width - thumbRect . width
235+ } ;
236+
237+ this . _slideRenderer . toggleDragging ( true ) ;
238+ }
239+
240+ /** TODO: internal */
241+ _onDrag ( event : HammerInput ) {
242+ if ( ! this . _dragState ) {
243+ return ;
244+ }
245+
246+ let percentage = ( event . deltaX / this . _dragState . barWidth ) * 100 ;
247+
248+ // When the slide-toggle was initially checked, then we have to start the drag at 100%
249+ if ( this . checked ) {
250+ percentage += 100 ;
251+ }
252+
253+ percentage = Math . max ( 0 , Math . min ( percentage , 100 ) ) ;
254+
255+ this . _slideRenderer . updateThumbPosition ( percentage ) ;
256+ this . _dragState . percentage = percentage ;
257+ }
258+
259+ /** TODO: internal */
260+ _onDragEnd ( ) {
261+ if ( ! this . _dragState ) {
262+ return ;
263+ }
264+
265+ this . checked = this . _dragState . percentage > 50 ;
266+
267+ this . _slideRenderer . updateThumbPosition ( null ) ;
268+ this . _slideRenderer . toggleDragging ( false ) ;
269+
270+ // We have to clear the drag after one tick, because otherwise
271+ // the click event will fire and toggle the slide-toggle again.
272+ setTimeout ( ( ) => { this . _dragState = null ; } , 0 ) ;
273+ }
274+
275+ }
276+
277+ /**
278+ * Renderer for the Slide Toggle component, which separates DOM modification in it's own class
279+ */
280+ export class MdSlideToggleRenderer {
281+
282+ constructor ( private _elementRef : ElementRef ) { }
283+
284+ getThumbClientRect ( ) : ClientRect {
285+ let thumbEl = this . _elementRef . nativeElement . querySelector ( '.md-slide-toggle-thumb-container' ) ;
286+ return thumbEl . getBoundingClientRect ( ) ;
287+ }
288+
289+ getThumbBarClientRect ( ) : ClientRect {
290+ let thumbBarEl = this . _elementRef . nativeElement . querySelector ( '.md-slide-toggle-bar' ) ;
291+ return thumbBarEl . getBoundingClientRect ( ) ;
292+ }
293+
294+ /**
295+ * Updates the thumb containers position by using the specified percentage.
296+ * When the percentage is set to `null`, the custom thumb position will be removed.
297+ */
298+ updateThumbPosition ( percentage : number ) {
299+ let thumbEl = this . _elementRef . nativeElement . querySelector ( '.md-slide-toggle-thumb-container' ) ;
300+ applyCssTransform ( thumbEl , percentage === null ? '' : `translate3d(${ percentage } %, 0, 0)` ) ;
301+ }
302+
303+ /** Toggles the dragging class for the thumb container to toggle the transition duration. */
304+ toggleDragging ( isDragging : boolean ) {
305+ let thumbEl = this . _elementRef . nativeElement . querySelector ( '.md-slide-toggle-thumb-container' ) ;
306+ thumbEl . classList . toggle ( 'md-dragging' , isDragging ) ;
307+ }
308+
309+
212310}
213311
214312export const MD_SLIDE_TOGGLE_DIRECTIVES = [ MdSlideToggle ] ;
0 commit comments