Skip to content

Commit 6096aed

Browse files
committed
Widget: Fixed super methods with deep inheritance chains.
1 parent fb35d4e commit 6096aed

File tree

3 files changed

+59
-34
lines changed

3 files changed

+59
-34
lines changed

tests/unit/testsuite.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ function testWidgetDefaults( widget, defaults ) {
2424

2525
var privateMethods = [
2626
"_createWidget",
27-
"_super",
28-
"_superApply",
2927
"destroy",
3028
"option",
3129
"enable",

tests/unit/widget/widget_core.js

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test( "element normalization", function() {
3434
};
3535
$.ui.testWidget();
3636

37-
$.ui.testWidget.prototype.defaultElement = "<span data-test='pass'>";
37+
$.ui.testWidget.prototype.defaultElement = "<span data-test='pass'></span>";
3838
$.ui.testWidget.prototype._create = function() {
3939
ok( this.element.is( "span[data-test=pass]" ), "generated span with properties" );
4040
same( this.element.data( "testWidget" ), this, "instace stored in .data()" );
@@ -224,12 +224,12 @@ test( "._getCreateOptions()", function() {
224224
options: {
225225
option1: "valuex",
226226
option2: "valuex",
227-
option3: "value3",
227+
option3: "value3"
228228
},
229229
_getCreateOptions: function() {
230230
return {
231231
option1: "override1",
232-
option2: "overideX",
232+
option2: "overideX"
233233
};
234234
},
235235
_create: function() {
@@ -274,55 +274,75 @@ test( "re-init", function() {
274274
});
275275

276276
test( "._super()", function() {
277-
expect( 6 );
277+
expect( 9 );
278278
var instance;
279279
$.widget( "ui.testWidget", {
280280
method: function( a, b ) {
281-
same( this, instance, "this is correct in super widget" );
282-
same( a, 5, "parameter passed to super widget" );
283-
same( b, 10, "second parameter passed to super widget" );
281+
same( this, instance, "this is correct in testWidget" );
282+
same( a, 5, "parameter passed to testWidget" );
283+
same( b, 20, "second parameter passed to testWidget" );
284284
return a + b;
285285
}
286286
});
287287

288288
$.widget( "ui.testWidget2", $.ui.testWidget, {
289+
method: function( a, b ) {
290+
same( this, instance, "this is correct in testWidget2" );
291+
same( a, 5, "parameter passed to testWidget2" );
292+
same( b, 10, "parameter passed to testWidget2" );
293+
return this._super( "method", a, b*2 );
294+
}
295+
});
296+
297+
$.widget( "ui.testWidget3", $.ui.testWidget2, {
289298
method: function( a ) {
290-
same( this, instance, "this is correct in widget" );
291-
same( a, 5, "parameter passed to widget" );
299+
same( this, instance, "this is correct in testWidget3" );
300+
same( a, 5, "parameter passed to testWidget3" );
292301
var ret = this._super( "method", a, a*2 );
293-
same( ret, 15, "super returned value" );
302+
same( ret, 25, "super returned value" );
294303
}
295304
});
296305

297-
instance = $( "<div>" ).testWidget2().data( "testWidget2" );
306+
instance = $( "<div>" ).testWidget3().data( "testWidget3" );
298307
instance.method( 5 );
308+
delete $.ui.testWidget3;
299309
delete $.ui.testWidget2;
300310
});
301311

302312
test( "._superApply()", function() {
303-
expect( 7 );
313+
expect( 10 );
304314
var instance;
305315
$.widget( "ui.testWidget", {
306316
method: function( a, b ) {
307-
same( this, instance, "this is correct in super widget" );
308-
same( a, 5, "parameter passed to super widget" );
309-
same( b, 10, "second parameter passed to super widget" );
317+
same( this, instance, "this is correct in testWidget" );
318+
same( a, 5, "parameter passed to testWidget" );
319+
same( b, 10, "second parameter passed to testWidget" );
310320
return a + b;
311321
}
312322
});
313323

314324
$.widget( "ui.testWidget2", $.ui.testWidget, {
315325
method: function( a, b ) {
316-
same( this, instance, "this is correct in widget" );
317-
same( a, 5, "parameter passed to widget" );
318-
same( b, 10, "second parameter passed to widget" );
326+
same( this, instance, "this is correct in testWidget2" );
327+
same( a, 5, "parameter passed to testWidget2" );
328+
same( b, 10, "second parameter passed to testWidget2" );
329+
return this._superApply( "method", arguments );
330+
}
331+
});
332+
333+
$.widget( "ui.testWidget3", $.ui.testWidget2, {
334+
method: function( a, b ) {
335+
same( this, instance, "this is correct in testWidget3" );
336+
same( a, 5, "parameter passed to testWidget3" );
337+
same( b, 10, "second parameter passed to testWidget3" );
319338
var ret = this._superApply( "method", arguments );
320339
same( ret, 15, "super returned value" );
321340
}
322341
});
323342

324-
instance = $( "<div>" ).testWidget2().data( "testWidget2" );
343+
instance = $( "<div>" ).testWidget3().data( "testWidget3" );
325344
instance.method( 5, 10 );
345+
delete $.ui.testWidget3;
326346
delete $.ui.testWidget2;
327347
});
328348

@@ -829,7 +849,7 @@ test( "redefine", function() {
829849
equal( str, "bar", "original invoked with correct parameter" );
830850
}
831851
});
832-
var ctor = $.ui.testWidget;
852+
$.ui.testWidget.foo = "bar";
833853
$.widget( "ui.testWidget", $.ui.testWidget, {
834854
method: function( str ) {
835855
equal( str, "foo", "new invoked with correct parameter" );
@@ -839,7 +859,7 @@ test( "redefine", function() {
839859

840860
var instance = new $.ui.testWidget();
841861
instance.method( "foo" );
842-
equal( $.ui.testWidget, ctor, "constructor did not change" );
862+
equal( $.ui.testWidget.foo, "bar", "static properties remain" );
843863
});
844864

845865
}( jQuery ) );

ui/jquery.ui.widget.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ $.widget = function( name, base, prototype ) {
3636
};
3737

3838
$[ namespace ] = $[ namespace ] || {};
39-
$[ namespace ][ name ] = $[ namespace ][ name ] || function( options, element ) {
39+
// create the constructor using $.extend() so we can carry over any
40+
// static properties stored on the existing constructor (if there is one)
41+
$[ namespace ][ name ] = $.extend( function( options, element ) {
4042
// allow instantiation without "new" keyword
4143
if ( !this._createWidget ) {
4244
return new $[ namespace ][ name ]( options, element );
@@ -47,19 +49,31 @@ $.widget = function( name, base, prototype ) {
4749
if ( arguments.length ) {
4850
this._createWidget( options, element );
4951
}
50-
};
52+
}, $[ namespace ][ name ] );
5153

5254
var basePrototype = new base();
5355
// we need to make the options hash a property directly on the new instance
5456
// otherwise we'll modify the options hash on the prototype that we're
5557
// inheriting from
5658
basePrototype.options = $.extend( true, {}, basePrototype.options );
59+
$.each( prototype, function( prop, value ) {
60+
if ( $.isFunction( value ) ) {
61+
prototype[ prop ] = function() {
62+
this._super = function( method ) {
63+
return base.prototype[ method ].apply( this, slice.call( arguments, 1 ) );
64+
};
65+
this._superApply = function( method, args ) {
66+
return base.prototype[ method ].apply( this, args );
67+
};
68+
return value.apply( this, arguments );
69+
};
70+
}
71+
});
5772
$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
5873
namespace: namespace,
5974
widgetName: name,
6075
widgetEventPrefix: name,
61-
widgetBaseClass: fullName,
62-
base: base.prototype
76+
widgetBaseClass: fullName
6377
}, prototype );
6478

6579
$.widget.bridge( name, $[ namespace ][ name ] );
@@ -159,13 +173,6 @@ $.Widget.prototype = {
159173
_create: $.noop,
160174
_init: $.noop,
161175

162-
_super: function( method ) {
163-
return this.base[ method ].apply( this, slice.call( arguments, 1 ) );
164-
},
165-
_superApply: function( method, args ) {
166-
return this.base[ method ].apply( this, args );
167-
},
168-
169176
destroy: function() {
170177
this._destroy();
171178
// we can probably remove the unbind calls in 2.0

0 commit comments

Comments
 (0)