Skip to content

Commit 5593736

Browse files
committed
Unit tests and implementation for $.Widget.prototype._bind, handling instance-scope for handlers, options.disabled and unbinding on destroy
1 parent faf963c commit 5593736

File tree

2 files changed

+96
-24
lines changed

2 files changed

+96
-24
lines changed

tests/unit/widget/widget.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,18 @@ test('merge multiple option arguments', function() {
146146
});
147147
});
148148

149+
function teardownWidget(name) {
150+
delete $.fn[name];
151+
delete $.ui[name];
152+
}
153+
149154
test(".widget() - base", function() {
150155
$.widget("ui.testWidget", {
151156
_create: function() {}
152157
});
153158
var div = $("<div></div>").testWidget()
154159
same(div[0], div.testWidget("widget")[0]);
160+
teardownWidget("testWidget");
155161
});
156162

157163
test(".widget() - overriden", function() {
@@ -163,6 +169,72 @@ test(".widget() - overriden", function() {
163169
}
164170
});
165171
same(wrapper[0], $("<div></div>").testWidget().testWidget("widget")[0]);
172+
teardownWidget("testWidget");
173+
});
174+
175+
test("_bind to element (default)", function() {
176+
expect(12);
177+
var self;
178+
$.widget("ui.testWidget", {
179+
_create: function() {
180+
self = this;
181+
this._bind({
182+
keyup: this.keyup,
183+
keydown: this.keydown
184+
});
185+
},
186+
keyup: function(event) {
187+
equals( self, this );
188+
equals( self.element[0], event.currentTarget );
189+
equals( "keyup", event.type );
190+
},
191+
keydown: function(event) {
192+
equals( self, this );
193+
equals( self.element[0], event.currentTarget );
194+
equals( "keydown", event.type );
195+
}
196+
});
197+
var widget = $("<div></div>").testWidget().trigger("keyup").trigger("keydown");
198+
widget.testWidget("disable").trigger("keyup").trigger("keydown");
199+
widget.testWidget("enable").trigger("keyup").trigger("keydown");
200+
widget.testWidget("destroy").trigger("keyup").trigger("keydown");
201+
teardownWidget("testWidget");
166202
});
167203

204+
test("_bind to descendent", function() {
205+
expect(12);
206+
var self;
207+
$.widget("ui.testWidget", {
208+
_create: function() {
209+
self = this;
210+
this._bind(this.element.find("strong"), {
211+
keyup: this.keyup,
212+
keydown: this.keydown
213+
});
214+
},
215+
keyup: function(event) {
216+
equals( self, this );
217+
equals( self.element.find("strong")[0], event.currentTarget );
218+
equals( "keyup", event.type );
219+
},
220+
keydown: function(event) {
221+
equals( self, this );
222+
equals( self.element.find("strong")[0], event.currentTarget );
223+
equals( "keydown", event.type );
224+
}
225+
});
226+
// trigger events on both widget and descendent to ensure that only descendent receives them
227+
var widget = $("<div><p><strong>hello</strong> world</p></div>").testWidget().trigger("keyup").trigger("keydown");
228+
var descendent = widget.find("strong").trigger("keyup").trigger("keydown");
229+
widget.testWidget("disable").trigger("keyup").trigger("keydown");
230+
descendent.trigger("keyup").trigger("keydown");
231+
widget.testWidget("enable").trigger("keyup").trigger("keydown");
232+
descendent.trigger("keyup").trigger("keydown");
233+
widget.testWidget("destroy").trigger("keyup").trigger("keydown");
234+
descendent.trigger("keyup").trigger("keydown");
235+
teardownWidget("testWidget");
236+
});
237+
238+
// test destroy and disabled
239+
168240
})(jQuery);

ui/jquery.ui.widget.js

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ $.Widget.prototype = {
139139
this.element.bind( "remove." + this.widgetName, function() {
140140
self.destroy();
141141
});
142+
143+
// used by _bind
144+
this.bindings = $();
142145

143146
this._create();
144147
this._init();
@@ -156,6 +159,8 @@ $.Widget.prototype = {
156159
.removeClass(
157160
this.widgetBaseClass + "-disabled " +
158161
this.namespace + "-state-disabled" );
162+
this.bindings
163+
.unbind( "." + this.widgetName );
159164
},
160165

161166
widget: function() {
@@ -206,30 +211,25 @@ $.Widget.prototype = {
206211
return this._setOption( "disabled", true );
207212
},
208213

209-
_bind: function() {
210-
// TODO figure out which element to bind to: this.element, if none specified
211-
// TODO append widget namespace to all event names
212-
// TODO set the scope of the callback to the instance (this here)
213-
// TODO extend destroy to unbind all events to elements other then this.element
214-
215-
// usage: bind to this.element
216-
this._bind({
217-
mouseover: function(event) {
218-
this.show(event.currentTarget)
219-
},
220-
mouseout: function(event) {
221-
this.hide(event.currentTarget);
222-
}
223-
});
224-
// usage: bind to a specified element
225-
this._bind(this.element.find(".headers"), {
226-
mouseover: function(event) {
227-
this.show(event.currentTarget)
228-
},
229-
mouseout: function(event) {
230-
this.hide(event.currentTarget);
231-
}
232-
});
214+
_bind: function( element, handlers ) {
215+
// no element argument, shuffle and use this.element
216+
if ( handlers == undefined ) {
217+
handlers = element;
218+
element = this.element;
219+
// if binding to something else then this.element, store for unbinding on destroy
220+
} else {
221+
this.bindings = this.bindings.add( element );
222+
}
223+
var instance = this;
224+
$.each( handlers, function(event, handler) {
225+
element.bind( event + "." + instance.widgetName, function() {
226+
if ( instance.options.disabled ) {
227+
return;
228+
}
229+
return handler.apply( instance, arguments );
230+
});
231+
232+
});
233233
},
234234

235235
_trigger: function( type, event, data ) {

0 commit comments

Comments
 (0)