From 1d5c43d6c07aa2152d7822b622ccb4370e4a4519 Mon Sep 17 00:00:00 2001 From: Hans-Peter Buniat Date: Thu, 8 Sep 2011 12:08:52 +0200 Subject: [PATCH 1/3] first changes to allow two handles on a slider-bar --- docs/forms/forms-slider.html | 5 + docs/forms/sliders/index.html | 0 js/jquery.mobile.forms.slider.js | 235 ++++++++++++++++------------- tests/unit/slider/slider_events.js | 9 +- 4 files changed, 143 insertions(+), 106 deletions(-) mode change 100644 => 100755 docs/forms/sliders/index.html mode change 100644 => 100755 js/jquery.mobile.forms.slider.js mode change 100644 => 100755 tests/unit/slider/slider_events.js diff --git a/docs/forms/forms-slider.html b/docs/forms/forms-slider.html index 58565d00bbc..263beeb1cf0 100755 --- a/docs/forms/forms-slider.html +++ b/docs/forms/forms-slider.html @@ -52,6 +52,11 @@

Sliders

Sliders also respond to the keyboards shortcuts. To increase the current value the Right Arrow, Up Arrow, and Page Up keys can be used. To decrease the current value the Left Arrow, Down Arrow, and Page Down keys can be used. To move the slider to its minimum or maximum value use the Home and End keys respectively.

+

An example of a range-slider

+
+ + +

Refreshing a slider

diff --git a/docs/forms/sliders/index.html b/docs/forms/sliders/index.html old mode 100644 new mode 100755 diff --git a/js/jquery.mobile.forms.slider.js b/js/jquery.mobile.forms.slider.js old mode 100644 new mode 100755 index 9195fca14a1..f6463e24097 --- a/js/jquery.mobile.forms.slider.js +++ b/js/jquery.mobile.forms.slider.js @@ -15,6 +15,16 @@ $.widget( "mobile.slider", $.mobile.widget, { initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')" }, + values: function() { + var cType = this.element[ 0 ].nodeName.toLowerCase(); + + return { + value: cType == "input" ? parseFloat( this.element.val() ) : this.element[0].selectedIndex , + handleMax: ( this.element.data('handle-max') ? parseFloat( this.element.data('handle-max') ) : ( cType == "input" ? parseFloat( this.element.val() ) : this.element[0].selectedIndex )), + handleMin: ( this.element.data('handle-min') ? parseFloat( this.element.data('handle-min') ) : undefined) + }; + }, + _create: function() { // TODO: Each of these should have comments explain what they're for @@ -40,10 +50,6 @@ $.widget( "mobile.slider", $.mobile.widget, { label = $( "[for='"+ controlID +"']" ).attr( "id", labelID ), - val = function() { - return cType == "input" ? parseFloat( control.val() ) : control[0].selectedIndex; - }, - min = cType == "input" ? parseFloat( control.attr( "min" ) ) : 0, max = cType == "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1, @@ -52,24 +58,42 @@ $.widget( "mobile.slider", $.mobile.widget, { slider = $( "
" ), - - handle = $( "" ) - .appendTo( slider ) - .buttonMarkup({ corners: true, theme: theme, shadow: true }) - .attr({ - "role": "slider", - "aria-valuemin": min, - "aria-valuemax": max, - "aria-valuenow": val(), - "aria-valuetext": val(), - "title": val(), - "aria-labelledby": labelID - }), + handles = [], + values = self.values(), options; + // if there are both, min- & max-handle, defined - remove the value-handle + if (typeof values['handleMin'] !== 'undefined' && typeof values['handleMax'] !== 'undefined') { + values['value'] = undefined; + control.addClass('ui-slider-range'); + } + else { + values['handleMin'] = values['handleMax'] = undefined; + control.addClass('ui-slider-single'); + } + + jQuery.each(['value', 'handleMax', 'handleMin'], function(i, valueAttribute) { + if (typeof values[valueAttribute] !== 'undefined') { + handles.push($( "" ) + .appendTo( slider ) + .buttonMarkup({ corners: true, theme: theme, shadow: true }) + .attr({ + "role": "slider", + "aria-valuemin": min, + "aria-valuemax": max, + "aria-valuenow": values[valueAttribute], + "aria-valuetext": values[valueAttribute], + "title": values[valueAttribute], + "aria-labelledby": labelID + }) + .data('handle', valueAttribute) + ); + } + }); + $.extend( this, { slider: slider, - handle: handle, + handles: handles, dragging: false, beforeStart: null, userModified: false @@ -91,7 +115,7 @@ $.widget( "mobile.slider", $.mobile.widget, { .prependTo( slider ); $( "" + $( this ).text() + "" ) - .prependTo( handle ); + .prependTo( handles[0] ); }); } @@ -101,13 +125,13 @@ $.widget( "mobile.slider", $.mobile.widget, { // monitor the input for updated values control.addClass( cType === "input" ? "ui-slider-input" : "ui-slider-switch" ) .change( function() { - self.refresh( val(), true ); + self.refresh( self.values(), true ); }) .keyup( function() { // necessary? - self.refresh( val(), true, true ); + self.refresh( self.values(), true, true ); }) .blur( function() { - self.refresh( val(), true ); + self.refresh( self.values(), true ); }); // prevent screen drag when slider activated @@ -151,78 +175,81 @@ $.widget( "mobile.slider", $.mobile.widget, { slider.insertAfter( control ); // NOTE force focus on handle - this.handle - .bind( "vmousedown", function() { + jQuery.each(this.handles, function(i, handle) { + var handleName = handle.data('handle'); + handle.bind( "vmousedown", function() { $( this ).focus(); - }) - .bind( "vclick", false ); - - this.handle - .bind( "keydown", function( event ) { - var index = val(); - - if ( self.options.disabled ) { - return; - } - - // In all cases prevent the default and mark the handle as active - switch ( event.keyCode ) { - case $.mobile.keyCode.HOME: - case $.mobile.keyCode.END: - case $.mobile.keyCode.PAGE_UP: - case $.mobile.keyCode.PAGE_DOWN: - case $.mobile.keyCode.UP: - case $.mobile.keyCode.RIGHT: - case $.mobile.keyCode.DOWN: - case $.mobile.keyCode.LEFT: - event.preventDefault(); - - if ( !self._keySliding ) { - self._keySliding = true; - $( this ).addClass( "ui-state-active" ); - } - break; - } - - // move the slider according to the keypress - switch ( event.keyCode ) { - case $.mobile.keyCode.HOME: - self.refresh( min ); - break; - case $.mobile.keyCode.END: - self.refresh( max ); - break; - case $.mobile.keyCode.PAGE_UP: - case $.mobile.keyCode.UP: - case $.mobile.keyCode.RIGHT: - self.refresh( index + step ); - break; - case $.mobile.keyCode.PAGE_DOWN: - case $.mobile.keyCode.DOWN: - case $.mobile.keyCode.LEFT: - self.refresh( index - step ); - break; - } - }) // remove active mark - .keyup( function( event ) { - if ( self._keySliding ) { - self._keySliding = false; - $( this ).removeClass( "ui-state-active" ); - } - }); - - this.refresh(undefined, undefined, true); + }) + .bind( "vclick", false ) + .bind( "keydown", function( event ) { + var index = self.values(); + + index = index[handleName]; + + if ( self.options.disabled ) { + return; + } + + // In all cases prevent the default and mark the handle as active + switch ( event.keyCode ) { + case $.mobile.keyCode.HOME: + case $.mobile.keyCode.END: + case $.mobile.keyCode.PAGE_UP: + case $.mobile.keyCode.PAGE_DOWN: + case $.mobile.keyCode.UP: + case $.mobile.keyCode.RIGHT: + case $.mobile.keyCode.DOWN: + case $.mobile.keyCode.LEFT: + event.preventDefault(); + + if ( !self._keySliding ) { + self._keySliding = true; + $( this ).addClass( "ui-state-active" ); + } + break; + } + + // move the slider according to the keypress + switch ( event.keyCode ) { + case $.mobile.keyCode.HOME: + self.refresh( min ); + break; + case $.mobile.keyCode.END: + self.refresh( max ); + break; + case $.mobile.keyCode.PAGE_UP: + case $.mobile.keyCode.UP: + case $.mobile.keyCode.RIGHT: + self.refresh( index + step ); + break; + case $.mobile.keyCode.PAGE_DOWN: + case $.mobile.keyCode.DOWN: + case $.mobile.keyCode.LEFT: + self.refresh( index - step ); + break; + } + }) // remove active mark + .keyup( function( event ) { + if ( self._keySliding ) { + self._keySliding = false; + $( this ).removeClass( "ui-state-active" ); + } + }); + + self.refresh(values[handleName], undefined, true); + }); }, refresh: function( val, isfromControl, preventInputUpdate ) { if ( this.options.disabled ) { return; } - var control = this.element, percent, + var control = this.element, + percent, cType = control[0].nodeName.toLowerCase(), min = cType === "input" ? parseFloat( control.attr( "min" ) ) : 0, max = cType === "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1; - if ( typeof val === "object" ) { + if ( val instanceof jQuery.Event ) { var data = val, // a slight tolerance helped get to the ends of the slider tol = 8; @@ -231,11 +258,13 @@ $.widget( "mobile.slider", $.mobile.widget, { data.pageX > this.slider.offset().left + this.slider.width() + tol ) { return; } + percent = Math.round( ( ( data.pageX - this.slider.offset().left ) / this.slider.width() ) * 100 ); - } else { - if ( val == null ) { - val = cType === "input" ? parseFloat( control.val() ) : control[0].selectedIndex; - } + } else if (val !== null) { + if (typeof val === 'object') { + val = val['value']; + } + percent = ( parseFloat( val ) - min ) / ( max - min ) * 100; } @@ -246,31 +275,33 @@ $.widget( "mobile.slider", $.mobile.widget, { if ( percent < 0 ) { percent = 0; } - - if ( percent > 100 ) { + else if ( percent > 100 ) { percent = 100; } var newval = Math.round( ( percent / 100 ) * ( max - min ) ) + min; - if ( newval < min ) { newval = min; } - - if ( newval > max ) { + else if( newval > max ) { newval = max; } - // Flip the stack of the bg colors - if ( percent > 60 && cType === "select" ) { - // TODO: Dead path? + var actHandle; + jQuery.each(this.handles, function(i, handle) { + if (typeof actHandle !== 'object' || Math.abs(actHandle.attr('title') - newval) > Math.abs(handle.attr('title') - newval)) { + actHandle = handle; + } + }); + + if (typeof actHandle === 'object') { + actHandle.css( "left", percent + "%" ).attr( { + "aria-valuenow": (cType === "select") ? control.find( "option" ).eq( newval ).attr( "value" ) : newval, + "aria-valuetext": (cType === "select") ? control.find( "option" ).eq( newval ).text() : newval, + title: newval + }); + control.data(actHandle.data('handle'), newval); } - this.handle.css( "left", percent + "%" ); - this.handle.attr( { - "aria-valuenow": cType === "input" ? newval : control.find( "option" ).eq( newval ).attr( "value" ), - "aria-valuetext": cType === "input" ? newval : control.find( "option" ).eq( newval ).text(), - title: newval - }); // add/remove classes for flip toggle switch if ( cType === "select" ) { diff --git a/tests/unit/slider/slider_events.js b/tests/unit/slider/slider_events.js old mode 100644 new mode 100755 index eb12b4885e9..38495ead080 --- a/tests/unit/slider/slider_events.js +++ b/tests/unit/slider/slider_events.js @@ -6,7 +6,8 @@ var onChangeCnt = 0; window.onChangeCounter = function() { onChangeCnt++; - } + }; + module('jquery.mobile.slider.js'); var keypressTest = function(opts){ @@ -99,7 +100,7 @@ slider.keyup(); same(slider.val(), "200"); }); - + test( "input type should degrade to number when slider is created", function(){ same($("#range-slider-up").attr( "type" ), "number"); }); @@ -155,8 +156,8 @@ $( "#onchange" ).slider( "refresh", 50 ); equals(onChangeCnt, 1, "onChange should have been called once"); }); - - + + test( "slider controls will create when inside a container that receives a 'create' event", function(){ ok( !$("#enhancetest").appendTo(".ui-page-active").find(".ui-slider").length, "did not have enhancements applied" ); ok( $("#enhancetest").trigger("create").find(".ui-slider").length, "enhancements applied" ); From 81310844e1ed14cf1ae663c97aefa3414511174a Mon Sep 17 00:00:00 2001 From: Hans-Peter Buniat Date: Mon, 12 Sep 2011 15:35:56 +0200 Subject: [PATCH 2/3] simplified and re-structured the code, added some tests --- js/jquery.mobile.forms.slider.js | 122 ++++++++++++++--------------- tests/unit/slider/index.html | 4 + tests/unit/slider/slider_events.js | 50 +++++++++++- 3 files changed, 109 insertions(+), 67 deletions(-) mode change 100644 => 100755 tests/unit/slider/index.html diff --git a/js/jquery.mobile.forms.slider.js b/js/jquery.mobile.forms.slider.js index f6463e24097..2ec8b3a1ce9 100755 --- a/js/jquery.mobile.forms.slider.js +++ b/js/jquery.mobile.forms.slider.js @@ -12,17 +12,22 @@ $.widget( "mobile.slider", $.mobile.widget, { theme: null, trackTheme: null, disabled: false, - initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')" + initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')", + handleData: ['handle-min', 'handle-max'] }, values: function() { - var cType = this.element[ 0 ].nodeName.toLowerCase(); + var isInput = ( this.element[ 0 ].nodeName.toLowerCase() === "input" ), + e = this.element, + val = []; - return { - value: cType == "input" ? parseFloat( this.element.val() ) : this.element[0].selectedIndex , - handleMax: ( this.element.data('handle-max') ? parseFloat( this.element.data('handle-max') ) : ( cType == "input" ? parseFloat( this.element.val() ) : this.element[0].selectedIndex )), - handleMin: ( this.element.data('handle-min') ? parseFloat( this.element.data('handle-min') ) : undefined) - }; + jQuery.each(this.options.handleData, function(i, handle) { + if ( e.data(handle)) { + val.push( parseFloat( e.data(handle) ) ); + } + }); + + return val.length ? val : [isInput ? parseFloat( e.val() ) : e[0].selectedIndex ]; }, _create: function() { @@ -32,17 +37,19 @@ $.widget( "mobile.slider", $.mobile.widget, { control = this.element, + o = this.options, + parentTheme = control.parents( "[class*='ui-bar-'],[class*='ui-body-']" ).eq( 0 ), parentTheme = parentTheme.length ? parentTheme.attr( "class" ).match( /ui-(bar|body)-([a-z])/ )[ 2 ] : "c", - theme = this.options.theme ? this.options.theme : parentTheme, + theme = this.options.theme ? o.theme : parentTheme, - trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme, + trackTheme = o.trackTheme ? o.trackTheme : parentTheme, - cType = control[ 0 ].nodeName.toLowerCase(), + cTypeIsSelect = control[ 0 ].nodeName.toLowerCase() === "select", - selectClass = ( cType == "select" ) ? "ui-slider-switch" : "", + selectClass = ( cTypeIsSelect ) ? "ui-slider-switch" : "", controlID = control.attr( "id" ), @@ -50,9 +57,9 @@ $.widget( "mobile.slider", $.mobile.widget, { label = $( "[for='"+ controlID +"']" ).attr( "id", labelID ), - min = cType == "input" ? parseFloat( control.attr( "min" ) ) : 0, + min = !cTypeIsSelect ? parseFloat( control.attr( "min" ) ) : 0, - max = cType == "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1, + max = !cTypeIsSelect ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1, step = window.parseFloat( control.attr( "step" ) || 1 ), @@ -62,33 +69,22 @@ $.widget( "mobile.slider", $.mobile.widget, { values = self.values(), options; - // if there are both, min- & max-handle, defined - remove the value-handle - if (typeof values['handleMin'] !== 'undefined' && typeof values['handleMax'] !== 'undefined') { - values['value'] = undefined; - control.addClass('ui-slider-range'); - } - else { - values['handleMin'] = values['handleMax'] = undefined; - control.addClass('ui-slider-single'); - } - - jQuery.each(['value', 'handleMax', 'handleMin'], function(i, valueAttribute) { - if (typeof values[valueAttribute] !== 'undefined') { - handles.push($( "" ) - .appendTo( slider ) - .buttonMarkup({ corners: true, theme: theme, shadow: true }) - .attr({ - "role": "slider", - "aria-valuemin": min, - "aria-valuemax": max, - "aria-valuenow": values[valueAttribute], - "aria-valuetext": values[valueAttribute], - "title": values[valueAttribute], - "aria-labelledby": labelID - }) - .data('handle', valueAttribute) - ); - } + control.addClass(values.length > 1 ? 'ui-slider-range' : 'ui-slider-single'); + jQuery.each(values, function(i) { + handles.push($( "" ) + .appendTo( slider ) + .buttonMarkup({ corners: true, theme: theme, shadow: true }) + .attr({ + "role": "slider", + "aria-valuemin": min, + "aria-valuemax": max, + "aria-valuenow": values[i], + "aria-valuetext": values[i], + "title": values[i], + "aria-labelledby": labelID + }) + .data('handle', values.length > 1 ? o.handleData[i] : 'single') + ); }); $.extend( this, { @@ -99,7 +95,7 @@ $.widget( "mobile.slider", $.mobile.widget, { userModified: false }); - if ( cType == "select" ) { + if ( cTypeIsSelect ) { slider.wrapInner( "
" ); @@ -123,7 +119,7 @@ $.widget( "mobile.slider", $.mobile.widget, { label.addClass( "ui-slider" ); // monitor the input for updated values - control.addClass( cType === "input" ? "ui-slider-input" : "ui-slider-switch" ) + control.addClass( !cTypeIsSelect ? "ui-slider-input" : "ui-slider-switch" ) .change( function() { self.refresh( self.values(), true ); }) @@ -147,7 +143,7 @@ $.widget( "mobile.slider", $.mobile.widget, { self.dragging = true; self.userModified = false; - if ( cType === "select" ) { + if ( cTypeIsSelect ) { self.beforeStart = control[0].selectedIndex; } self.refresh( event ); @@ -160,7 +156,7 @@ $.widget( "mobile.slider", $.mobile.widget, { self.dragging = false; - if ( cType === "select" ) { + if ( cTypeIsSelect ) { if ( !self.userModified ) { //tap occurred, but value didn't change. flip it! @@ -176,15 +172,13 @@ $.widget( "mobile.slider", $.mobile.widget, { // NOTE force focus on handle jQuery.each(this.handles, function(i, handle) { - var handleName = handle.data('handle'); handle.bind( "vmousedown", function() { $( this ).focus(); }) .bind( "vclick", false ) .bind( "keydown", function( event ) { var index = self.values(); - - index = index[handleName]; + index = index[i]; if ( self.options.disabled ) { return; @@ -235,19 +229,20 @@ $.widget( "mobile.slider", $.mobile.widget, { $( this ).removeClass( "ui-state-active" ); } }); - - self.refresh(values[handleName], undefined, true); }); + + self.refresh(values, undefined, true); }, refresh: function( val, isfromControl, preventInputUpdate ) { if ( this.options.disabled ) { return; } - var control = this.element, + var self = this, + control = this.element, percent, - cType = control[0].nodeName.toLowerCase(), - min = cType === "input" ? parseFloat( control.attr( "min" ) ) : 0, - max = cType === "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1; + cTypeIsSelect = control[ 0 ].nodeName.toLowerCase() === "select", + min = !cTypeIsSelect ? parseFloat( control.attr( "min" ) ) : 0, + max = !cTypeIsSelect ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1; if ( val instanceof jQuery.Event ) { var data = val, @@ -260,11 +255,12 @@ $.widget( "mobile.slider", $.mobile.widget, { } percent = Math.round( ( ( data.pageX - this.slider.offset().left ) / this.slider.width() ) * 100 ); + } else if (typeof val === 'object' && val.length) { + jQuery.each(val, function(i, value) { + self.refresh(value, isfromControl, preventInputUpdate); + }); + return; } else if (val !== null) { - if (typeof val === 'object') { - val = val['value']; - } - percent = ( parseFloat( val ) - min ) / ( max - min ) * 100; } @@ -296,15 +292,14 @@ $.widget( "mobile.slider", $.mobile.widget, { if (typeof actHandle === 'object') { actHandle.css( "left", percent + "%" ).attr( { - "aria-valuenow": (cType === "select") ? control.find( "option" ).eq( newval ).attr( "value" ) : newval, - "aria-valuetext": (cType === "select") ? control.find( "option" ).eq( newval ).text() : newval, + "aria-valuenow": (cTypeIsSelect) ? control.find( "option" ).eq( newval ).attr( "value" ) : newval, + "aria-valuetext": (cTypeIsSelect) ? control.find( "option" ).eq( newval ).text() : newval, title: newval }); - control.data(actHandle.data('handle'), newval); } // add/remove classes for flip toggle switch - if ( cType === "select" ) { + if ( cTypeIsSelect ) { if ( newval === 0 ) { this.slider.addClass( "ui-slider-switch-a" ) .removeClass( "ui-slider-switch-b" ); @@ -316,11 +311,12 @@ $.widget( "mobile.slider", $.mobile.widget, { if ( !preventInputUpdate ) { // update control"s value - if ( cType === "input" ) { - control.val( newval ); + if ( !cTypeIsSelect ) { + actHandle.data('handle') === 'single' ? control.val(newval) : control.data(actHandle.data('handle'), newval); } else { control[ 0 ].selectedIndex = newval; } + if ( !isfromControl ) { control.trigger( "change" ); } diff --git a/tests/unit/slider/index.html b/tests/unit/slider/index.html old mode 100644 new mode 100755 index b359353be20..2c2a215251e --- a/tests/unit/slider/index.html +++ b/tests/unit/slider/index.html @@ -47,6 +47,10 @@

+
+ +
+
+

Sliders also respond to the keyboards shortcuts. To increase the current value the Right Arrow, Up Arrow, and Page Up keys can be used. To decrease the current value the Left Arrow, Down Arrow, and Page Down keys can be used. To move the slider to its minimum or maximum value use the Home and End keys respectively.

@@ -55,7 +55,7 @@

Sliders

An example of a range-slider

- +

Refreshing a slider

diff --git a/docs/forms/sliders/index.html b/docs/forms/sliders/index.html index 1053ab0728b..79e6fa6aed4 100755 --- a/docs/forms/sliders/index.html +++ b/docs/forms/sliders/index.html @@ -54,7 +54,7 @@

Sliders

The slider with a min of 500, max of 5,000 and initial value of 2,500

- +

Sliders also respond to the keyboards shortcuts. To increase the current value the Right Arrow, Up Arrow, and Page Up keys can be used. To decrease the current value the Left Arrow, Down Arrow, and Page Down keys can be used. To move the slider to its minimum or maximum value use the Home and End keys respectively.

diff --git a/js/jquery.mobile.forms.slider.js b/js/jquery.mobile.forms.slider.js index 2ec8b3a1ce9..fd33036b47e 100755 --- a/js/jquery.mobile.forms.slider.js +++ b/js/jquery.mobile.forms.slider.js @@ -11,6 +11,7 @@ $.widget( "mobile.slider", $.mobile.widget, { options: { theme: null, trackTheme: null, + rangeTheme: null, disabled: false, initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')", handleData: ['handle-min', 'handle-max'] @@ -35,7 +36,7 @@ $.widget( "mobile.slider", $.mobile.widget, { // TODO: Each of these should have comments explain what they're for var self = this, - control = this.element, + control = this.element, o = this.options, @@ -45,8 +46,12 @@ $.widget( "mobile.slider", $.mobile.widget, { theme = this.options.theme ? o.theme : parentTheme, + // theme of the outer track-bar trackTheme = o.trackTheme ? o.trackTheme : parentTheme, + // theme for the part between start & current slider position + rangeTheme = this.options.rangeTheme ? this.options.rangeTheme : trackTheme, + cTypeIsSelect = control[ 0 ].nodeName.toLowerCase() === "select", selectClass = ( cTypeIsSelect ) ? "ui-slider-switch" : "", @@ -63,10 +68,19 @@ $.widget( "mobile.slider", $.mobile.widget, { step = window.parseFloat( control.attr( "step" ) || 1 ), + // the slider-wrapper slider = $( "
" ), + + // handle-container handles = [], + + // the current handle-values values = self.values(), + + // the track-background-container + rangeBar, + options; control.addClass(values.length > 1 ? 'ui-slider-range' : 'ui-slider-single'); @@ -87,14 +101,6 @@ $.widget( "mobile.slider", $.mobile.widget, { ); }); - $.extend( this, { - slider: slider, - handles: handles, - dragging: false, - beforeStart: null, - userModified: false - }); - if ( cTypeIsSelect ) { slider.wrapInner( "
" ); @@ -115,6 +121,19 @@ $.widget( "mobile.slider", $.mobile.widget, { }); } + else if (trackTheme != rangeTheme) { + slider.wrapInner( "
" ); + rangeBar = slider.find('div.ui-slider-range-background'); + } + + $.extend( this, { + slider: slider, + handles: handles, + rangeBar: rangeBar, + dragging: false, + beforeStart: null, + userModified: false + }); label.addClass( "ui-slider" ); @@ -242,7 +261,13 @@ $.widget( "mobile.slider", $.mobile.widget, { percent, cTypeIsSelect = control[ 0 ].nodeName.toLowerCase() === "select", min = !cTypeIsSelect ? parseFloat( control.attr( "min" ) ) : 0, - max = !cTypeIsSelect ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1; + max = !cTypeIsSelect ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1, + + // the handle on which the new-value will be applied + actHandle, + + // the left-value of the range-theme + rangeLeft = 0; if ( val instanceof jQuery.Event ) { var data = val, @@ -283,7 +308,6 @@ $.widget( "mobile.slider", $.mobile.widget, { newval = max; } - var actHandle; jQuery.each(this.handles, function(i, handle) { if (typeof actHandle !== 'object' || Math.abs(actHandle.attr('title') - newval) > Math.abs(handle.attr('title') - newval)) { actHandle = handle; @@ -298,6 +322,14 @@ $.widget( "mobile.slider", $.mobile.widget, { }); } + if (this.rangeBar) { + rangeLeft = (this.handles.length > 1) ? this.handles[0].attr('title') : 0; + this.rangeBar.css({ + 'margin-left': rangeLeft + "%", + 'width': (percent-rangeLeft) + "%" + }); + } + // add/remove classes for flip toggle switch if ( cTypeIsSelect ) { if ( newval === 0 ) { diff --git a/tests/unit/slider/index.html b/tests/unit/slider/index.html index 2c2a215251e..b31bb7ecebe 100755 --- a/tests/unit/slider/index.html +++ b/tests/unit/slider/index.html @@ -50,6 +50,10 @@

+ +
+ +