8000 Widget: Don't modify the prototype passed to $.widget(). Fixes #8876 … · faroncoder/jquery-ui@8b15aaf · GitHub
[go: up one dir, main page]

Skip to content

Commit 8b15aaf

Browse files
committed
Widget: Don't modify the prototype passed to $.widget(). Fixes #8876 - Calling _super calls wrong inherited widget.
1 parent 7312933 commit 8b15aaf

File tree

2 files changed

+71
-33
lines changed

2 files changed

+71
-33
lines changed

tests/unit/widget/widget_core.js

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,23 @@ TestHelpers.testJshint( "widget" );
1313

1414
test( "widget creation", function() {
1515
expect( 5 );
16-
var myPrototype = {
17-
_create: function() {},
18-
creationTest: function() {}
19-
};
16+
var method,
17+
myPrototype = {
18+
_create: function() {
19+
equal( method, "_create", "create function is copied over" );
20+
},
21+
creationTest: function() {
22+
equal( method, "creationTest", "random function is copied over" );
23+
}
24+
};
2025

2126
$.widget( "ui.testWidget", myPrototype );
2227
ok( $.isFunction( $.ui.testWidget ), "constructor was created" );
2328
equal( typeof $.ui.testWidget.prototype, "object", "prototype was created" );
24-
equal( $.ui.testWidget.prototype._create, myPrototype._create,
25-
"create function is copied over" );
26-
equal( $.ui.testWidget.prototype.creationTest, myPrototype.creationTest,
27-
"random function is copied over" );
29+
method = "_create";
30+
$.ui.testWidget.prototype._create();
31+
method = "creationTest";
32+
$.ui.testWidget.prototype.creationTest();
2833
equal( $.ui.testWidget.prototype.option, $.Widget.prototype.option,
2934
"option method copied over from base widget" );
3035
});
@@ -1324,6 +1329,34 @@ test( "redefine - widgetEventPrefix", function() {
13241329

13251330
});
13261331

1332+
test( "mixins", function() {
1333+
expect( 2 );
1334+
1335+
var mixin = {
1336+
method: function() {
1337+
return "mixed " + this._super();
1338+
}
1339+
};
1340+
1341+
$.widget( "ui.testWidget1", {
1342+
method: function() {
1343+
return "testWidget1";
1344+
}
1345+
});
1346+
$.widget( "ui.testWidget2", {
1347+
method: function() {
1348+
return "testWidget2";
1349+
}
1350+
});
1351+
$.widget( "ui.testWidget1", $.ui.testWidget1, mixin );
1352+
$.widget( "ui.testWidget2", $.ui.testWidget2, mixin );
1353+
1354+
equal( $( "<div>" ).testWidget1().testWidget1( "method" ),
1355+
"mixed testWidget1", "testWidget1 mixin successful" );
1356+
equal( $( "<div>" ).testWidget2().testWidget2( "method" ),
1357+
"mixed testWidget2", "testWidget2 mixin successful" );
1358+
});
1359+
13271360
asyncTest( "_delay", function() {
13281361
expect( 6 );
13291362
var order = 0,

ui/jquery.ui.widget.js

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ $.cleanData = function( elems ) {
2525

2626
$.widget = function( name, base, prototype ) {
2727
var fullName, existingConstructor, constructor, basePrototype,
28+
// proxiedPrototype allows the provided prototype to remain unmodified
29+
// so that it can be used as a mixin for multiple widgets (#8876)
30+
proxiedPrototype = {},
2831
namespace = name.split( "." )[ 0 ];
2932

3033
name = name.split( "." )[ 1 ];
@@ -71,38 +74,40 @@ $.widget = function( name, base, prototype ) {
7174
// inheriting from
7275
basePrototype.options = $.widget.extend( {}, basePrototype.options );
7376
$.each( prototype, function( prop, value ) {
74-
if ( $.isFunction( value ) ) {
75-
prototype[ prop ] = (function() {
76-
var _super = function() {
77-
return base.prototype[ prop ].apply( this, arguments );
78-
},
79-
_superApply = function( args ) {
80-
return base.prototype[ prop ].apply( this, args );
81-
};
82-
return function() {
83-
var __super = this._super,
84-
__superApply = this._superApply,
85-
returnValue;
86-
87-
this._super = _super;
88-
this._superApply = _superApply;
89-
90-
returnValue = value.apply( this, arguments );
91-
92-
this._super = __super;
93-
this._superApply = __superApply;
94-
95-
return returnValue;
96-
};
97-
})();
77+
if ( !$.isFunction( value ) ) {
78+
proxiedPrototype[ prop ] = value;
79+
return;
9880
}
81+
proxiedPrototype[ prop ] = (function() {
82+
var _super = function() {
83+
return base.prototype[ prop ].apply( this, arguments );
84+
},
85+
_superApply = function( args ) {
86+
return base.prototype[ prop ].apply( this, args );
87+
};
88+
return function() {
89+
var __super = this._super,
90+
__superApply = this._superApply,
91+
returnValue;
92+
93+
this._super = _super;
94+
this._superApply = _superApply;
95+
96+
returnValue = value.apply( this, arguments );
97+
98+
this._super = __super;
99+
this._superApply = __superApply;
100+
101+
return returnValue;
102+
};
103+
})();
99104
});
100105
constructor.prototype = $.widget.extend( basePrototype, {
101106
// TODO: remove support for widgetEventPrefix
102107
// always use the name + a colon as the prefix, e.g., draggable:start
103108
// don't prefix for widgets that aren't DOM-based
104109
widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
105-
}, prototype, {
110+
}, proxiedPrototype, {
106111
constructor: constructor,
107112
namespace: namespace,
108113
widgetName: name,

0 commit comments

Comments
 (0)
0