From fd8d5d2168586d39dac7e145c2c7b283f8ae3d93 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Mon, 22 Mar 2010 15:24:23 +0100
Subject: [PATCH 1/7] Placeholder for _bind prototype
---
ui/jquery.ui.widget.js | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/ui/jquery.ui.widget.js b/ui/jquery.ui.widget.js
index 49067449dcd..a888020f4d2 100644
--- a/ui/jquery.ui.widget.js
+++ b/ui/jquery.ui.widget.js
@@ -205,6 +205,12 @@ $.Widget.prototype = {
disable: function() {
return this._setOption( "disabled", true );
},
+
+ _bind: function() {
+ // TODO figure out which element to bind to: this.element, if none specified
+ // TODO append widget namespace to all event names
+ // TODO set the scope of the callback to the instance (this here)
+ },
_trigger: function( type, event, data ) {
var callback = this.options[ type ];
From faf963c9c5ab08f561e0e21417f9d93a039aa938 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Mon, 22 Mar 2010 15:50:09 +0100
Subject: [PATCH 2/7] Extended placeholder for _bind with usage code and some
TODOs
---
ui/jquery.ui.widget.js | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/ui/jquery.ui.widget.js b/ui/jquery.ui.widget.js
index a888020f4d2..837dcd8c17e 100644
--- a/ui/jquery.ui.widget.js
+++ b/ui/jquery.ui.widget.js
@@ -210,6 +210,26 @@ $.Widget.prototype = {
// TODO figure out which element to bind to: this.element, if none specified
// TODO append widget namespace to all event names
// TODO set the scope of the callback to the instance (this here)
+ // TODO extend destroy to unbind all events to elements other then this.element
+
+ // usage: bind to this.element
+ this._bind({
+ mouseover: function(event) {
+ this.show(event.currentTarget)
+ },
+ mouseout: function(event) {
+ this.hide(event.currentTarget);
+ }
+ });
+ // usage: bind to a specified element
+ this._bind(this.element.find(".headers"), {
+ mouseover: function(event) {
+ this.show(event.currentTarget)
+ },
+ mouseout: function(event) {
+ this.hide(event.currentTarget);
+ }
+ });
},
_trigger: function( type, event, data ) {
From 559373631a1f3d965a7bc976338039ec721b81a4 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Fri, 26 Mar 2010 12:25:24 -0400
Subject: [PATCH 3/7] Unit tests and implementation for
$.Widget.prototype._bind, handling instance-scope for handlers,
options.disabled and unbinding on destroy
---
tests/unit/widget/widget.js | 72 +++++++++++++++++++++++++++++++++++++
ui/jquery.ui.widget.js | 48 ++++++++++++-------------
2 files changed, 96 insertions(+), 24 deletions(-)
diff --git a/tests/unit/widget/widget.js b/tests/unit/widget/widget.js
index 3c870f1fe18..40afd4b2bfb 100644
--- a/tests/unit/widget/widget.js
+++ b/tests/unit/widget/widget.js
@@ -146,12 +146,18 @@ test('merge multiple option arguments', function() {
});
});
+function teardownWidget(name) {
+ delete $.fn[name];
+ delete $.ui[name];
+}
+
test(".widget() - base", function() {
$.widget("ui.testWidget", {
_create: function() {}
});
var div = $("").testWidget()
same(div[0], div.testWidget("widget")[0]);
+ teardownWidget("testWidget");
});
test(".widget() - overriden", function() {
@@ -163,6 +169,72 @@ test(".widget() - overriden", function() {
}
});
same(wrapper[0], $("").testWidget().testWidget("widget")[0]);
+ teardownWidget("testWidget");
+});
+
+test("_bind to element (default)", function() {
+ expect(12);
+ var self;
+ $.widget("ui.testWidget", {
+ _create: function() {
+ self = this;
+ this._bind({
+ keyup: this.keyup,
+ keydown: this.keydown
+ });
+ },
+ keyup: function(event) {
+ equals( self, this );
+ equals( self.element[0], event.currentTarget );
+ equals( "keyup", event.type );
+ },
+ keydown: function(event) {
+ equals( self, this );
+ equals( self.element[0], event.currentTarget );
+ equals( "keydown", event.type );
+ }
+ });
+ var widget = $("").testWidget().trigger("keyup").trigger("keydown");
+ widget.testWidget("disable").trigger("keyup").trigger("keydown");
+ widget.testWidget("enable").trigger("keyup").trigger("keydown");
+ widget.testWidget("destroy").trigger("keyup").trigger("keydown");
+ teardownWidget("testWidget");
});
+test("_bind to descendent", function() {
+ expect(12);
+ var self;
+ $.widget("ui.testWidget", {
+ _create: function() {
+ self = this;
+ this._bind(this.element.find("strong"), {
+ keyup: this.keyup,
+ keydown: this.keydown
+ });
+ },
+ keyup: function(event) {
+ equals( self, this );
+ equals( self.element.find("strong")[0], event.currentTarget );
+ equals( "keyup", event.type );
+ },
+ keydown: function(event) {
+ equals( self, this );
+ equals( self.element.find("strong")[0], event.currentTarget );
+ equals( "keydown", event.type );
+ }
+ });
+ // trigger events on both widget and descendent to ensure that only descendent receives them
+ var widget = $("").testWidget().trigger("keyup").trigger("keydown");
+ var descendent = widget.find("strong").trigger("keyup").trigger("keydown");
+ widget.testWidget("disable").trigger("keyup").trigger("keydown");
+ descendent.trigger("keyup").trigger("keydown");
+ widget.testWidget("enable").trigger("keyup").trigger("keydown");
+ descendent.trigger("keyup").trigger("keydown");
+ widget.testWidget("destroy").trigger("keyup").trigger("keydown");
+ descendent.trigger("keyup").trigger("keydown");
+ teardownWidget("testWidget");
+});
+
+// test destroy and disabled
+
})(jQuery);
diff --git a/ui/jquery.ui.widget.js b/ui/jquery.ui.widget.js
index 837dcd8c17e..7b29bc153e8 100644
--- a/ui/jquery.ui.widget.js
+++ b/ui/jquery.ui.widget.js
@@ -139,6 +139,9 @@ $.Widget.prototype = {
this.element.bind( "remove." + this.widgetName, function() {
self.destroy();
});
+
+ // used by _bind
+ this.bindings = $();
this._create();
this._init();
@@ -156,6 +159,8 @@ $.Widget.prototype = {
.removeClass(
this.widgetBaseClass + "-disabled " +
this.namespace + "-state-disabled" );
+ this.bindings
+ .unbind( "." + this.widgetName );
},
widget: function() {
@@ -206,30 +211,25 @@ $.Widget.prototype = {
return this._setOption( "disabled", true );
},
- _bind: function() {
- // TODO figure out which element to bind to: this.element, if none specified
- // TODO append widget namespace to all event names
- // TODO set the scope of the callback to the instance (this here)
- // TODO extend destroy to unbind all events to elements other then this.element
-
- // usage: bind to this.element
- this._bind({
- mouseover: function(event) {
- this.show(event.currentTarget)
- },
- mouseout: function(event) {
- this.hide(event.currentTarget);
- }
- });
- // usage: bind to a specified element
- this._bind(this.element.find(".headers"), {
- mouseover: function(event) {
- this.show(event.currentTarget)
- },
- mouseout: function(event) {
- this.hide(event.currentTarget);
- }
- });
+ _bind: function( element, handlers ) {
+ // no element argument, shuffle and use this.element
+ if ( handlers == undefined ) {
+ handlers = element;
+ element = this.element;
+ // if binding to something else then this.element, store for unbinding on destroy
+ } else {
+ this.bindings = this.bindings.add( element );
+ }
+ var instance = this;
+ $.each( handlers, function(event, handler) {
+ element.bind( event + "." + instance.widgetName, function() {
+ if ( instance.options.disabled ) {
+ return;
+ }
+ return handler.apply( instance, arguments );
+ });
+
+ });
},
_trigger: function( type, event, data ) {
From 0a63be6367dc812700c69d272dc30da388a319b1 Mon Sep 17 00:00:00 2001
From: lthibodeaux
Date: Sat, 7 Aug 2010 08:17:06 -0700
Subject: [PATCH 4/7] Slider: Corrected range option setter. Refactored
_create() code to make portions accessible to both it and setter method.
Fixes #5602 - slider: Slider Does Not Exhibit Proper Behavior When Switching
Range
---
ui/jquery.ui.slider.js | 370 +++++++++++++++++++++++------------------
1 file changed, 209 insertions(+), 161 deletions(-)
diff --git a/ui/jquery.ui.slider.js b/ui/jquery.ui.slider.js
index d90a7940f8f..f4f40155e15 100644
--- a/ui/jquery.ui.slider.js
+++ b/ui/jquery.ui.slider.js
@@ -56,167 +56,9 @@ $.widget( "ui.slider", $.ui.mouse, {
this.element.addClass( "ui-slider-disabled ui-disabled" );
}
- this.range = $([]);
-
- if ( o.range ) {
- if ( o.range === true ) {
- this.range = $( "" );
- if ( !o.values ) {
- o.values = [ this._valueMin(), this._valueMin() ];
- }
- if ( o.values.length && o.values.length !== 2 ) {
- o.values = [ o.values[0], o.values[0] ];
- }
- } else {
- this.range = $( "" );
- }
-
- this.range
- .appendTo( this.element )
- .addClass( "ui-slider-range" );
-
- if ( o.range === "min" || o.range === "max" ) {
- this.range.addClass( "ui-slider-range-" + o.range );
- }
-
- // note: this isn't the most fittingly semantic framework class for this element,
- // but worked best visually with a variety of themes
- this.range.addClass( "ui-widget-header" );
- }
-
- if ( $( ".ui-slider-handle", this.element ).length === 0 ) {
- $( "" )
- .appendTo( this.element )
- .addClass( "ui-slider-handle" );
- }
-
- if ( o.values && o.values.length ) {
- while ( $(".ui-slider-handle", this.element).length < o.values.length ) {
- $( "" )
- .appendTo( this.element )
- .addClass( "ui-slider-handle" );
- }
- }
-
- this.handles = $( ".ui-slider-handle", this.element )
- .addClass( "ui-state-default" +
- " ui-corner-all" );
+ this._refreshRange();
- this.handle = this.handles.eq( 0 );
-
- this.handles.add( this.range ).filter( "a" )
- .click(function( event ) {
- event.preventDefault();
- })
- .hover(function() {
- if ( !o.disabled ) {
- $( this ).addClass( "ui-state-hover" );
- }
- }, function() {
- $( this ).removeClass( "ui-state-hover" );
- })
- .focus(function() {
- if ( !o.disabled ) {
- $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
- $( this ).addClass( "ui-state-focus" );
- } else {
- $( this ).blur();
- }
- })
- .blur(function() {
- $( this ).removeClass( "ui-state-focus" );
- });
-
- this.handles.each(function( i ) {
- $( this ).data( "index.ui-slider-handle", i );
- });
-
- this.handles
- .keydown(function( event ) {
- var ret = true,
- index = $( this ).data( "index.ui-slider-handle" ),
- allowed,
- curVal,
- newVal,
- step;
-
- if ( self.options.disabled ) {
- return;
- }
-
- switch ( event.keyCode ) {
- case $.ui.keyCode.HOME:
- case $.ui.keyCode.END:
- case $.ui.keyCode.PAGE_UP:
- case $.ui.keyCode.PAGE_DOWN:
- case $.ui.keyCode.UP:
- case $.ui.keyCode.RIGHT:
- case $.ui.keyCode.DOWN:
- case $.ui.keyCode.LEFT:
- ret = false;
- if ( !self._keySliding ) {
- self._keySliding = true;
- $( this ).addClass( "ui-state-active" );
- allowed = self._start( event, index );
- if ( allowed === false ) {
- return;
- }
- }
- break;
- }
-
- step = self.options.step;
- if ( self.options.values && self.options.values.length ) {
- curVal = newVal = self.values( index );
- } else {
- curVal = newVal = self.value();
- }
-
- switch ( event.keyCode ) {
- case $.ui.keyCode.HOME:
- newVal = self._valueMin();
- break;
- case $.ui.keyCode.END:
- newVal = self._valueMax();
- break;
- case $.ui.keyCode.PAGE_UP:
- newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );
- break;
- case $.ui.keyCode.PAGE_DOWN:
- newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );
- break;
- case $.ui.keyCode.UP:
- case $.ui.keyCode.RIGHT:
- if ( curVal === self._valueMax() ) {
- return;
- }
- newVal = self._trimAlignValue( curVal + step );
- break;
- case $.ui.keyCode.DOWN:
- case $.ui.keyCode.LEFT:
- if ( curVal === self._valueMin() ) {
- return;
- }
- newVal = self._trimAlignValue( curVal - step );
- break;
- }
-
- self._slide( event, index, newVal );
-
- return ret;
-
- })
- .keyup(function( event ) {
- var index = $( this ).data( "index.ui-slider-handle" );
-
- if ( self._keySliding ) {
- self._keySliding = false;
- self._stop( event, index );
- self._change( event, index );
- $( this ).removeClass( "ui-state-active" );
- }
-
- });
+ this._refreshHandles();
this._refreshValue();
@@ -509,6 +351,9 @@ $.widget( "ui.slider", $.ui.mouse, {
valsLength = this.options.values.length;
}
+ // Register look-back range state for post-processing
+ var lastRange = this.options.range;
+
$.Widget.prototype._setOption.apply( this, arguments );
switch ( key ) {
@@ -530,6 +375,24 @@ $.widget( "ui.slider", $.ui.mouse, {
.addClass( "ui-slider-" + this.orientation );
this._refreshValue();
break;
+ case "range":
+ // Handle necessary options object changes for migrating from multiple sliders to single
+ // Reverse case already handled in _refreshRange()
+ if ( lastRange === true && this.options.range !== true ) {
+ if ( this.options.range === "max" ) {
+ this.options.value = this.options.values[1];
+ } else {
+ this.options.value = this.options.values[0];
+ }
+ this.options.values = null;
+ }
+ this._animateOff = true;
+ // Redraw the fill and handle elements and set their values according to new options
+ this._refreshRange();
+ this._refreshHandles();
+ this._refreshValue();
+ this._animateOn = true;
+ break;
case "value":
this._animateOff = true;
this._refreshValue();
@@ -580,7 +443,7 @@ $.widget( "ui.slider", $.ui.mouse, {
return vals;
}
},
-
+
// returns the step-aligned value that val is closest to, between (inclusive) min and max
_trimAlignValue: function( val ) {
if ( val < this._valueMin() ) {
@@ -609,7 +472,192 @@ $.widget( "ui.slider", $.ui.mouse, {
_valueMax: function() {
return this.options.max;
},
+
+ _refreshRange: function() {
+ // Remove any pre-existing range fill div; member object reinitialized below
+ if ( this.range ) {
+ this.range.remove();
+ }
+
+ var o = this.options;
+
+ this.range = $([]);
+
+ if ( o.range ) {
+ if ( o.range === true ) {
+ this.range = $( "" );
+ if ( !o.values && o.value == undefined ) {
+ o.values = [ this._valueMin(), this._valueMin() ];
+ } else if ( !o.values && o.value != undefined ) {
+ o.values = [ o.value, o.value ];
+ o.value = null;
+ }
+ if ( o.values.length && o.values.length !== 2 ) {
+ o.values = [ o.values[0], o.values[0] ];
+ }
+ } else {
+ this.range = $( "" );
+ }
+
+ this.range
+ .appendTo( this.element )
+ .addClass( "ui-slider-range" );
+
+ if ( o.range === "min" || o.range === "max" ) {
+ this.range.addClass( "ui-slider-range-" + o.range );
+ }
+
+ // note: this isn't the most fittingly semantic framework class for this element,
+ // but worked best visually with a variety of themes
+ this.range.addClass( "ui-widget-header" );
+ }
+ },
+
+ _refreshHandles: function() {
+ // Remove any pre-existing jQuery data for handles, then remove handle objects themselves
+ if ( this.handles ) {
+ this.handles.each(function (i) {
+ $( this ).removeData( "index.ui-slider-handle", i );
+ });
+ $( ".ui-slider-handle", this.element ).remove();
+ }
+
+ var o = this.options;
+
+ $( "" )
+ .appendTo( this.element )
+ .addClass( "ui-slider-handle" );
+
+ if ( o.values && o.values.length ) {
+ while ( $(".ui-slider-handle", this.element).length < o.values.length ) {
+ $( "" )
+ .appendTo( this.element )
+ .addClass( "ui-slider-handle" );
+ }
+ }
+
+ this.handles = $( ".ui-slider-handle", this.element )
+ .addClass( "ui-state-default" +
+ " ui-corner-all" );
+
+ this.handle = this.handles.eq( 0 );
+
+ this.handles.add( this.range ).filter( "a" )
+ .click(function( event ) {
+ event.preventDefault();
+ })
+ .hover(function() {
+ if ( !o.disabled ) {
+ $( this ).addClass( "ui-state-hover" );
+ }
+ }, function() {
+ $( this ).removeClass( "ui-state-hover" );
+ })
+ .focus(function() {
+ if ( !o.disabled ) {
+ $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
+ $( this ).addClass( "ui-state-focus" );
+ } else {
+ $( this ).blur();
+ }
+ })
+ .blur(function() {
+ $( this ).removeClass( "ui-state-focus" );
+ });
+
+ this.handles.each(function( i ) {
+ $( this ).data( "index.ui-slider-handle", i );
+ });
+
+ this.handles
+ .keydown(function( event ) {
+ var ret = true,
+ index = $( this ).data( "index.ui-slider-handle" ),
+ allowed,
+ curVal,
+ newVal,
+ step;
+
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ case $.ui.keyCode.END:
+ case $.ui.keyCode.PAGE_UP:
+ case $.ui.keyCode.PAGE_DOWN:
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ ret = false;
+ if ( !self._keySliding ) {
+ self._keySliding = true;
+ $( this ).addClass( "ui-state-active" );
+ allowed = self._start( event, index );
+ if ( allowed === false ) {
+ return;
+ }
+ }
+ break;
+ }
+
+ step = self.options.step;
+ if ( self.options.values && self.options.values.length ) {
+ curVal = newVal = self.values( index );
+ } else {
+ curVal = newVal = self.value();
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ newVal = self._valueMin();
+ break;
+ case $.ui.keyCode.END:
+ newVal = self._valueMax();
+ break;
+ case $.ui.keyCode.PAGE_UP:
+ newVal = curVal + ( (self._valueMax() - self._valueMin()) / numPages );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ newVal = curVal - ( (self._valueMax() - self._valueMin()) / numPages );
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ if ( curVal === self._valueMax() ) {
+ return;
+ }
+ newVal = curVal + step;
+ break;
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ if ( curVal === self._valueMin() ) {
+ return;
+ }
+ newVal = curVal - step;
+ break;
+ }
+
+ self._slide( event, index, newVal );
+
+ return ret;
+
+ })
+ .keyup(function( event ) {
+ var index = $( this ).data( "index.ui-slider-handle" );
+
+ if ( self._keySliding ) {
+ self._keySliding = false;
+ self._stop( event, index );
+ self._change( event, index );
+ $( this ).removeClass( "ui-state-active" );
+ }
+ });
+
+ },
+
_refreshValue: function() {
var oRange = this.options.range,
o = this.options,
From b74d3053b13924f38d0a6f741691bb977973934e Mon Sep 17 00:00:00 2001
From: lthibodeaux
Date: Sat, 7 Aug 2010 11:38:09 -0500
Subject: [PATCH 5/7] html pages: added visual test for slider ticket #5602
---
tests/visual/slider/slider_ticket_5602.html | 35 +++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 tests/visual/slider/slider_ticket_5602.html
diff --git a/tests/visual/slider/slider_ticket_5602.html b/tests/visual/slider/slider_ticket_5602.html
new file mode 100644
index 00000000000..75a56ff531e
--- /dev/null
+++ b/tests/visual/slider/slider_ticket_5602.html
@@ -0,0 +1,35 @@
+
+
+
+
+ Slider Visual Test : Slider ticket #5602
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Set range option to:
+
+
+
+
+
\ No newline at end of file
From 248b513f841144fcb28f70df7f15c90a5a2da8eb Mon Sep 17 00:00:00 2001
From: lthibodeaux
Date: Sat, 7 Aug 2010 11:43:25 -0500
Subject: [PATCH 6/7] html pages: added newline to end of test for slider
ticket #5602
---
tests/visual/slider/slider_ticket_5602.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/visual/slider/slider_ticket_5602.html b/tests/visual/slider/slider_ticket_5602.html
index 75a56ff531e..56749fb5278 100644
--- a/tests/visual/slider/slider_ticket_5602.html
+++ b/tests/visual/slider/slider_ticket_5602.html
@@ -32,4 +32,4 @@