@@ -59,7 +59,7 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
5959 private _hasFocus : boolean = false ;
6060 private _isMousedown : boolean = false ;
6161 private _isInitialized : boolean = false ;
62- private _slideRenderer : MdSlideToggleRenderer = null ;
62+ private _slideRenderer : SlideToggleRenderer = null ;
6363
6464 // State of the current drag, which holds required variables for the drag.
6565 private _dragState : {
@@ -80,13 +80,12 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
8080 // Returns the unique id for the visual hidden input.
8181 getInputId = ( ) => `${ this . id || this . _uniqueId } -input` ;
8282
83- constructor ( private _elementRef : ElementRef ,
84- private _renderer : Renderer ) {
85- this . _slideRenderer = new MdSlideToggleRenderer ( this . _elementRef ) ;
86- }
83+ constructor ( private _elementRef : ElementRef , private _renderer : Renderer ) { }
8784
8885 /** TODO: internal */
8986 ngAfterContentInit ( ) {
87+ this . _slideRenderer = new SlideToggleRenderer ( this . _elementRef ) ;
88+
9089 // Mark this component as initialized in AfterContentInit because the initial checked value can
9190 // possibly be set by NgModel or the checked attribute. This would cause the change event to
9291 // be emitted, before the component is actually initialized.
@@ -105,7 +104,7 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
105104 event . stopPropagation ( ) ;
106105
107106 // 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 ) {
107+ if ( ! this . disabled && ! this . _slideRenderer . isDragging ( ) ) {
109108 this . toggle ( ) ;
110109 }
111110 }
@@ -223,89 +222,86 @@ export class MdSlideToggle implements AfterContentInit, ControlValueAccessor {
223222
224223 /** TODO: internal */
225224 _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 ) ;
225+ this . _slideRenderer . startThumbDrag ( this . checked ) ;
238226 }
239227
240228 /** TODO: internal */
241229 _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 ;
230+ this . _slideRenderer . updateThumbPosition ( event . deltaX ) ;
257231 }
258232
259233 /** TODO: internal */
260234 _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 ) ;
235+ // Notice that we have to stop outside of the current event handler,
236+ // because otherwise the click event will be fired and will reset the new checked variable.
237+ setTimeout ( ( ) => {
238+ this . checked = this . _slideRenderer . stopThumbDrag ( ) ;
239+ } , 0 ) ;
273240 }
274241
275242}
276243
277244/**
278245 * Renderer for the Slide Toggle component, which separates DOM modification in it's own class
279246 */
280- export class MdSlideToggleRenderer {
247+ class SlideToggleRenderer {
281248
282- constructor ( private _elementRef : ElementRef ) { }
249+ private _thumbEl : HTMLElement ;
250+ private _thumbBarEl : HTMLElement ;
251+ private _thumbBarWidth : number ;
252+ private _checked : boolean ;
253+ private _percentage : number ;
283254
284- getThumbClientRect ( ) : ClientRect {
285- let thumbEl = this . _elementRef . nativeElement . querySelector ( '.md-slide-toggle-thumb-container' ) ;
286- return thumbEl . getBoundingClientRect ( ) ;
255+ constructor ( private _elementRef : ElementRef ) {
256+ this . _thumbEl = _elementRef . nativeElement . querySelector ( '.md-slide-toggle-thumb-container' ) ;
257+ this . _thumbBarEl = _elementRef . nativeElement . querySelector ( '.md-slide-toggle-bar' ) ;
287258 }
288259
289- getThumbBarClientRect ( ) : ClientRect {
290- let thumbBarEl = this . _elementRef . nativeElement . querySelector ( '.md-slide-toggle-bar' ) ;
291- return thumbBarEl . getBoundingClientRect ( ) ;
260+ /** Whether the slide-toggle is currently dragging. */
261+ isDragging ( ) : boolean {
262+ return ! ! this . _thumbBarWidth ;
292263 }
293264
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)` ) ;
265+ /** Initializes the drag of the slide-toggle. */
266+ startThumbDrag ( checked : boolean ) {
267+ if ( ! this . _thumbBarWidth ) {
268+ this . _thumbBarWidth = this . _thumbBarEl . clientWidth - this . _thumbEl . clientWidth ;
269+ this . _checked = checked ;
270+ this . _thumbEl . classList . add ( ' md-dragging ') ;
271+ }
301272 }
302273
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 ) ;
274+ /** Stops the current drag and returns the new checked value. */
275+ stopThumbDrag ( ) : boolean {
276+ if ( this . _thumbBarWidth ) {
277+ this . _thumbBarWidth = null ;
278+ this . _thumbEl . classList . remove ( 'md-dragging' ) ;
279+
280+ applyCssTransform ( this . _thumbEl , '' ) ;
281+
282+ return this . _percentage > 50 ;
283+ }
307284 }
308285
286+ /** Updates the thumb containers position from the specified distance. */
287+ updateThumbPosition ( distance : number ) {
288+ if ( this . _thumbBarWidth ) {
289+ this . _percentage = this . _getThumbPercentage ( distance ) ;
290+ applyCssTransform ( this . _thumbEl , `translate3d(${ this . _percentage } %, 0, 0)` ) ;
291+ }
292+ }
293+
294+ /** Retrieves the percentage of thumb from the moved distance. */
295+ private _getThumbPercentage ( distance : number ) {
296+ let percentage = ( distance / this . _thumbBarWidth ) * 100 ;
297+
298+ // When the toggle was initially checked, then we have to start the drag at the end.
299+ if ( this . _checked ) {
300+ percentage += 100 ;
301+ }
302+
303+ return Math . max ( 0 , Math . min ( percentage , 100 ) ) ;
304+ }
309305
310306}
311307
0 commit comments