8102b1f4fa84d8ffda6ded4c5d9daf8005b091b4
[myslice.git] / third-party / jquery-ui-1.10.2 / tests / unit / widget / widget_core.js
1 (function( $ ) {
2
3 module( "widget factory", {
4         teardown: function() {
5                 if ( $.ui ) {
6                         delete $.ui.testWidget;
7                         delete $.fn.testWidget;
8                 }
9         }
10 });
11
12 TestHelpers.testJshint( "widget" );
13
14 test( "widget creation", function() {
15         expect( 5 );
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                 };
25
26         $.widget( "ui.testWidget", myPrototype );
27         ok( $.isFunction( $.ui.testWidget ), "constructor was created" );
28         equal( typeof $.ui.testWidget.prototype, "object", "prototype was created" );
29         method = "_create";
30         $.ui.testWidget.prototype._create();
31         method = "creationTest";
32         $.ui.testWidget.prototype.creationTest();
33         equal( $.ui.testWidget.prototype.option, $.Widget.prototype.option,
34                 "option method copied over from base widget" );
35 });
36
37 test( "element normalization", function() {
38         expect( 11 );
39         var elem;
40         $.widget( "ui.testWidget", {} );
41
42         $.ui.testWidget.prototype._create = function() {
43                 // workaround for core ticket #8381
44                 this.element.appendTo( "#qunit-fixture" );
45                 ok( this.element.is( "div" ), "generated div" );
46                 deepEqual( this.element.data( "ui-testWidget" ), this, "instance stored in .data()" );
47         };
48         $.ui.testWidget();
49
50         $.ui.testWidget.prototype.defaultElement = "<span data-test='pass'></span>";
51         $.ui.testWidget.prototype._create = function() {
52                 ok( this.element.is( "span[data-test=pass]" ), "generated span with properties" );
53                 deepEqual( this.element.data( "ui-testWidget" ), this, "instace stored in .data()" );
54         };
55         $.ui.testWidget();
56
57         elem = $( "<input>" );
58         $.ui.testWidget.prototype._create = function() {
59                 deepEqual( this.element[ 0 ], elem[ 0 ], "from element" );
60                 deepEqual( elem.data( "ui-testWidget" ), this, "instace stored in .data()" );
61         };
62         $.ui.testWidget( {}, elem[ 0 ] );
63
64         elem = $( "<div>" );
65         $.ui.testWidget.prototype._create = function() {
66                 deepEqual( this.element[ 0 ], elem[ 0 ], "from jQuery object" );
67                 deepEqual( elem.data( "ui-testWidget" ), this, "instace stored in .data()" );
68         };
69         $.ui.testWidget( {}, elem );
70
71         elem = $( "<div id='element-normalization-selector'></div>" )
72                 .appendTo( "#qunit-fixture" );
73         $.ui.testWidget.prototype._create = function() {
74                 deepEqual( this.element[ 0 ], elem[ 0 ], "from selector" );
75                 deepEqual( elem.data( "ui-testWidget" ), this, "instace stored in .data()" );
76         };
77         $.ui.testWidget( {}, "#element-normalization-selector" );
78
79         $.ui.testWidget.prototype.defaultElement = null;
80         $.ui.testWidget.prototype._create = function() {
81                 // using strictEqual throws an error (Maximum call stack size exceeded)
82                 ok( this.element[ 0 ] === this, "instance as element" );
83         };
84         $.ui.testWidget();
85 });
86
87 test( "custom selector expression", function() {
88         expect( 1 );
89         var elem = $( "<div>" ).appendTo( "#qunit-fixture" );
90         $.widget( "ui.testWidget", {} );
91         elem.testWidget();
92         deepEqual( $( ":ui-testwidget" )[0], elem[0] );
93         elem.testWidget( "destroy" );
94 });
95
96 test( "jQuery usage", function() {
97         expect( 14 );
98
99         var elem, instance, ret,
100                 shouldCreate = false;
101
102         $.widget( "ui.testWidget", {
103                 getterSetterVal: 5,
104                 _create: function() {
105                         ok( shouldCreate, "create called on instantiation" );
106                 },
107                 methodWithParams: function( param1, param2 ) {
108                         ok( true, "method called via .pluginName(methodName)" );
109                         equal( param1, "value1",
110                                 "parameter passed via .pluginName(methodName, param)" );
111                         equal( param2, "value2",
112                                 "multiple parameters passed via .pluginName(methodName, param, param)" );
113
114                         return this;
115                 },
116                 getterSetterMethod: function( val ) {
117                         if ( val ) {
118                                 this.getterSetterVal = val;
119                         } else {
120                                 return this.getterSetterVal;
121                         }
122                 },
123                 jQueryObject: function() {
124                         return $( "body" );
125                 }
126         });
127
128         shouldCreate = true;
129         elem = $( "<div>" )
130                 .bind( "testwidgetcreate", function() {
131                         ok( shouldCreate, "create event triggered on instantiation" );
132                 })
133                 .testWidget();
134         shouldCreate = false;
135
136         instance = elem.data( "ui-testWidget" );
137         equal( typeof instance, "object", "instance stored in .data(pluginName)" );
138         equal( instance.element[0], elem[0], "element stored on widget" );
139         ret = elem.testWidget( "methodWithParams", "value1", "value2" );
140         equal( ret, elem, "jQuery object returned from method call" );
141
142         ret = elem.testWidget( "getterSetterMethod" );
143         equal( ret, 5, "getter/setter can act as getter" );
144         ret = elem.testWidget( "getterSetterMethod", 30 );
145         equal( ret, elem, "getter/setter method can be chainable" );
146         equal( instance.getterSetterVal, 30, "getter/setter can act as setter" );
147         ret = elem.testWidget( "jQueryObject" );
148         equal( ret[ 0 ], document.body, "returned jQuery object" );
149         equal( ret.end(), elem, "stack preserved" );
150
151         elem.testWidget( "destroy" );
152         equal( elem.data( "ui-testWidget" ), null );
153 });
154
155 test( "direct usage", function() {
156         expect( 9 );
157
158         var elem, instance, ret,
159                 shouldCreate = false;
160
161         $.widget( "ui.testWidget", {
162                 getterSetterVal: 5,
163                 _create: function() {
164                         ok( shouldCreate, "create called on instantiation" );
165                 },
166                 methodWithParams: function( param1, param2 ) {
167                         ok( true, "method called dirctly" );
168                         equal( param1, "value1", "parameter passed via direct call" );
169                         equal( param2, "value2", "multiple parameters passed via direct call" );
170
171                         return this;
172                 },
173                 getterSetterMethod: function( val ) {
174                         if ( val ) {
175                                 this.getterSetterVal = val;
176                         } else {
177                                 return this.getterSetterVal;
178                         }
179                 }
180         });
181
182         elem = $( "<div>" )[ 0 ];
183
184         shouldCreate = true;
185         instance = new $.ui.testWidget( {}, elem );
186         shouldCreate = false;
187
188         equal( $( elem ).data( "ui-testWidget" ), instance,
189                 "instance stored in .data(pluginName)" );
190         equal( instance.element[ 0 ], elem, "element stored on widget" );
191
192         ret = instance.methodWithParams( "value1", "value2" );
193         equal( ret, instance, "plugin returned from method call" );
194
195         ret = instance.getterSetterMethod();
196         equal( ret, 5, "getter/setter can act as getter" );
197         instance.getterSetterMethod( 30 );
198         equal( instance.getterSetterVal, 30, "getter/setter can act as setter" );
199 });
200
201 test( "error handling", function() {
202         expect( 3 );
203         var error = $.error;
204         $.widget( "ui.testWidget", {
205                 _privateMethod: function () {}
206         });
207         $.error = function( msg ) {
208                 equal( msg, "cannot call methods on testWidget prior to initialization; " +
209                         "attempted to call method 'missing'", "method call before init" );
210         };
211         $( "<div>" ).testWidget( "missing" );
212         $.error = function( msg ) {
213                 equal( msg, "no such method 'missing' for testWidget widget instance",
214                         "invalid method call on widget instance" );
215         };
216         $( "<div>" ).testWidget().testWidget( "missing" );
217         $.error = function ( msg ) {
218                 equal( msg, "no such method '_privateMethod' for testWidget widget instance",
219                         "invalid method call on widget instance" );
220         };
221         $( "<div>" ).testWidget().testWidget( "_privateMethod" );
222         $.error = error;
223 });
224
225 test( "merge multiple option arguments", function() {
226         expect( 1 );
227         $.widget( "ui.testWidget", {
228                 _create: function() {
229                         deepEqual( this.options, {
230                                 create: null,
231                                 disabled: false,
232                                 option1: "value1",
233                                 option2: "value2",
234                                 option3: "value3",
235                                 option4: {
236                                         option4a: "valuea",
237                                         option4b: "valueb"
238                                 }
239                         });
240                 }
241         });
242         $( "<div>" ).testWidget({
243                 option1: "valuex",
244                 option2: "valuex",
245                 option3: "value3",
246                 option4: {
247                         option4a: "valuex"
248                 }
249         }, {
250                 option1: "value1",
251                 option2: "value2",
252                 option4: {
253                         option4b: "valueb"
254                 }
255         }, {
256                 option4: {
257                         option4a: "valuea"
258                 }
259         });
260 });
261
262 test( "._getCreateOptions()", function() {
263         expect( 1 );
264         $.widget( "ui.testWidget", {
265                 options: {
266                         option1: "valuex",
267                         option2: "valuex",
268                         option3: "value3"
269                 },
270                 _getCreateOptions: function() {
271                         return {
272                                 option1: "override1",
273                                 option2: "overideX"
274                         };
275                 },
276                 _create: function() {
277                         deepEqual( this.options, {
278                                 create: null,
279                                 disabled: false,
280                                 option1: "override1",
281                                 option2: "value2",
282                                 option3: "value3"
283                         });
284                 }
285         });
286         $( "<div>" ).testWidget({ option2: "value2" });
287 });
288
289 test( "._getCreateEventData()", function() {
290         expect( 1 );
291         var data = { foo: "bar" };
292         $.widget( "ui.testWidget", {
293                 _getCreateEventData: function() {
294                         return data;
295                 }
296         });
297         $( "<div>" ).testWidget({
298                 create: function( event, ui ) {
299                         strictEqual( ui, data, "event data" );
300                 }
301         });
302 });
303
304 test( "re-init", function() {
305         expect( 3 );
306         var div = $( "<div>" ),
307                 actions = [];
308
309         $.widget( "ui.testWidget", {
310                 _create: function() {
311                         actions.push( "create" );
312                 },
313                 _init: function() {
314                         actions.push( "init" );
315                 },
316                 _setOption: function( key ) {
317                         actions.push( "option" + key );
318                 }
319         });
320
321         actions = [];
322         div.testWidget({ foo: "bar" });
323         deepEqual( actions, [ "create", "init" ], "correct methods called on init" );
324
325         actions = [];
326         div.testWidget();
327         deepEqual( actions, [ "init" ], "correct methods call on re-init" );
328
329         actions = [];
330         div.testWidget({ foo: "bar" });
331         deepEqual( actions, [ "optionfoo", "init" ], "correct methods called on re-init with options" );
332 });
333
334 test( "inheritance", function() {
335         expect( 6 );
336         // #5830 - Widget: Using inheritance overwrites the base classes options
337         $.widget( "ui.testWidgetBase", {
338                 options: {
339                         obj: {
340                                 key1: "foo",
341                                 key2: "bar"
342                         },
343                         arr: [ "testing" ]
344                 }
345         });
346
347         $.widget( "ui.testWidgetExtension", $.ui.testWidgetBase, {
348                 options: {
349                         obj: {
350                                 key1: "baz"
351                         },
352                         arr: [ "alpha", "beta" ]
353                 }
354         });
355
356         equal( $.ui.testWidgetBase.prototype.widgetEventPrefix, "testWidgetBase",
357                 "base class event prefix" );
358         deepEqual( $.ui.testWidgetBase.prototype.options.obj, {
359                 key1: "foo",
360                 key2: "bar"
361         }, "base class option object not overridden");
362         deepEqual( $.ui.testWidgetBase.prototype.options.arr, [ "testing" ],
363                 "base class option array not overridden");
364
365         equal( $.ui.testWidgetExtension.prototype.widgetEventPrefix, "testWidgetExtension",
366                 "extension class event prefix" );
367         deepEqual( $.ui.testWidgetExtension.prototype.options.obj, {
368                 key1: "baz",
369                 key2: "bar"
370         }, "extension class option object extends base");
371         deepEqual( $.ui.testWidgetExtension.prototype.options.arr, [ "alpha", "beta" ],
372                 "extension class option array overwrites base");
373
374         delete $.ui.testWidgetBase;
375         delete $.ui.testWidgetExtension;
376 });
377
378 test( "._super()", function() {
379         expect( 9 );
380         var instance;
381         $.widget( "ui.testWidget", {
382                 method: function( a, b ) {
383                         deepEqual( this, instance, "this is correct in testWidget" );
384                         deepEqual( a, 5, "parameter passed to testWidget" );
385                         deepEqual( b, 20, "second parameter passed to testWidget" );
386                         return a + b;
387                 }
388         });
389
390         $.widget( "ui.testWidget2", $.ui.testWidget, {
391                 method: function( a, b ) {
392                         deepEqual( this, instance, "this is correct in testWidget2" );
393                         deepEqual( a, 5, "parameter passed to testWidget2" );
394                         deepEqual( b, 10, "parameter passed to testWidget2" );
395                         return this._super( a, b*2 );
396                 }
397         });
398
399         $.widget( "ui.testWidget3", $.ui.testWidget2, {
400                 method: function( a ) {
401                         deepEqual( this, instance, "this is correct in testWidget3" );
402                         deepEqual( a, 5, "parameter passed to testWidget3" );
403                         var ret = this._super( a, a*2 );
404                         deepEqual( ret, 25, "super returned value" );
405                 }
406         });
407
408         instance = $( "<div>" ).testWidget3().data( "ui-testWidget3" );
409         instance.method( 5 );
410         delete $.ui.testWidget3;
411         delete $.ui.testWidget2;
412 });
413
414 test( "._superApply()", function() {
415         expect( 10 );
416         var instance;
417         $.widget( "ui.testWidget", {
418                 method: function( a, b ) {
419                         deepEqual( this, instance, "this is correct in testWidget" );
420                         deepEqual( a, 5, "parameter passed to testWidget" );
421                         deepEqual( b, 10, "second parameter passed to testWidget" );
422                         return a + b;
423                 }
424         });
425
426         $.widget( "ui.testWidget2", $.ui.testWidget, {
427                 method: function( a, b ) {
428                         deepEqual( this, instance, "this is correct in testWidget2" );
429                         deepEqual( a, 5, "parameter passed to testWidget2" );
430                         deepEqual( b, 10, "second parameter passed to testWidget2" );
431                         return this._superApply( arguments );
432                 }
433         });
434
435         $.widget( "ui.testWidget3", $.ui.testWidget2, {
436                 method: function( a, b ) {
437                         deepEqual( this, instance, "this is correct in testWidget3" );
438                         deepEqual( a, 5, "parameter passed to testWidget3" );
439                         deepEqual( b, 10, "second parameter passed to testWidget3" );
440                         var ret = this._superApply( arguments );
441                         deepEqual( ret, 15, "super returned value" );
442                 }
443         });
444
445         instance = $( "<div>" ).testWidget3().data( "ui-testWidget3" );
446         instance.method( 5, 10 );
447         delete $.ui.testWidget3;
448         delete $.ui.testWidget2;
449 });
450
451 test( ".option() - getter", function() {
452         expect( 6 );
453         $.widget( "ui.testWidget", {
454                 _create: function() {}
455         });
456
457         var options,
458                 div = $( "<div>" ).testWidget({
459                         foo: "bar",
460                         baz: 5,
461                         qux: [ "quux", "quuux" ]
462                 });
463
464         deepEqual( div.testWidget( "option", "x" ), null, "non-existent option" );
465         deepEqual( div.testWidget( "option", "foo"), "bar", "single option - string" );
466         deepEqual( div.testWidget( "option", "baz"), 5, "single option - number" );
467         deepEqual( div.testWidget( "option", "qux"), [ "quux", "quuux" ],
468                 "single option - array" );
469
470         options = div.testWidget( "option" );
471         deepEqual( options, {
472                 create: null,
473                 disabled: false,
474                 foo: "bar",
475                 baz: 5,
476                 qux: [ "quux", "quuux" ]
477         }, "full options hash returned" );
478         options.foo = "notbar";
479         deepEqual( div.testWidget( "option", "foo"), "bar",
480                 "modifying returned options hash does not modify plugin instance" );
481 });
482
483 test( ".option() - deep option getter", function() {
484         expect( 5 );
485         $.widget( "ui.testWidget", {} );
486         var div = $( "<div>" ).testWidget({
487                 foo: {
488                         bar: "baz",
489                         qux: {
490                                 quux: "xyzzy"
491                         }
492                 }
493         });
494         equal( div.testWidget( "option", "foo.bar" ), "baz", "one level deep - string" );
495         deepEqual( div.testWidget( "option", "foo.qux" ), { quux: "xyzzy" },
496                 "one level deep - object" );
497         equal( div.testWidget( "option", "foo.qux.quux" ), "xyzzy", "two levels deep - string" );
498         equal( div.testWidget( "option", "x.y" ), null, "top level non-existent" );
499         equal( div.testWidget( "option", "foo.x.y" ), null, "one level deep - non-existent" );
500 });
501
502 test( ".option() - delegate to ._setOptions()", function() {
503         expect( 2 );
504         var div,
505                 calls = [];
506         $.widget( "ui.testWidget", {
507                 _create: function() {},
508                 _setOptions: function( options ) {
509                         calls.push( options );
510                 }
511         });
512         div = $( "<div>" ).testWidget();
513
514         calls = [];
515         div.testWidget( "option", "foo", "bar" );
516         deepEqual( calls, [{ foo: "bar" }], "_setOptions called for single option" );
517
518         calls = [];
519         div.testWidget( "option", {
520                 bar: "qux",
521                 quux: "quuux"
522         });
523         deepEqual( calls, [{ bar: "qux", quux: "quuux" }],
524                 "_setOptions called with multiple options" );
525 });
526
527 test( ".option() - delegate to ._setOption()", function() {
528         expect( 2 );
529         var div,
530                 calls = [];
531         $.widget( "ui.testWidget", {
532                 _create: function() {},
533                 _setOption: function( key, val ) {
534                         calls.push({
535                                 key: key,
536                                 val: val
537                         });
538                 }
539         });
540         div = $( "<div>" ).testWidget();
541
542         calls = [];
543         div.testWidget( "option", "foo", "bar" );
544         deepEqual( calls, [{ key: "foo", val: "bar" }],
545                 "_setOption called for single option" );
546
547         calls = [];
548         div.testWidget( "option", {
549                 bar: "qux",
550                 quux: "quuux"
551         });
552         deepEqual( calls, [
553                 { key: "bar", val: "qux" },
554                 { key: "quux", val: "quuux" }
555         ], "_setOption called with multiple options" );
556 });
557
558 test( ".option() - deep option setter", function() {
559         expect( 6 );
560         $.widget( "ui.testWidget", {} );
561         var div = $( "<div>" ).testWidget();
562         function deepOption( from, to, msg ) {
563                 div.data( "ui-testWidget" ).options.foo = from;
564                 $.ui.testWidget.prototype._setOption = function( key, value ) {
565                         deepEqual( key, "foo", msg + ": key" );
566                         deepEqual( value, to, msg + ": value" );
567                 };
568         }
569
570         deepOption( { bar: "baz" }, { bar: "qux" }, "one deep" );
571         div.testWidget( "option", "foo.bar", "qux" );
572
573         deepOption( null, { bar: "baz" }, "null" );
574         div.testWidget( "option", "foo.bar", "baz" );
575
576         deepOption(
577                 { bar: "baz", qux: { quux: "quuux" } },
578                 { bar: "baz", qux: { quux: "quuux", newOpt: "newVal" } },
579                 "add property" );
580         div.testWidget( "option", "foo.qux.newOpt", "newVal" );
581 });
582
583 test( ".enable()", function() {
584         expect( 2 );
585         $.widget( "ui.testWidget", {
586                 _create: function() {},
587                 _setOption: function( key, val ) {
588                         deepEqual( key, "disabled", "_setOption called with disabled option" );
589                         deepEqual( val, false, "disabled set to false" );
590                 }
591         });
592         $( "<div>" ).testWidget().testWidget( "enable" );
593 });
594
595 test( ".disable()", function() {
596         expect( 2 );
597         $.widget( "ui.testWidget", {
598                 _create: function() {},
599                 _setOption: function( key, val ) {
600                         deepEqual( key, "disabled", "_setOption called with disabled option" );
601                         deepEqual( val, true, "disabled set to true" );
602                 }
603         });
604         $( "<div>" ).testWidget().testWidget( "disable" );
605 });
606
607 test( ".widget() - base", function() {
608         expect( 1 );
609         $.widget( "ui.testWidget", {
610                 _create: function() {}
611         });
612         var div = $( "<div>" ).testWidget();
613         deepEqual( div[0], div.testWidget( "widget" )[0]);
614 });
615
616 test( ".widget() - overriden", function() {
617         expect( 1 );
618         var wrapper = $( "<div>" );
619         $.widget( "ui.testWidget", {
620                 _create: function() {},
621                 widget: function() {
622                         return wrapper;
623                 }
624         });
625         deepEqual( wrapper[0], $( "<div>" ).testWidget().testWidget( "widget" )[0] );
626 });
627
628 test( "._on() to element (default)", function() {
629         expect( 12 );
630         var that, widget;
631         $.widget( "ui.testWidget", {
632                 _create: function() {
633                         that = this;
634                         this._on({
635                                 keyup: this.keyup,
636                                 keydown: "keydown"
637                         });
638                 },
639                 keyup: function( event ) {
640                         equal( that, this );
641                         equal( that.element[0], event.currentTarget );
642                         equal( "keyup", event.type );
643                 },
644                 keydown: function( event ) {
645                         equal( that, this );
646                         equal( that.element[0], event.currentTarget );
647                         equal( "keydown", event.type );
648                 }
649         });
650         widget = $( "<div></div>" )
651                 .testWidget()
652                 .trigger( "keyup" )
653                 .trigger( "keydown" );
654         widget
655                 .testWidget( "disable" )
656                 .trigger( "keyup" )
657                 .trigger( "keydown" );
658         widget
659                 .testWidget( "enable" )
660                 .trigger( "keyup" )
661                 .trigger( "keydown" );
662         widget
663                 .testWidget( "destroy" )
664                 .trigger( "keyup" )
665                 .trigger( "keydown" );
666 });
667
668 test( "._on() to element with suppressDisabledCheck", function() {
669         expect( 18 );
670         var that, widget;
671         $.widget( "ui.testWidget", {
672                 _create: function() {
673                         that = this;
674                         this._on( true, {
675                                 keyup: this.keyup,
676                                 keydown: "keydown"
677                         });
678                 },
679                 keyup: function( event ) {
680                         equal( that, this );
681                         equal( that.element[0], event.currentTarget );
682                         equal( "keyup", event.type );
683                 },
684                 keydown: function( event ) {
685                         equal( that, this );
686                         equal( that.element[0], event.currentTarget );
687                         equal( "keydown", event.type );
688                 }
689         });
690         widget = $( "<div></div>" )
691                 .testWidget()
692                 .trigger( "keyup" )
693                 .trigger( "keydown" );
694         widget
695                 .testWidget( "disable" )
696                 .trigger( "keyup" )
697                 .trigger( "keydown" );
698         widget
699                 .testWidget( "enable" )
700                 .trigger( "keyup" )
701                 .trigger( "keydown" );
702         widget
703                 .testWidget( "destroy" )
704                 .trigger( "keyup" )
705                 .trigger( "keydown" );
706 });
707
708 test( "._on() to descendent", function() {
709         expect( 12 );
710         var that, widget, descendant;
711         $.widget( "ui.testWidget", {
712                 _create: function() {
713                         that = this;
714                         this._on( this.element.find( "strong" ), {
715                                 keyup: this.keyup,
716                                 keydown: "keydown"
717                         });
718                 },
719                 keyup: function( event ) {
720                         equal( that, this );
721                         equal( that.element.find( "strong" )[0], event.currentTarget );
722                         equal( "keyup", event.type );
723                 },
724                 keydown: function(event) {
725                         equal( that, this );
726                         equal( that.element.find( "strong" )[0], event.currentTarget );
727                         equal( "keydown", event.type );
728                 }
729         });
730         // trigger events on both widget and descendent to ensure that only descendent receives them
731         widget = $( "<div><p><strong>hello</strong> world</p></div>" )
732                 .testWidget()
733                 .trigger( "keyup" )
734                 .trigger( "keydown" );
735         descendant = widget.find( "strong" )
736                 .trigger( "keyup" )
737                 .trigger( "keydown" );
738         widget
739                 .testWidget( "disable" )
740                 .trigger( "keyup" )
741                 .trigger( "keydown" );
742         descendant
743                 .trigger( "keyup" )
744                 .trigger( "keydown" );
745         widget
746                 .testWidget( "enable" )
747                 .trigger( "keyup" )
748                 .trigger( "keydown" );
749         descendant
750                 .trigger( "keyup" )
751                 .trigger( "keydown" );
752         descendant
753                 .addClass( "ui-state-disabled" )
754                 .trigger( "keyup" )
755                 .trigger( "keydown" );
756         widget
757                 .testWidget( "destroy" )
758                 .trigger( "keyup" )
759                 .trigger( "keydown" );
760         descendant
761                 .trigger( "keyup" )
762                 .trigger( "keydown" );
763 });
764
765 test( "_on() with delegate", function() {
766         expect( 8 );
767         $.widget( "ui.testWidget", {
768                 _create: function() {
769                         var uuid = this.uuid;
770                         this.element = {
771                                 bind: function( event, handler ) {
772                                         equal( event, "click.testWidget" + uuid );
773                                         ok( $.isFunction(handler) );
774                                 },
775                                 trigger: $.noop
776                         };
777                         this.widget = function() {
778                                 return {
779                                         delegate: function( selector, event, handler ) {
780                                                 equal( selector, "a" );
781                                                 equal( event, "click.testWidget" + uuid );
782                                                 ok( $.isFunction(handler) );
783                                         }
784                                 };
785                         };
786                         this._on({
787                                 "click": "handler",
788                                 "click a": "handler"
789                         });
790                         this.widget = function() {
791                                 return {
792                                         delegate: function( selector, event, handler ) {
793                                                 equal( selector, "form fieldset > input" );
794                                                 equal( event, "change.testWidget" + uuid );
795                                                 ok( $.isFunction(handler) );
796                                         }
797                                 };
798                         };
799                         this._on({
800                                 "change form fieldset > input": "handler"
801                         });
802                 }
803         });
804         $.ui.testWidget();
805 });
806
807 test( "_on() with delegate to descendent", function() {
808         expect( 4 );
809         $.widget( "ui.testWidget", {
810                 _create: function() {
811                         this.target = $( "<p><strong>hello</strong> world</p>" );
812                         this.child = this.target.children();
813                         this._on( this.target, {
814                                 "keyup": "handlerDirect",
815                                 "keyup strong": "handlerDelegated"
816                         });
817                         this.child.trigger( "keyup" );
818                 },
819                 handlerDirect: function( event ) {
820                         deepEqual( event.currentTarget, this.target[ 0 ] );
821                         deepEqual( event.target, this.child[ 0 ] );
822                 },
823                 handlerDelegated: function( event ) {
824                         deepEqual( event.currentTarget, this.child[ 0 ] );
825                         deepEqual( event.target, this.child[ 0 ] );
826                 }
827         });
828         $.ui.testWidget();
829 });
830
831 test( "_on() to common element", function() {
832         expect( 1 );
833         $.widget( "ui.testWidget", {
834                 _create: function() {
835                         this._on( this.document, {
836                                 "customevent": "_handler"
837                         });
838                 },
839                 _handler: function() {
840                         ok( true, "handler triggered" );
841                 }
842         });
843         var widget = $( "#widget" ).testWidget().data( "ui-testWidget" );
844         $( "#widget-wrapper" ).testWidget();
845         widget.destroy();
846         $( document ).trigger( "customevent" );
847 });
848
849 test( "_off() - single event", function() {
850         expect( 3 );
851
852         $.widget( "ui.testWidget", {} );
853         var shouldTriggerWidget, shouldTriggerOther,
854                 element = $( "#widget" ),
855                 widget = element.testWidget().data( "ui-testWidget" );
856         widget._on( element, { foo: function() {
857                 ok( shouldTriggerWidget, "foo called from _on" );
858         }});
859         element.bind( "foo", function() {
860                 ok( shouldTriggerOther, "foo called from bind" );
861         });
862         shouldTriggerWidget = true;
863         shouldTriggerOther = true;
864         element.trigger( "foo" );
865         shouldTriggerWidget = false;
866         widget._off( element, "foo" );
867         element.trigger( "foo" );
868 });
869
870 test( "_off() - multiple events", function() {
871         expect( 6 );
872
873         $.widget( "ui.testWidget", {} );
874         var shouldTriggerWidget, shouldTriggerOther,
875                 element = $( "#widget" ),
876                 widget = element.testWidget().data( "ui-testWidget" );
877         widget._on( element, {
878                 foo: function() {
879                         ok( shouldTriggerWidget, "foo called from _on" );
880                 },
881                 bar: function() {
882                         ok( shouldTriggerWidget, "bar called from _on" );
883                 }
884         });
885         element.bind( "foo bar", function( event ) {
886                 ok( shouldTriggerOther, event.type + " called from bind" );
887         });
888         shouldTriggerWidget = true;
889         shouldTriggerOther = true;
890         element.trigger( "foo" );
891         element.trigger( "bar" );
892         shouldTriggerWidget = false;
893         widget._off( element, "foo bar" );
894         element.trigger( "foo" );
895         element.trigger( "bar" );
896 });
897
898 test( "_off() - all events", function() {
899         expect( 6 );
900
901         $.widget( "ui.testWidget", {} );
902         var shouldTriggerWidget, shouldTriggerOther,
903                 element = $( "#widget" ),
904                 widget = element.testWidget().data( "ui-testWidget" );
905         widget._on( element, {
906                 foo: function() {
907                         ok( shouldTriggerWidget, "foo called from _on" );
908                 },
909                 bar: function() {
910                         ok( shouldTriggerWidget, "bar called from _on" );
911                 }
912         });
913         element.bind( "foo bar", function( event ) {
914                 ok( shouldTriggerOther, event.type + " called from bind" );
915         });
916         shouldTriggerWidget = true;
917         shouldTriggerOther = true;
918         element.trigger( "foo" );
919         element.trigger( "bar" );
920         shouldTriggerWidget = false;
921         widget._off( element );
922         element.trigger( "foo" );
923         element.trigger( "bar" );
924 });
925
926 test( "._hoverable()", function() {
927         expect( 10 );
928         $.widget( "ui.testWidget", {
929                 _create: function() {
930                         this._hoverable( this.element.children() );
931                 }
932         });
933
934         var div = $( "#widget" ).testWidget().children();
935         ok( !div.hasClass( "ui-state-hover" ), "not hovered on init" );
936         div.trigger( "mouseenter" );
937         ok( div.hasClass( "ui-state-hover" ), "hovered after mouseenter" );
938         div.trigger( "mouseleave" );
939         ok( !div.hasClass( "ui-state-hover" ), "not hovered after mouseleave" );
940
941         div.trigger( "mouseenter" );
942         ok( div.hasClass( "ui-state-hover" ), "hovered after mouseenter" );
943         $( "#widget" ).testWidget( "disable" );
944         ok( !div.hasClass( "ui-state-hover" ), "not hovered while disabled" );
945         div.trigger( "mouseenter" );
946         ok( !div.hasClass( "ui-state-hover" ), "can't hover while disabled" );
947         $( "#widget" ).testWidget( "enable" );
948         ok( !div.hasClass( "ui-state-hover" ), "enabling doesn't reset hover" );
949
950         div.trigger( "mouseenter" );
951         ok( div.hasClass( "ui-state-hover" ), "hovered after mouseenter" );
952         $( "#widget" ).testWidget( "destroy" );
953         ok( !div.hasClass( "ui-state-hover" ), "not hovered after destroy" );
954         div.trigger( "mouseenter" );
955         ok( !div.hasClass( "ui-state-hover" ), "event handler removed on destroy" );
956 });
957
958 test( "._focusable()", function() {
959         expect( 10 );
960         $.widget( "ui.testWidget", {
961                 _create: function() {
962                         this._focusable( this.element.children() );
963                 }
964         });
965
966         var div = $( "#widget" ).testWidget().children();
967         ok( !div.hasClass( "ui-state-focus" ), "not focused on init" );
968         div.trigger( "focusin" );
969         ok( div.hasClass( "ui-state-focus" ), "focused after explicit focus" );
970         div.trigger( "focusout" );
971         ok( !div.hasClass( "ui-state-focus" ), "not focused after blur" );
972
973         div.trigger( "focusin" );
974         ok( div.hasClass( "ui-state-focus" ), "focused after explicit focus" );
975         $( "#widget" ).testWidget( "disable" );
976         ok( !div.hasClass( "ui-state-focus" ), "not focused while disabled" );
977         div.trigger( "focusin" );
978         ok( !div.hasClass( "ui-state-focus" ), "can't focus while disabled" );
979         $( "#widget" ).testWidget( "enable" );
980         ok( !div.hasClass( "ui-state-focus" ), "enabling doesn't reset focus" );
981
982         div.trigger( "focusin" );
983         ok( div.hasClass( "ui-state-focus" ), "focused after explicit focus" );
984         $( "#widget" ).testWidget( "destroy" );
985         ok( !div.hasClass( "ui-state-focus" ), "not focused after destroy" );
986         div.trigger( "focusin" );
987         ok( !div.hasClass( "ui-state-focus" ), "event handler removed on destroy" );
988 });
989
990 test( "._trigger() - no event, no ui", function() {
991         expect( 7 );
992         var handlers = [];
993
994         $.widget( "ui.testWidget", {
995                 _create: function() {}
996         });
997
998         $( "#widget" ).testWidget({
999                 foo: function( event, ui ) {
1000                         deepEqual( event.type, "testwidgetfoo", "correct event type in callback" );
1001                         deepEqual( ui, {}, "empty ui hash passed" );
1002                         handlers.push( "callback" );
1003                 }
1004         });
1005         $( document ).add( "#widget-wrapper" ).add( "#widget" )
1006                 .bind( "testwidgetfoo", function( event, ui ) {
1007                         deepEqual( ui, {}, "empty ui hash passed" );
1008                         handlers.push( this );
1009                 });
1010         deepEqual( $( "#widget" ).data( "ui-testWidget" )._trigger( "foo" ), true,
1011                 "_trigger returns true when event is not cancelled" );
1012         deepEqual( handlers, [
1013                 $( "#widget" )[ 0 ],
1014                 $( "#widget-wrapper" )[ 0 ],
1015                 document,
1016                 "callback"
1017         ], "event bubbles and then invokes callback" );
1018
1019         $( document ).unbind( "testwidgetfoo" );
1020 });
1021
1022 test( "._trigger() - cancelled event", function() {
1023         expect( 3 );
1024
1025         $.widget( "ui.testWidget", {
1026                 _create: function() {}
1027         });
1028
1029         $( "#widget" ).testWidget({
1030                 foo: function() {
1031                         ok( true, "callback invoked even if event is cancelled" );
1032                 }
1033         })
1034         .bind( "testwidgetfoo", function() {
1035                 ok( true, "event was triggered" );
1036                 return false;
1037         });
1038         deepEqual( $( "#widget" ).data( "ui-testWidget" )._trigger( "foo" ), false,
1039                 "_trigger returns false when event is cancelled" );
1040 });
1041
1042 test( "._trigger() - cancelled callback", function() {
1043         expect( 1 );
1044         $.widget( "ui.testWidget", {
1045                 _create: function() {}
1046         });
1047
1048         $( "#widget" ).testWidget({
1049                 foo: function() {
1050                         return false;
1051                 }
1052         });
1053         deepEqual( $( "#widget" ).data( "ui-testWidget" )._trigger( "foo" ), false,
1054                 "_trigger returns false when callback returns false" );
1055 });
1056
1057 test( "._trigger() - provide event and ui", function() {
1058         expect( 7 );
1059
1060         var originalEvent = $.Event( "originalTest" );
1061         $.widget( "ui.testWidget", {
1062                 _create: function() {},
1063                 testEvent: function() {
1064                         var ui = {
1065                                         foo: "bar",
1066                                         baz: {
1067                                                 qux: 5,
1068                                                 quux: 20
1069                                         }
1070                                 };
1071                         this._trigger( "foo", originalEvent, ui );
1072                         deepEqual( ui, {
1073                                 foo: "notbar",
1074                                 baz: {
1075                                         qux: 10,
1076                                         quux: "jQuery"
1077                                 }
1078                         }, "ui object modified" );
1079                 }
1080         });
1081         $( "#widget" ).bind( "testwidgetfoo", function( event, ui ) {
1082                 equal( event.originalEvent, originalEvent, "original event object passed" );
1083                 deepEqual( ui, {
1084                         foo: "bar",
1085                         baz: {
1086                                 qux: 5,
1087                                 quux: 20
1088                         }
1089                 }, "ui hash passed" );
1090                 ui.foo = "notbar";
1091         });
1092         $( "#widget-wrapper" ).bind( "testwidgetfoo", function( event, ui ) {
1093                 equal( event.originalEvent, originalEvent, "original event object passed" );
1094                 deepEqual( ui, {
1095                         foo: "notbar",
1096                         baz: {
1097                                 qux: 5,
1098                                 quux: 20
1099                         }
1100                 }, "modified ui hash passed" );
1101                 ui.baz.qux = 10;
1102         });
1103         $( "#widget" ).testWidget({
1104                 foo: function( event, ui ) {
1105                         equal( event.originalEvent, originalEvent, "original event object passed" );
1106                         deepEqual( ui, {
1107                                 foo: "notbar",
1108                                 baz: {
1109                                         qux: 10,
1110                                         quux: 20
1111                                 }
1112                         }, "modified ui hash passed" );
1113                         ui.baz.quux = "jQuery";
1114                 }
1115         })
1116         .testWidget( "testEvent" );
1117 });
1118
1119 test( "._trigger() - array as ui", function() {
1120         // #6795 - Widget: handle array arguments to _trigger consistently
1121         expect( 4 );
1122
1123         $.widget( "ui.testWidget", {
1124                 _create: function() {},
1125                 testEvent: function() {
1126                         var ui = {
1127                                         foo: "bar",
1128                                         baz: {
1129                                                 qux: 5,
1130                                                 quux: 20
1131                                         }
1132                                 },
1133                                 extra = {
1134                                         bar: 5
1135                                 };
1136                         this._trigger( "foo", null, [ ui, extra ] );
1137                 }
1138         });
1139         $( "#widget" ).bind( "testwidgetfoo", function( event, ui, extra ) {
1140                 deepEqual( ui, {
1141                         foo: "bar",
1142                         baz: {
1143                                 qux: 5,
1144                                 quux: 20
1145                         }
1146                 }, "event: ui hash passed" );
1147                 deepEqual( extra, {
1148                         bar: 5
1149                 }, "event: extra argument passed" );
1150         });
1151         $( "#widget" ).testWidget({
1152                 foo: function( event, ui, extra ) {
1153                         deepEqual( ui, {
1154                                 foo: "bar",
1155                                 baz: {
1156                                         qux: 5,
1157                                         quux: 20
1158                                 }
1159                         }, "callback: ui hash passed" );
1160                         deepEqual( extra, {
1161                                 bar: 5
1162                         }, "callback: extra argument passed" );
1163                 }
1164         })
1165         .testWidget( "testEvent" );
1166 });
1167
1168 test( "._trigger() - instance as element", function() {
1169         expect( 4 );
1170         $.widget( "ui.testWidget", {
1171                 defaultElement: null,
1172                 testEvent: function() {
1173                         this._trigger( "foo", null, { foo: "bar" } );
1174                 }
1175         });
1176         var instance = $.ui.testWidget({
1177                 foo: function( event, ui ) {
1178                         equal( event.type, "testwidgetfoo", "event object passed to callback" );
1179                         deepEqual( ui, { foo: "bar" }, "ui object passed to callback" );
1180                 }
1181         });
1182         $( instance ).bind( "testwidgetfoo", function( event, ui ) {
1183                 equal( event.type, "testwidgetfoo", "event object passed to event handler" );
1184                 deepEqual( ui, { foo: "bar" }, "ui object passed to event handler" );
1185         });
1186         instance.testEvent();
1187 });
1188
1189 (function() {
1190         function shouldDestroy( expected, callback ) {
1191                 expect( 1 );
1192                 var destroyed = false;
1193                 $.widget( "ui.testWidget", {
1194                         _create: function() {},
1195                         destroy: function() {
1196                                 destroyed = true;
1197                         }
1198                 });
1199                 callback();
1200                 equal( destroyed, expected );
1201         }
1202
1203         test( "auto-destroy - .remove()", function() {
1204                 shouldDestroy( true, function() {
1205                         $( "#widget" ).testWidget().remove();
1206                 });
1207         });
1208
1209         test( "auto-destroy - .remove() when disabled", function() {
1210                 shouldDestroy( true, function() {
1211                         $( "#widget" ).testWidget({ disabled: true }).remove();
1212                 });
1213         });
1214
1215         test( "auto-destroy - .remove() on parent", function() {
1216                 shouldDestroy( true, function() {
1217                         $( "#widget" ).testWidget().parent().remove();
1218                 });
1219         });
1220
1221         test( "auto-destroy - .remove() on child", function() {
1222                 shouldDestroy( false, function() {
1223                         $( "#widget" ).testWidget().children().remove();
1224                 });
1225         });
1226
1227         test( "auto-destroy - .empty()", function() {
1228                 shouldDestroy( false, function() {
1229                         $( "#widget" ).testWidget().empty();
1230                 });
1231         });
1232
1233         test( "auto-destroy - .empty() on parent", function() {
1234                 shouldDestroy( true, function() {
1235                         $( "#widget" ).testWidget().parent().empty();
1236                 });
1237         });
1238
1239         test( "auto-destroy - .detach()", function() {
1240                 shouldDestroy( false, function() {
1241                         $( "#widget" ).testWidget().detach();
1242                 });
1243         });
1244
1245         test( "destroy - remove event bubbling", function() {
1246                 shouldDestroy( false, function() {
1247                         $( "<div>child</div>" ).appendTo( $( "#widget" ).testWidget() )
1248                                 .trigger( "remove" );
1249                 });
1250         });
1251 }());
1252
1253 test( "redefine", function() {
1254         expect( 4 );
1255         $.widget( "ui.testWidget", {
1256                 method: function( str ) {
1257                         strictEqual( this, instance, "original invoked with correct this" );
1258                         equal( str, "bar", "original invoked with correct parameter" );
1259                 }
1260         });
1261         $.ui.testWidget.foo = "bar";
1262         $.widget( "ui.testWidget", $.ui.testWidget, {
1263                 method: function( str ) {
1264                         equal( str, "foo", "new invoked with correct parameter" );
1265                         this._super( "bar" );
1266                 }
1267         });
1268
1269         var instance = new $.ui.testWidget({});
1270         instance.method( "foo" );
1271         equal( $.ui.testWidget.foo, "bar", "static properties remain" );
1272 });
1273
1274 test( "redefine deep prototype chain", function() {
1275         expect( 8 );
1276         $.widget( "ui.testWidget", {
1277                 method: function( str ) {
1278                         strictEqual( this, instance, "original invoked with correct this" );
1279                         equal( str, "level 4", "original invoked with correct parameter" );
1280                 }
1281         });
1282         $.widget( "ui.testWidget2", $.ui.testWidget, {
1283                 method: function( str ) {
1284                         strictEqual( this, instance, "testWidget2 invoked with correct this" );
1285                         equal( str, "level 2", "testWidget2 invoked with correct parameter" );
1286                         this._super( "level 3" );
1287                 }
1288         });
1289         $.widget( "ui.testWidget3", $.ui.testWidget2, {
1290                 method: function( str ) {
1291                         strictEqual( this, instance, "testWidget3 invoked with correct this" );
1292                         equal( str, "level 1", "testWidget3 invoked with correct parameter" );
1293                         this._super( "level 2" );
1294                 }
1295         });
1296         // redefine testWidget after other widgets have inherited from it
1297         // this tests whether the inheriting widgets get updated prototype chains
1298         $.widget( "ui.testWidget", $.ui.testWidget, {
1299                 method: function( str ) {
1300                         strictEqual( this, instance, "new invoked with correct this" );
1301                         equal( str, "level 3", "new invoked with correct parameter" );
1302                         this._super( "level 4" );
1303                 }
1304         });
1305         // redefine testWidget3 after it has been automatically redefined
1306         // this tests whether we properly handle _super() when the topmost prototype
1307         // doesn't have the method defined
1308         $.widget( "ui.testWidget3", $.ui.testWidget3, {} );
1309
1310         var instance = new $.ui.testWidget3({});
1311         instance.method( "level 1" );
1312
1313         delete $.ui.testWidget3;
1314         delete $.ui.testWidget2;
1315 });
1316
1317 test( "redefine - widgetEventPrefix", function() {
1318         expect( 2 );
1319
1320         $.widget( "ui.testWidget", {
1321                 widgetEventPrefix: "test"
1322         });
1323         equal( $.ui.testWidget.prototype.widgetEventPrefix, "test",
1324                 "cusotm prefix in original" );
1325
1326         $.widget( "ui.testWidget", $.ui.testWidget, {} );
1327         equal( $.ui.testWidget.prototype.widgetEventPrefix, "test",
1328                 "cusotm prefix in extension" );
1329
1330 });
1331
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
1360 asyncTest( "_delay", function() {
1361         expect( 6 );
1362         var order = 0,
1363                 that;
1364         $.widget( "ui.testWidget", {
1365                 defaultElement: null,
1366                 _create: function() {
1367                         that = this;
1368                         var timer = this._delay(function() {
1369                                 strictEqual( this, that );
1370                                 equal( order, 1 );
1371                                 start();
1372                         }, 500);
1373                         ok( timer !== undefined );
1374                         timer = this._delay("callback");
1375                         ok( timer !== undefined );
1376                 },
1377                 callback: function() {
1378                         strictEqual( this, that );
1379                         equal( order, 0 );
1380                         order += 1;
1381                 }
1382         });
1383         $( "#widget" ).testWidget();
1384 });
1385
1386 test( "$.widget.bridge()", function() {
1387         expect( 9 );
1388
1389         var instance, ret,
1390                 elem = $( "<div>" );
1391
1392         function TestWidget( options, element ) {
1393                 deepEqual( options, { foo: "bar" }, "options passed" );
1394                 strictEqual( element, elem[ 0 ], "element passed" );
1395         }
1396
1397         $.extend( TestWidget.prototype, {
1398                 method: function( param ) {
1399                         ok( true, "method called via .pluginName(methodName)" );
1400                         equal( param, "value1",
1401                                 "parameter passed via .pluginName(methodName, param)" );
1402                 },
1403                 getter: function() {
1404                         return "qux";
1405                 }
1406         });
1407
1408         $.widget.bridge( "testWidget", TestWidget );
1409
1410         ok( $.isFunction( $.fn.testWidget ), "jQuery plugin was created" );
1411
1412         strictEqual( elem.testWidget({ foo: "bar" }), elem, "plugin returns original jQuery object" );
1413         instance = elem.data( "testWidget" );
1414         equal( typeof instance, "object", "instance stored in .data(pluginName)" );
1415
1416         ret = elem.testWidget( "method", "value1" );
1417         equal( ret, elem, "jQuery object returned from method call" );
1418
1419         ret = elem.testWidget( "getter" );
1420         equal( ret, "qux", "getter returns value" );
1421 });
1422
1423 test( "$.widget.bridge() - widgetFullName", function() {
1424         expect( 1 );
1425
1426         var instance,
1427                 elem = $( "<div>" );
1428
1429         function TestWidget() {}
1430         TestWidget.prototype.widgetFullName = "custom-widget";
1431         $.widget.bridge( "testWidget", TestWidget );
1432
1433         elem.testWidget();
1434         instance = elem.data( "custom-widget" );
1435         equal( typeof instance, "object", "instance stored in .data(widgetFullName)" );
1436 });
1437
1438 }( jQuery ) );