summaryrefslogtreecommitdiffstats
path: root/apps/it/static/js/ui/tests/unit
diff options
context:
space:
mode:
authorFilipp Lepalaan <f@230.to>2014-02-19 18:02:09 +0200
committerFilipp Lepalaan <f@230.to>2014-02-19 18:02:09 +0200
commit75ad7e4bd7d69243e7e5281c2642f00478fb072d (patch)
treeeaaaf360902d369f42d94778aac8803db7973ce0 /apps/it/static/js/ui/tests/unit
parentcfc7c3f52544af8a71d3fa3988a06fee200d2c24 (diff)
downloadpudding-75ad7e4bd7d69243e7e5281c2642f00478fb072d.tar.gz
pudding-75ad7e4bd7d69243e7e5281c2642f00478fb072d.tar.bz2
pudding-75ad7e4bd7d69243e7e5281c2642f00478fb072d.zip
Added tags, jquery UI
Diffstat (limited to 'apps/it/static/js/ui/tests/unit')
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/accordion.html143
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/accordion_common.js20
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/accordion_core.js117
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/accordion_events.js169
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/accordion_methods.js126
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/accordion_options.js463
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/accordion_test_helpers.js27
-rw-r--r--apps/it/static/js/ui/tests/unit/accordion/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/all.html70
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/autocomplete.html49
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_common.js29
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_core.js270
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_events.js182
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_methods.js45
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_options.js278
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_labels.txt1
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_values.txt1
-rw-r--r--apps/it/static/js/ui/tests/unit/autocomplete/remote_string_array.txt1
-rw-r--r--apps/it/static/js/ui/tests/unit/button/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/button/button.html78
-rw-r--r--apps/it/static/js/ui/tests/unit/button/button_common.js14
-rw-r--r--apps/it/static/js/ui/tests/unit/button/button_core.js212
-rw-r--r--apps/it/static/js/ui/tests/unit/button/button_events.js36
-rw-r--r--apps/it/static/js/ui/tests/unit/button/button_methods.js52
-rw-r--r--apps/it/static/js/ui/tests/unit/button/button_options.js117
-rw-r--r--apps/it/static/js/ui/tests/unit/core/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/core/core.html135
-rw-r--r--apps/it/static/js/ui/tests/unit/core/core.js191
-rw-r--r--apps/it/static/js/ui/tests/unit/core/selector.js251
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/datepicker.html48
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/datepicker_common.js7
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/datepicker_core.js524
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/datepicker_events.js153
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/datepicker_methods.js125
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/datepicker_options.js1113
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/datepicker_test_helpers.js37
-rw-r--r--apps/it/static/js/ui/tests/unit/datepicker/images/calendar.gifbin0 -> 269 bytes
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog.html71
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_common.js43
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_core.js163
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.html67
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.js63
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_events.js370
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_methods.js252
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_options.js584
-rw-r--r--apps/it/static/js/ui/tests/unit/dialog/dialog_test_helpers.js44
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/draggable.html58
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/draggable_common.js40
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/draggable_core.js168
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/draggable_events.js125
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/draggable_methods.js99
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/draggable_options.js1404
-rw-r--r--apps/it/static/js/ui/tests/unit/draggable/draggable_test_helpers.js79
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/droppable.html50
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/droppable_common.js20
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/droppable_core.js29
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/droppable_events.js63
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/droppable_methods.js88
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/droppable_options.js67
-rw-r--r--apps/it/static/js/ui/tests/unit/droppable/droppable_test_helpers.js10
-rw-r--r--apps/it/static/js/ui/tests/unit/effects/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/effects/effects.html117
-rw-r--r--apps/it/static/js/ui/tests/unit/effects/effects_core.js274
-rw-r--r--apps/it/static/js/ui/tests/unit/effects/effects_scale.js68
-rw-r--r--apps/it/static/js/ui/tests/unit/images/jqueryui_32x32.pngbin0 -> 1193 bytes
-rw-r--r--apps/it/static/js/ui/tests/unit/index.html66
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/menu.html269
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/menu_common.js20
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/menu_core.js48
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/menu_events.js637
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/menu_methods.js117
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/menu_options.js115
-rw-r--r--apps/it/static/js/ui/tests/unit/menu/menu_test_helpers.js31
-rw-r--r--apps/it/static/js/ui/tests/unit/position/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/position/position.html53
-rw-r--r--apps/it/static/js/ui/tests/unit/position/position_core.js729
-rw-r--r--apps/it/static/js/ui/tests/unit/progressbar/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/progressbar/progressbar.html44
-rw-r--r--apps/it/static/js/ui/tests/unit/progressbar/progressbar_common.js12
-rw-r--r--apps/it/static/js/ui/tests/unit/progressbar/progressbar_core.js53
-rw-r--r--apps/it/static/js/ui/tests/unit/progressbar/progressbar_events.js51
-rw-r--r--apps/it/static/js/ui/tests/unit/progressbar/progressbar_methods.js25
-rw-r--r--apps/it/static/js/ui/tests/unit/progressbar/progressbar_options.js72
-rw-r--r--apps/it/static/js/ui/tests/unit/qunit-composite.css13
-rw-r--r--apps/it/static/js/ui/tests/unit/qunit-composite.js112
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/images/test.jpgbin0 -> 391 bytes
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/resizable.html65
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/resizable_common.js30
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/resizable_core.js209
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/resizable_events.js220
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/resizable_methods.js12
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/resizable_options.js291
-rw-r--r--apps/it/static/js/ui/tests/unit/resizable/resizable_test_helpers.js11
-rw-r--r--apps/it/static/js/ui/tests/unit/selectable/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/selectable/selectable.html51
-rw-r--r--apps/it/static/js/ui/tests/unit/selectable/selectable_common.js21
-rw-r--r--apps/it/static/js/ui/tests/unit/selectable/selectable_core.js3
-rw-r--r--apps/it/static/js/ui/tests/unit/selectable/selectable_events.js69
-rw-r--r--apps/it/static/js/ui/tests/unit/selectable/selectable_methods.js104
-rw-r--r--apps/it/static/js/ui/tests/unit/selectable/selectable_options.js65
-rw-r--r--apps/it/static/js/ui/tests/unit/slider/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/slider/slider.html48
-rw-r--r--apps/it/static/js/ui/tests/unit/slider/slider_common.js23
-rw-r--r--apps/it/static/js/ui/tests/unit/slider/slider_core.js297
-rw-r--r--apps/it/static/js/ui/tests/unit/slider/slider_events.js152
-rw-r--r--apps/it/static/js/ui/tests/unit/slider/slider_methods.js96
-rw-r--r--apps/it/static/js/ui/tests/unit/slider/slider_options.js317
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/sortable.html99
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/sortable_common.js45
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/sortable_core.js3
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/sortable_events.js275
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/sortable_methods.js92
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/sortable_options.js460
-rw-r--r--apps/it/static/js/ui/tests/unit/sortable/sortable_test_helpers.js9
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/spinner.html50
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/spinner_common.js23
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/spinner_core.js238
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/spinner_events.js259
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/spinner_methods.js174
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/spinner_options.js262
-rw-r--r--apps/it/static/js/ui/tests/unit/spinner/spinner_test_helpers.js8
-rw-r--r--apps/it/static/js/ui/tests/unit/subsuite.js25
-rw-r--r--apps/it/static/js/ui/tests/unit/swarminject.js10
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/data/test.html1
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/tabs.html155
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/tabs_common.js18
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/tabs_core.js615
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/tabs_events.js318
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/tabs_methods.js270
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/tabs_options.js345
-rw-r--r--apps/it/static/js/ui/tests/unit/tabs/tabs_test_helpers.js67
-rw-r--r--apps/it/static/js/ui/tests/unit/testsuite.js298
-rw-r--r--apps/it/static/js/ui/tests/unit/tooltip/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/tooltip/tooltip.html55
-rw-r--r--apps/it/static/js/ui/tests/unit/tooltip/tooltip_common.js21
-rw-r--r--apps/it/static/js/ui/tests/unit/tooltip/tooltip_core.js137
-rw-r--r--apps/it/static/js/ui/tests/unit/tooltip/tooltip_events.js57
-rw-r--r--apps/it/static/js/ui/tests/unit/tooltip/tooltip_methods.js94
-rw-r--r--apps/it/static/js/ui/tests/unit/tooltip/tooltip_options.js171
-rw-r--r--apps/it/static/js/ui/tests/unit/widget/all.html30
-rw-r--r--apps/it/static/js/ui/tests/unit/widget/widget.html44
-rw-r--r--apps/it/static/js/ui/tests/unit/widget/widget_animation.js257
-rw-r--r--apps/it/static/js/ui/tests/unit/widget/widget_core.js1459
-rw-r--r--apps/it/static/js/ui/tests/unit/widget/widget_extend.js105
154 files changed, 21170 insertions, 0 deletions
diff --git a/apps/it/static/js/ui/tests/unit/accordion/accordion.html b/apps/it/static/js/ui/tests/unit/accordion/accordion.html
new file mode 100644
index 0000000..67928fd
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/accordion.html
@@ -0,0 +1,143 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Accordion Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.accordion" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.accordion.js"
+ ]
+ });
+ </script>
+
+ <script src="accordion_test_helpers.js"></script>
+ <script src="accordion_common.js"></script>
+ <script src="accordion_core.js"></script>
+ <script src="accordion_events.js"></script>
+ <script src="accordion_methods.js"></script>
+ <script src="accordion_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+ <style>
+ #list, #list1 *, #navigation, #navigation * {
+ margin: 0;
+ padding: 0;
+ font-size: 12px;
+ line-height: 15px;
+ }
+ /* avoid IE7 oscillating between overflow visible and scroll values */
+ #list1 > div {
+ overflow: visible;
+ }
+ </style>
+</head>
+<body>
+<h1 id="qunit-header">jQuery UI Accordion Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="list1" class="foo">
+ <h3 class="bar">There is one obvious advantage:</h3>
+ <div class="foo">
+ <p>
+ You've seen it coming!
+ <br>
+ Buy now and get nothing for free!
+ <br>
+ Well, at least no free beer. Perhaps a bear, if you can afford it.
+ </p>
+ </div>
+ <h3 class="bar">Now that you've got...</h3>
+ <div class="foo">
+ <p>
+ your bear, you have to admit it!
+ <br>
+ No, we aren't <a href="#">selling bears</a>.
+ </p>
+ <p>
+ We could talk about renting one.
+ </p>
+ </div>
+ <h3 class="bar">Rent one bear, ...</h3>
+ <div class="foo">
+ <p>
+ get two for three beer.
+ </p>
+ <p>
+ And now, for something completely different.
+ </p>
+ </div>
+</div>
+
+<div id="navigationWrapper">
+ <ul id="navigation">
+ <li>
+ <h2><a href="?p=1.1.1">Guitar</a></h2>
+ <ul>
+ <li><a href="?p=1.1.1.1">Electric</a></li>
+ <li><a href="?p=1.1.1.2">Acoustic</a></li>
+ <li><a href="?p=1.1.1.3">Amps</a></li>
+ <li><a href="?p=1.1.1.4">Effects</a></li>
+ <li><a href="?p=1.1.1.5">Accessories</a></li>
+ </ul>
+ </li>
+ <li>
+ <h2><a href="?p=1.1.2"><span>Bass</span></a></h2>
+ <ul>
+ <li><a href="?p=1.1.2.1">Electric</a></li>
+ <li><a href="?p=1.1.2.2">Acoustic</a></li>
+ <li><a href="?p=1.1.2.3">Amps</a></li>
+ <li><a href="?p=1.1.2.4">Effects</a></li>
+ <li><a href="?p=1.1.2.5">Accessories</a></li>
+ <li><a href="?p=1.1.2.5">Accessories</a></li>
+ <li><a href="?p=1.1.2.5">Accessories</a></li>
+ </ul>
+ </li>
+ <li>
+ <h2><a href="?p=1.1.3">Drums</a></h2>
+ <ul>
+ <li><a href="?p=1.1.3.2">Acoustic</a></li>
+ <li><a href="?p=1.1.3.3">Electronic</a></li>
+ <li><a href="?p=1.1.3.6">Accessories</a></li>
+ </ul>
+ </li>
+ </ul>
+</div>
+
+<dl id="accordion-dl">
+ <dt>
+ Accordion Header 1
+ </dt>
+ <dd>
+ Accordion Content 1
+ </dd>
+ <dt>
+ Accordion Header 2
+ </dt>
+ <dd>
+ Accordion Content 2
+ </dd>
+ <dt>
+ Accordion Header 3
+ </dt>
+ <dd>
+ Accordion Content 3
+ </dd>
+</dl>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/accordion/accordion_common.js b/apps/it/static/js/ui/tests/unit/accordion/accordion_common.js
new file mode 100644
index 0000000..ef24cf2
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/accordion_common.js
@@ -0,0 +1,20 @@
+TestHelpers.commonWidgetTests( "accordion", {
+ defaults: {
+ active: 0,
+ animate: {},
+ collapsible: false,
+ disabled: false,
+ event: "click",
+ header: "> li > :first-child,> :not(li):even",
+ heightStyle: "auto",
+ icons: {
+ "activeHeader": "ui-icon-triangle-1-s",
+ "header": "ui-icon-triangle-1-e"
+ },
+
+ // callbacks
+ activate: null,
+ beforeActivate: null,
+ create: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/accordion/accordion_core.js b/apps/it/static/js/ui/tests/unit/accordion/accordion_core.js
new file mode 100644
index 0000000..8e0175a
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/accordion_core.js
@@ -0,0 +1,117 @@
+(function( $ ) {
+
+var setupTeardown = TestHelpers.accordion.setupTeardown,
+ state = TestHelpers.accordion.state;
+
+module( "accordion: core", setupTeardown() );
+
+$.each( { div: "#list1", ul: "#navigation", dl: "#accordion-dl" }, function( type, selector ) {
+ test( "markup structure: " + type, function() {
+ expect( 4 );
+ var element = $( selector ).accordion();
+ ok( element.hasClass( "ui-accordion" ), "main element is .ui-accordion" );
+ equal( element.find( ".ui-accordion-header" ).length, 3,
+ ".ui-accordion-header elements exist, correct number" );
+ equal( element.find( ".ui-accordion-content" ).length, 3,
+ ".ui-accordion-content elements exist, correct number" );
+ deepEqual( element.find( ".ui-accordion-header" ).next().get(),
+ element.find( ".ui-accordion-content" ).get(),
+ "content panels come immediately after headers" );
+ });
+});
+
+test( "handle click on header-descendant", function() {
+ expect( 1 );
+ var element = $( "#navigation" ).accordion();
+ $( "#navigation h2:eq(1) a" ).click();
+ state( element, 0, 1, 0 );
+});
+
+test( "accessibility", function () {
+ expect( 37 );
+ var element = $( "#list1" ).accordion({
+ active: 1
+ }),
+ headers = element.find( ".ui-accordion-header" );
+
+ equal( element.attr( "role" ), "tablist", "element role" );
+ headers.each(function( i ) {
+ var header = headers.eq( i ),
+ panel = header.next();
+ equal( header.attr( "role" ), "tab", "header " + i + " role" );
+ equal( header.attr( "aria-controls" ), panel.attr( "id" ), "header " + i + " aria-controls" );
+ equal( panel.attr( "role" ), "tabpanel", "panel " + i + " role" );
+ equal( panel.attr( "aria-labelledby" ), header.attr( "id" ), "panel " + i + " aria-labelledby" );
+ });
+
+ equal( headers.eq( 1 ).attr( "tabindex" ), 0, "active header has tabindex=0" );
+ equal( headers.eq( 1 ).attr( "aria-selected" ), "true", "active tab has aria-selected=true" );
+ equal( headers.eq( 1 ).attr( "aria-expanded" ), "true", "active tab has aria-expanded=true" );
+ equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "false", "active tabpanel has aria-hidden=false" );
+ equal( headers.eq( 0 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" );
+ equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" );
+ equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" );
+ equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" );
+ equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" );
+ equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" );
+
+ element.accordion( "option", "active", 0 );
+ equal( headers.eq( 0 ).attr( "tabindex" ), 0, "active header has tabindex=0" );
+ equal( headers.eq( 0 ).attr( "aria-selected" ), "true", "active tab has aria-selected=true" );
+ equal( headers.eq( 0 ).attr( "aria-expanded" ), "true", "active tab has aria-expanded=true" );
+ equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "false", "active tabpanel has aria-hidden=false" );
+ equal( headers.eq( 1 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" );
+ equal( headers.eq( 1 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( headers.eq( 1 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" );
+ equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" );
+ equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" );
+ equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" );
+ equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" );
+});
+
+asyncTest( "keyboard support", function() {
+ expect( 13 );
+ var element = $( "#list1" ).accordion(),
+ headers = element.find( ".ui-accordion-header" ),
+ anchor = headers.eq( 1 ).next().find( "a" ).eq( 0 ),
+ keyCode = $.ui.keyCode;
+ equal( headers.filter( ".ui-state-focus" ).length, 0, "no headers focused on init" );
+ headers.eq( 0 ).simulate( "focus" );
+ setTimeout(function() {
+ ok( headers.eq( 0 ).is( ".ui-state-focus" ), "first header has focus" );
+ headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN } );
+ ok( headers.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next header" );
+ headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.RIGHT } );
+ ok( headers.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next header" );
+ headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.DOWN } );
+ ok( headers.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first header" );
+
+ headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.UP } );
+ ok( headers.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last header" );
+ headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.LEFT } );
+ ok( headers.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous header" );
+
+ headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.HOME } );
+ ok( headers.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first header" );
+ headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.END } );
+ ok( headers.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last header" );
+
+ headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.ENTER } );
+ equal( element.accordion( "option", "active" ) , 2, "ENTER activates panel" );
+ headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.SPACE } );
+ equal( element.accordion( "option", "active" ), 1, "SPACE activates panel" );
+
+ anchor.simulate( "focus" );
+ setTimeout(function() {
+ ok( !headers.eq( 1 ).is( ".ui-state-focus" ), "header loses focus when focusing inside the panel" );
+ anchor.simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } );
+ ok( headers.eq( 1 ).is( ".ui-state-focus" ), "CTRL+UP moves focus to header" );
+ start();
+ }, 1 );
+ }, 1 );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/accordion/accordion_events.js b/apps/it/static/js/ui/tests/unit/accordion/accordion_events.js
new file mode 100644
index 0000000..79283d1
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/accordion_events.js
@@ -0,0 +1,169 @@
+(function( $ ) {
+
+var setupTeardown = TestHelpers.accordion.setupTeardown,
+ state = TestHelpers.accordion.state;
+
+module( "accordion: events", setupTeardown() );
+
+test( "create", function() {
+ expect( 15 );
+
+ var element = $( "#list1" ),
+ headers = element.children( "h3" ),
+ contents = headers.next();
+
+ element.accordion({
+ create: function( event, ui ) {
+ equal( ui.header.length, 1, "header length" );
+ strictEqual( ui.header[ 0 ], headers[ 0 ], "header" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], contents[ 0 ], "panel" );
+ equal( ui.content.length, 1, "content length" );
+ strictEqual( ui.content[ 0 ], contents[ 0 ], "content" );
+ }
+ });
+ element.accordion( "destroy" );
+
+ element.accordion({
+ active: 2,
+ create: function( event, ui ) {
+ equal( ui.header.length, 1, "header length" );
+ strictEqual( ui.header[ 0 ], headers[ 2 ], "header" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], contents[ 2 ], "panel" );
+ equal( ui.content.length, 1, "content length" );
+ strictEqual( ui.content[ 0 ], contents[ 2 ], "content" );
+ }
+ });
+ element.accordion( "destroy" );
+
+ element.accordion({
+ active: false,
+ collapsible: true,
+ create: function( event, ui ) {
+ equal( ui.header.length, 0, "header length" );
+ equal( ui.panel.length, 0, "panel length" );
+ equal( ui.content.length, 0, "content length" );
+ }
+ });
+ element.accordion( "destroy" );
+});
+
+test( "beforeActivate", function() {
+ expect( 38 );
+ var element = $( "#list1" ).accordion({
+ active: false,
+ collapsible: true
+ }),
+ headers = element.find( ".ui-accordion-header" ),
+ content = element.find( ".ui-accordion-content" );
+
+ element.one( "accordionbeforeactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ) );
+ equal( ui.oldHeader.length, 0 );
+ equal( ui.oldPanel.length, 0 );
+ equal( ui.newHeader.length, 1 );
+ strictEqual( ui.newHeader[ 0 ], headers[ 0 ] );
+ equal( ui.newPanel.length, 1 );
+ strictEqual( ui.newPanel[ 0 ], content[ 0 ] );
+ state( element, 0, 0, 0 );
+ });
+ element.accordion( "option", "active", 0 );
+ state( element, 1, 0, 0 );
+
+ element.one( "accordionbeforeactivate", function( event, ui ) {
+ equal( event.originalEvent.type, "click" );
+ equal( ui.oldHeader.length, 1 );
+ strictEqual( ui.oldHeader[ 0 ], headers[ 0 ] );
+ equal( ui.oldPanel.length, 1 );
+ strictEqual( ui.oldPanel[ 0 ], content[ 0 ] );
+ equal( ui.newHeader.length, 1 );
+ strictEqual( ui.newHeader[ 0 ], headers[ 1 ] );
+ equal( ui.newPanel.length, 1 );
+ strictEqual( ui.newPanel[ 0 ], content[ 1 ] );
+ state( element, 1, 0, 0 );
+ });
+ headers.eq( 1 ).click();
+ state( element, 0, 1, 0 );
+
+ element.one( "accordionbeforeactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ) );
+ equal( ui.oldHeader.length, 1 );
+ strictEqual( ui.oldHeader[ 0 ], headers[ 1 ] );
+ equal( ui.oldPanel.length, 1 );
+ strictEqual( ui.oldPanel[ 0 ], content[ 1 ] );
+ equal( ui.newHeader.length, 0 );
+ equal( ui.newPanel.length, 0 );
+ state( element, 0, 1, 0 );
+ });
+ element.accordion( "option", "active", false );
+ state( element, 0, 0, 0 );
+
+ element.one( "accordionbeforeactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ) );
+ equal( ui.oldHeader.length, 0 );
+ equal( ui.oldPanel.length, 0 );
+ equal( ui.newHeader.length, 1 );
+ strictEqual( ui.newHeader[ 0 ], headers[ 2 ] );
+ equal( ui.newPanel.length, 1 );
+ strictEqual( ui.newPanel[ 0 ], content[ 2 ] );
+ event.preventDefault();
+ state( element, 0, 0, 0 );
+ });
+ element.accordion( "option", "active", 2 );
+ state( element, 0, 0, 0 );
+});
+
+test( "activate", function() {
+ expect( 21 );
+ var element = $( "#list1" ).accordion({
+ active: false,
+ collapsible: true
+ }),
+ headers = element.find( ".ui-accordion-header" ),
+ content = element.find( ".ui-accordion-content" );
+
+ element.one( "accordionactivate", function( event, ui ) {
+ equal( ui.oldHeader.length, 0 );
+ equal( ui.oldPanel.length, 0 );
+ equal( ui.newHeader.length, 1 );
+ strictEqual( ui.newHeader[ 0 ], headers[ 0 ] );
+ equal( ui.newPanel.length, 1 );
+ strictEqual( ui.newPanel[ 0 ], content[ 0 ] );
+ });
+ element.accordion( "option", "active", 0 );
+
+ element.one( "accordionactivate", function( event, ui ) {
+ equal( ui.oldHeader.length, 1 );
+ strictEqual( ui.oldHeader[ 0 ], headers[ 0 ] );
+ equal( ui.oldPanel.length, 1 );
+ strictEqual( ui.oldPanel[ 0 ], content[ 0 ] );
+ equal( ui.newHeader.length, 1 );
+ strictEqual( ui.newHeader[ 0 ], headers[ 1 ] );
+ equal( ui.newPanel.length, 1 );
+ strictEqual( ui.newPanel[ 0 ], content[ 1 ] );
+ });
+ headers.eq( 1 ).click();
+
+ element.one( "accordionactivate", function( event, ui ) {
+ equal( ui.oldHeader.length, 1 );
+ strictEqual( ui.oldHeader[ 0 ], headers[ 1 ] );
+ equal( ui.oldPanel.length, 1 );
+ strictEqual( ui.oldPanel[ 0 ], content[ 1 ] );
+ equal( ui.newHeader.length, 0 );
+ equal( ui.newPanel.length, 0 );
+ });
+ element.accordion( "option", "active", false );
+
+ // prevent activation
+ element.one( "accordionbeforeactivate", function( event ) {
+ ok( true );
+ event.preventDefault();
+ });
+ element.one( "accordionactivate", function() {
+ ok( false );
+ });
+ element.accordion( "option", "active", 1 );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/accordion/accordion_methods.js b/apps/it/static/js/ui/tests/unit/accordion/accordion_methods.js
new file mode 100644
index 0000000..f81bd6d
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/accordion_methods.js
@@ -0,0 +1,126 @@
+(function( $ ) {
+
+var equalHeight = TestHelpers.accordion.equalHeight,
+ setupTeardown = TestHelpers.accordion.setupTeardown,
+ state = TestHelpers.accordion.state;
+
+module( "accordion: methods", setupTeardown() );
+
+test( "destroy", function() {
+ expect( 1 );
+ domEqual( "#list1", function() {
+ $( "#list1" ).accordion().accordion( "destroy" );
+ });
+});
+
+test( "enable/disable", function() {
+ expect( 4 );
+ var element = $( "#list1" ).accordion();
+ state( element, 1, 0, 0 );
+ element.accordion( "disable" );
+ // event does nothing
+ element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "click" );
+ state( element, 1, 0, 0 );
+ // option still works
+ element.accordion( "option", "active", 1 );
+ state( element, 0, 1, 0 );
+ element.accordion( "enable" );
+ element.accordion( "option", "active", 2 );
+ state( element, 0, 0, 1 );
+});
+
+test( "refresh", function() {
+ expect( 19 );
+ var element = $( "#navigation" )
+ .parent()
+ .height( 300 )
+ .end()
+ .accordion({
+ heightStyle: "fill"
+ });
+ equalHeight( element, 255 );
+
+ element.parent().height( 500 );
+ element.accordion( "refresh" );
+ equalHeight( element, 455 );
+
+ element = $( "#list1" );
+ element.accordion();
+ state( element, 1, 0, 0 );
+
+ // disable panel via markup
+ element.find( "h3.bar" ).eq( 1 ).addClass( "ui-state-disabled" );
+ element.accordion( "refresh" );
+ state( element, 1, 0, 0 );
+
+ // don't add multiple icons
+ element.accordion( "refresh" );
+ equal( element.find( ".ui-accordion-header-icon" ).length, 3 );
+
+ // add a panel
+ element
+ .append("<h3 class='bar' id='new_1'>new 1</h3>")
+ .append("<div class='foo' id='new_1_panel'>new 1</div>");
+ element.accordion( "refresh" );
+ state( element, 1, 0, 0, 0 );
+
+ // remove all tabs
+ element.find( "h3.bar, div.foo" ).remove();
+ element.accordion( "refresh" );
+ state( element );
+ equal( element.accordion( "option", "active" ), false, "no active accordion panel" );
+
+ // add panels
+ element
+ .append("<h3 class='bar' id='new_2'>new 2</h3>")
+ .append("<div class='foo' id='new_2_panel'>new 2</div>")
+ .append("<h3 class='bar' id='new_3'>new 3</h3>")
+ .append("<div class='foo' id='new_3_panel'>new 3</div>")
+ .append("<h3 class='bar' id='new_4'>new 4</h3>")
+ .append("<div class='foo' id='new_4_panel'>new 4</div>")
+ .append("<h3 class='bar' id='new_5'>new 5</h3>")
+ .append("<div class='foo' id='new_5_panel'>new 5</div>");
+ element.accordion( "refresh" );
+ state( element, 1, 0, 0, 0 );
+
+ // activate third tab
+ element.accordion( "option", "active", 2 );
+ state( element, 0, 0, 1, 0 );
+
+ // remove fourth panel, third panel should stay active
+ element.find( "h3.bar" ).eq( 3 ).remove();
+ element.find( "div.foo" ).eq( 3 ).remove();
+ element.accordion( "refresh" );
+ state( element, 0, 0, 1 );
+
+ // remove third (active) panel, second panel should become active
+ element.find( "h3.bar" ).eq( 2 ).remove();
+ element.find( "div.foo" ).eq( 2 ).remove();
+ element.accordion( "refresh" );
+ state( element, 0, 1 );
+
+ // remove first panel, previously active panel (now first) should stay active
+ element.find( "h3.bar" ).eq( 0 ).remove();
+ element.find( "div.foo" ).eq( 0 ).remove();
+ element.accordion( "refresh" );
+ state( element, 1 );
+
+ // collapse all panels
+ element.accordion( "option", {
+ collapsible: true,
+ active: false
+ });
+ state( element, 0 );
+ element.accordion( "refresh" );
+ state( element, 0 );
+});
+
+test( "widget", function() {
+ expect( 2 );
+ var element = $( "#list1" ).accordion(),
+ widgetElement = element.accordion( "widget" );
+ equal( widgetElement.length, 1, "one element" );
+ strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/accordion/accordion_options.js b/apps/it/static/js/ui/tests/unit/accordion/accordion_options.js
new file mode 100644
index 0000000..214753e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/accordion_options.js
@@ -0,0 +1,463 @@
+(function( $ ) {
+
+var equalHeight = TestHelpers.accordion.equalHeight,
+ setupTeardown = TestHelpers.accordion.setupTeardown,
+ state = TestHelpers.accordion.state;
+
+module( "accordion: options", setupTeardown() );
+
+test( "{ active: default }", function() {
+ expect( 2 );
+ var element = $( "#list1" ).accordion();
+ equal( element.accordion( "option", "active" ), 0 );
+ state( element, 1, 0, 0 );
+});
+
+test( "{ active: null }", function() {
+ expect( 2 );
+ var element = $( "#list1" ).accordion({
+ active: null
+ });
+ equal( element.accordion( "option", "active" ), 0 );
+ state( element, 1, 0, 0 );
+});
+
+test( "{ active: false }", function() {
+ expect( 7 );
+ var element = $( "#list1" ).accordion({
+ active: false,
+ collapsible: true
+ });
+ state( element, 0, 0, 0 );
+ equal( element.find( ".ui-accordion-header.ui-state-active" ).length, 0, "no headers selected" );
+ equal( element.accordion( "option", "active" ), false );
+
+ element.accordion( "option", "collapsible", false );
+ state( element, 1, 0, 0 );
+ equal( element.accordion( "option", "active" ), 0 );
+
+ element.accordion( "destroy" );
+ element.accordion({
+ active: false
+ });
+ state( element, 1, 0, 0 );
+ strictEqual( element.accordion( "option", "active" ), 0 );
+});
+
+test( "{ active: Number }", function() {
+ expect( 8 );
+ var element = $( "#list1" ).accordion({
+ active: 2
+ });
+ equal( element.accordion( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.accordion( "option", "active", 0 );
+ equal( element.accordion( "option", "active" ), 0 );
+ state( element, 1, 0, 0 );
+
+ element.find( ".ui-accordion-header" ).eq( 1 ).click();
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.accordion( "option", "active", 10 );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ active: -Number }", function() {
+ expect( 8 );
+ var element = $( "#list1" ).accordion({
+ active: -1
+ });
+ equal( element.accordion( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.accordion( "option", "active", -2 );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.accordion( "option", "active", -10 );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.accordion( "option", "active", -3 );
+ equal( element.accordion( "option", "active" ), 0 );
+ state( element, 1, 0, 0 );
+});
+
+test( "{ animate: false }", function() {
+ expect( 3 );
+ var element = $( "#list1" ).accordion({
+ animate: false
+ }),
+ panels = element.find( ".ui-accordion-content" ),
+ animate = $.fn.animate;
+ $.fn.animate = function() {
+ ok( false, ".animate() called" );
+ };
+
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" );
+ element.accordion( "option", "active", 1 );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" );
+ $.fn.animate = animate;
+});
+
+asyncTest( "{ animate: Number }", function() {
+ expect( 7 );
+ var element = $( "#list1" ).accordion({
+ animate: 100
+ }),
+ panels = element.find( ".ui-accordion-content" ),
+ animate = $.fn.animate;
+ // called twice (both panels)
+ $.fn.animate = function( props, options ) {
+ equal( options.duration, 100, "correct duration" );
+ equal( options.easing, undefined, "default easing" );
+ animate.apply( this, arguments );
+ };
+
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" );
+ element.accordion( "option", "active", 1 );
+ panels.promise().done(function() {
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" );
+ $.fn.animate = animate;
+ start();
+ });
+});
+
+asyncTest( "{ animate: String }", function() {
+ expect( 7 );
+ var element = $( "#list1" ).accordion({
+ animate: "linear"
+ }),
+ panels = element.find( ".ui-accordion-content" ),
+ animate = $.fn.animate;
+ // called twice (both panels)
+ $.fn.animate = function( props, options ) {
+ equal( options.duration, undefined, "default duration" );
+ equal( options.easing, "linear", "correct easing" );
+ animate.apply( this, arguments );
+ };
+
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" );
+ element.accordion( "option", "active", 1 );
+ panels.promise().done(function() {
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" );
+ $.fn.animate = animate;
+ start();
+ });
+});
+
+asyncTest( "{ animate: {} }", function() {
+ expect( 7 );
+ var element = $( "#list1" ).accordion({
+ animate: {}
+ }),
+ panels = element.find( ".ui-accordion-content" ),
+ animate = $.fn.animate;
+ // called twice (both panels)
+ $.fn.animate = function( props, options ) {
+ equal( options.duration, undefined, "default duration" );
+ equal( options.easing, undefined, "default easing" );
+ animate.apply( this, arguments );
+ };
+
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" );
+ element.accordion( "option", "active", 1 );
+ panels.promise().done(function() {
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" );
+ $.fn.animate = animate;
+ start();
+ });
+});
+
+asyncTest( "{ animate: { duration, easing } }", function() {
+ expect( 7 );
+ var element = $( "#list1" ).accordion({
+ animate: { duration: 100, easing: "linear" }
+ }),
+ panels = element.find( ".ui-accordion-content" ),
+ animate = $.fn.animate;
+ // called twice (both panels)
+ $.fn.animate = function( props, options ) {
+ equal( options.duration, 100, "correct duration" );
+ equal( options.easing, "linear", "correct easing" );
+ animate.apply( this, arguments );
+ };
+
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" );
+ element.accordion( "option", "active", 1 );
+ panels.promise().done(function() {
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" );
+ $.fn.animate = animate;
+ start();
+ });
+});
+
+asyncTest( "{ animate: { duration, easing } }, animate down", function() {
+ expect( 7 );
+ var element = $( "#list1" ).accordion({
+ active: 1,
+ animate: { duration: 100, easing: "linear" }
+ }),
+ panels = element.find( ".ui-accordion-content" ),
+ animate = $.fn.animate;
+ // called twice (both panels)
+ $.fn.animate = function( props, options ) {
+ equal( options.duration, 100, "correct duration" );
+ equal( options.easing, "linear", "correct easing" );
+ animate.apply( this, arguments );
+ };
+
+ ok( panels.eq( 1 ).is( ":visible" ), "first panel visible" );
+ element.accordion( "option", "active", 0 );
+ panels.promise().done(function() {
+ ok( panels.eq( 1 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 0 ).is( ":visible" ), "second panel visible" );
+ $.fn.animate = animate;
+ start();
+ });
+});
+
+asyncTest( "{ animate: { duration, easing, down } }, animate down", function() {
+ expect( 7 );
+ var element = $( "#list1" ).accordion({
+ active: 1,
+ animate: {
+ duration: 100,
+ easing: "linear",
+ down: {
+ easing: "swing"
+ }
+ }
+ }),
+ panels = element.find( ".ui-accordion-content" ),
+ animate = $.fn.animate;
+ // called twice (both panels)
+ $.fn.animate = function( props, options ) {
+ equal( options.duration, 100, "correct duration" );
+ equal( options.easing, "swing", "correct easing" );
+ animate.apply( this, arguments );
+ };
+
+ ok( panels.eq( 1 ).is( ":visible" ), "first panel visible" );
+ element.accordion( "option", "active", 0 );
+ panels.promise().done(function() {
+ ok( panels.eq( 1 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 0 ).is( ":visible" ), "second panel visible" );
+ $.fn.animate = animate;
+ start();
+ });
+});
+
+test( "{ collapsible: false }", function() {
+ expect( 4 );
+ var element = $( "#list1" ).accordion({
+ active: 1
+ });
+ element.accordion( "option", "active", false );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.find( ".ui-accordion-header" ).eq( 1 ).click();
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ collapsible: true }", function() {
+ expect( 6 );
+ var element = $( "#list1" ).accordion({
+ active: 1,
+ collapsible: true
+ });
+
+ element.accordion( "option", "active", false );
+ equal( element.accordion( "option", "active" ), false );
+ state( element, 0, 0, 0 );
+
+ element.accordion( "option", "active", 1 );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.find( ".ui-accordion-header" ).eq( 1 ).click();
+ equal( element.accordion( "option", "active" ), false );
+ state( element, 0, 0, 0 );
+});
+
+test( "{ event: null }", function() {
+ expect( 5 );
+ var element = $( "#list1" ).accordion({
+ event: null
+ });
+ state( element, 1, 0, 0 );
+
+ element.accordion( "option", "active", 1 );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ // ensure default click handler isn't bound
+ element.find( ".ui-accordion-header" ).eq( 2 ).click();
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ event: custom }", function() {
+ expect( 11 );
+ var element = $( "#list1" ).accordion({
+ event: "custom1 custom2"
+ });
+ state( element, 1, 0, 0 );
+
+ element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom1" );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ // ensure default click handler isn't bound
+ element.find( ".ui-accordion-header" ).eq( 2 ).trigger( "click" );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.find( ".ui-accordion-header" ).eq( 2 ).trigger( "custom2" );
+ equal( element.accordion( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.accordion( "option", "event", "custom3" );
+
+ // ensure old event handlers are unbound
+ element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom1" );
+ element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom2" );
+ equal( element.accordion( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom3" );
+ equal( element.accordion( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ header: default }", function() {
+ expect( 2 );
+ // default: > li > :first-child,> :not(li):even
+ // > :not(li):even
+ state( $( "#list1" ).accordion(), 1, 0, 0);
+ // > li > :first-child
+ state( $( "#navigation" ).accordion(), 1, 0, 0);
+});
+
+test( "{ header: custom }", function() {
+ expect( 6 );
+ var element = $( "#navigationWrapper" ).accordion({
+ header: "h2"
+ });
+ element.find( "h2" ).each(function() {
+ ok( $( this ).hasClass( "ui-accordion-header" ) );
+ });
+ equal( element.find( ".ui-accordion-header" ).length, 3 );
+ state( element, 1, 0, 0 );
+ element.accordion( "option", "active", 2 );
+ state( element, 0, 0, 1 );
+});
+
+test( "{ heightStyle: 'auto' }", function() {
+ expect( 3 );
+ var element = $( "#navigation" ).accordion({ heightStyle: "auto" });
+ equalHeight( element, 105 );
+});
+
+test( "{ heightStyle: 'content' }", function() {
+ expect( 3 );
+ var element = $( "#navigation" ).accordion({ heightStyle: "content" }),
+ sizes = element.find( ".ui-accordion-content" ).map(function() {
+ return $( this ).height();
+ }).get();
+ equal( sizes[ 0 ], 75 );
+ equal( sizes[ 1 ], 105 );
+ equal( sizes[ 2 ], 45 );
+});
+
+test( "{ heightStyle: 'fill' }", function() {
+ expect( 3 );
+ $( "#navigationWrapper" ).height( 500 );
+ var element = $( "#navigation" ).accordion({ heightStyle: "fill" });
+ equalHeight( element, 455 );
+});
+
+test( "{ heightStyle: 'fill' } with sibling", function() {
+ expect( 3 );
+ $( "#navigationWrapper" ).height( 500 );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 50,
+ marginTop: 20,
+ marginBottom: 30
+ })
+ .prependTo( "#navigationWrapper" );
+ var element = $( "#navigation" ).accordion({ heightStyle: "fill" });
+ equalHeight( element , 355 );
+});
+
+test( "{ heightStyle: 'fill' } with multiple siblings", function() {
+ expect( 3 );
+ $( "#navigationWrapper" ).height( 500 );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 50,
+ marginTop: 20,
+ marginBottom: 30
+ })
+ .prependTo( "#navigationWrapper" );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 50,
+ marginTop: 20,
+ marginBottom: 30,
+ position: "absolute"
+ })
+ .prependTo( "#navigationWrapper" );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 25,
+ marginTop: 10,
+ marginBottom: 15
+ })
+ .prependTo( "#navigationWrapper" );
+ var element = $( "#navigation" ).accordion({ heightStyle: "fill" });
+ equalHeight( element, 305 );
+});
+
+test( "{ icons: false }", function() {
+ expect( 8 );
+ var element = $( "#list1" );
+ function icons( on ) {
+ deepEqual( element.find( "span.ui-icon").length, on ? 3 : 0 );
+ deepEqual( element.find( ".ui-accordion-header.ui-accordion-icons" ).length, on ? 3 : 0 );
+ }
+ element.accordion();
+ icons( true );
+ element.accordion( "destroy" ).accordion({
+ icons: false
+ });
+ icons( false );
+ element.accordion( "option", "icons", { header: "foo", activeHeader: "bar" } );
+ icons( true );
+ element.accordion( "option", "icons", false );
+ icons( false );
+});
+
+test( "{ icons: hash }", function() {
+ expect( 3 );
+ var element = $( "#list1" ).accordion({
+ icons: { activeHeader: "a1", header: "h1" }
+ });
+ ok( element.find( ".ui-accordion-header.ui-state-active span.ui-icon" ).hasClass( "a1" ) );
+ element.accordion( "option", "icons", { activeHeader: "a2", header: "h2" } );
+ ok( !element.find( ".ui-accordion-header.ui-state-active span.ui-icon" ).hasClass( "a1" ) );
+ ok( element.find( ".ui-accordion-header.ui-state-active span.ui-icon" ).hasClass( "a2" ) );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/accordion/accordion_test_helpers.js b/apps/it/static/js/ui/tests/unit/accordion/accordion_test_helpers.js
new file mode 100644
index 0000000..643f8e2
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/accordion_test_helpers.js
@@ -0,0 +1,27 @@
+TestHelpers.accordion = {
+ equalHeight: function( accordion, height ) {
+ accordion.find( ".ui-accordion-content" ).each(function() {
+ equal( $( this ).outerHeight(), height );
+ });
+ },
+
+ setupTeardown: function() {
+ var animate = $.ui.accordion.prototype.options.animate;
+ return {
+ setup: function() {
+ $.ui.accordion.prototype.options.animate = false;
+ },
+ teardown: function() {
+ $.ui.accordion.prototype.options.animate = animate;
+ }
+ };
+ },
+
+ state: function( accordion ) {
+ var expected = $.makeArray( arguments ).slice( 1 ),
+ actual = accordion.find( ".ui-accordion-content" ).map(function() {
+ return $( this ).css( "display" ) === "none" ? 0 : 1;
+ }).get();
+ QUnit.push( QUnit.equiv(actual, expected), actual, expected );
+ }
+};
diff --git a/apps/it/static/js/ui/tests/unit/accordion/all.html b/apps/it/static/js/ui/tests/unit/accordion/all.html
new file mode 100644
index 0000000..8710d03
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/accordion/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Accordion Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "accordion" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Accordion Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/all.html b/apps/it/static/js/ui/tests/unit/all.html
new file mode 100644
index 0000000..a05deb1
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/all.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Test Suite</title>
+
+ <script src="../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../external/qunit.css">
+ <link rel="stylesheet" href="qunit-composite.css">
+ <script src="../../external/qunit.js"></script>
+ <script src="qunit-composite.js"></script>
+
+ <script>
+ (function() {
+
+ var params = [],
+ suites = [
+ "accordion/accordion.html",
+ "autocomplete/autocomplete.html",
+ "button/button.html",
+ "core/core.html",
+ "datepicker/datepicker.html",
+ "dialog/dialog.html",
+ "dialog/dialog_deprecated.html",
+ "draggable/draggable.html",
+ "droppable/droppable.html",
+ "effects/effects.html",
+ "menu/menu.html",
+ "position/position.html",
+ "progressbar/progressbar.html",
+ "resizable/resizable.html",
+ "selectable/selectable.html",
+ "slider/slider.html",
+ "sortable/sortable.html",
+ "spinner/spinner.html",
+ "tabs/tabs.html",
+ "tooltip/tooltip.html",
+ "widget/widget.html"
+ ];
+
+ $.each( QUnit.urlParams, function( key, value ) {
+ if ( key === "filter" ) {
+ return;
+ }
+ params.push( encodeURIComponent( key ) + "=" + encodeURIComponent( value ) );
+ });
+ if ( params.length ) {
+ params = "?" + params.join( "&" );
+ suites = $.map( suites, function( suite ) {
+ return suite + params;
+ });
+ }
+ QUnit.testSuites( suites );
+
+ }());
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/all.html b/apps/it/static/js/ui/tests/unit/autocomplete/all.html
new file mode 100644
index 0000000..bfc8b8e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Autocomplete Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "autocomplete" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Autocomplete Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete.html b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete.html
new file mode 100644
index 0000000..8c7b5b6
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Autocomplete Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.menu", "ui.autocomplete" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.position.js",
+ "ui/jquery.ui.menu.js",
+ "ui/jquery.ui.autocomplete.js"
+ ]
+ });
+ </script>
+
+ <script src="autocomplete_common.js"></script>
+ <script src="autocomplete_core.js"></script>
+ <script src="autocomplete_events.js"></script>
+ <script src="autocomplete_methods.js"></script>
+ <script src="autocomplete_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Autocomplete Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="autocomplete-wrap1" class="autocomplete-wrap"></div>
+<div id="autocomplete-wrap2" class="autocomplete-wrap"><input id="autocomplete" class="foo"></div>
+<div id="autocomplete-contenteditable" contenteditable="" tabindex=0></div>
+<textarea id="autocomplete-textarea"></textarea>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_common.js b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_common.js
new file mode 100644
index 0000000..63b24d3
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_common.js
@@ -0,0 +1,29 @@
+TestHelpers.commonWidgetTests( "autocomplete", {
+ defaults: {
+ appendTo: null,
+ autoFocus: false,
+ delay: 300,
+ disabled: false,
+ messages: {
+ noResults: "No search results.",
+ results: $.ui.autocomplete.prototype.options.messages.results
+ },
+ minLength: 1,
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ source: null,
+
+ // callbacks
+ change: null,
+ close: null,
+ create: null,
+ focus: null,
+ open: null,
+ response: null,
+ search: null,
+ select: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_core.js b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_core.js
new file mode 100644
index 0000000..679955d
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_core.js
@@ -0,0 +1,270 @@
+(function( $ ) {
+
+module( "autocomplete: core" );
+
+test( "prevent form submit on enter when menu is active", function() {
+ expect( 2 );
+ var event,
+ element = $( "#autocomplete" )
+ .autocomplete({
+ source: [ "java", "javascript" ]
+ })
+ .val( "ja" )
+ .autocomplete( "search" ),
+ menu = element.autocomplete( "widget" );
+
+ event = $.Event( "keydown" );
+ event.keyCode = $.ui.keyCode.DOWN;
+ element.trigger( event );
+ deepEqual( menu.find( ".ui-menu-item:has(.ui-state-focus)" ).length, 1, "menu item is active" );
+
+ event = $.Event( "keydown" );
+ event.keyCode = $.ui.keyCode.ENTER;
+ element.trigger( event );
+ ok( event.isDefaultPrevented(), "default action is prevented" );
+});
+
+test( "allow form submit on enter when menu is not active", function() {
+ expect( 1 );
+ var event,
+ element = $( "#autocomplete" )
+ .autocomplete({
+ autoFocus: false,
+ source: [ "java", "javascript" ]
+ })
+ .val( "ja" )
+ .autocomplete( "search" );
+
+ event = $.Event( "keydown" );
+ event.keyCode = $.ui.keyCode.ENTER;
+ element.trigger( event );
+ ok( !event.isDefaultPrevented(), "default action is prevented" );
+});
+
+(function() {
+ test( "up arrow invokes search - input", function() {
+ arrowsInvokeSearch( "#autocomplete", true, true );
+ });
+
+ test( "down arrow invokes search - input", function() {
+ arrowsInvokeSearch( "#autocomplete", false, true );
+ });
+
+ test( "up arrow invokes search - textarea", function() {
+ arrowsInvokeSearch( "#autocomplete-textarea", true, false );
+ });
+
+ test( "down arrow invokes search - textarea", function() {
+ arrowsInvokeSearch( "#autocomplete-textarea", false, false );
+ });
+
+ test( "up arrow invokes search - contenteditable", function() {
+ arrowsInvokeSearch( "#autocomplete-contenteditable", true, false );
+ });
+
+ test( "down arrow invokes search - contenteditable", function() {
+ arrowsInvokeSearch( "#autocomplete-contenteditable", false, false );
+ });
+
+ test( "up arrow moves focus - input", function() {
+ arrowsMoveFocus( "#autocomplete", true );
+ });
+
+ test( "down arrow moves focus - input", function() {
+ arrowsMoveFocus( "#autocomplete", false );
+ });
+
+ test( "up arrow moves focus - textarea", function() {
+ arrowsMoveFocus( "#autocomplete-textarea", true );
+ });
+
+ test( "down arrow moves focus - textarea", function() {
+ arrowsMoveFocus( "#autocomplete-textarea", false );
+ });
+
+ test( "up arrow moves focus - contenteditable", function() {
+ arrowsMoveFocus( "#autocomplete-contenteditable", true );
+ });
+
+ test( "down arrow moves focus - contenteditable", function() {
+ arrowsMoveFocus( "#autocomplete-contenteditable", false );
+ });
+
+ test( "up arrow moves cursor - input", function() {
+ arrowsNavigateElement( "#autocomplete", true, false );
+ });
+
+ test( "down arrow moves cursor - input", function() {
+ arrowsNavigateElement( "#autocomplete", false, false );
+ });
+
+ test( "up arrow moves cursor - textarea", function() {
+ arrowsNavigateElement( "#autocomplete-textarea", true, true );
+ });
+
+ test( "down arrow moves cursor - textarea", function() {
+ arrowsNavigateElement( "#autocomplete-textarea", false, true );
+ });
+
+ test( "up arrow moves cursor - contenteditable", function() {
+ arrowsNavigateElement( "#autocomplete-contenteditable", true, true );
+ });
+
+ test( "down arrow moves cursor - contenteditable", function() {
+ arrowsNavigateElement( "#autocomplete-contenteditable", false, true );
+ });
+
+ function arrowsInvokeSearch( id, isKeyUp, shouldMove ) {
+ expect( 1 );
+
+ var didMove = false,
+ element = $( id ).autocomplete({
+ source: [ "a" ],
+ delay: 0,
+ minLength: 0
+ });
+ element.data( "ui-autocomplete" )._move = function() {
+ didMove = true;
+ };
+ element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } );
+ equal( didMove, shouldMove, "respond to arrow" );
+ }
+
+ function arrowsMoveFocus( id, isKeyUp ) {
+ expect( 1 );
+
+ var element = $( id ).autocomplete({
+ source: [ "a" ],
+ delay: 0,
+ minLength: 0
+ });
+ element.data( "ui-autocomplete" )._move = function() {
+ ok( true, "repsond to arrow" );
+ };
+ element.autocomplete( "search" );
+ element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } );
+ }
+
+ function arrowsNavigateElement( id, isKeyUp, shouldMove ) {
+ expect( 1 );
+
+ var didMove = false,
+ element = $( id ).autocomplete({
+ source: [ "a" ],
+ delay: 0,
+ minLength: 0
+ });
+ element.on( "keypress", function( e ) {
+ didMove = !e.isDefaultPrevented();
+ });
+ element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } );
+ element.simulate( "keypress" );
+ equal( didMove, shouldMove, "respond to arrow" );
+ }
+})();
+
+asyncTest( "handle race condition", function() {
+ expect( 3 );
+ var count = 0,
+ element = $( "#autocomplete" ).autocomplete({
+ source: function( request, response ) {
+ count++;
+ if ( request.term.length === 1 ) {
+ equal( count, 1, "request with 1 character is first" );
+ setTimeout(function() {
+ response([ "one" ]);
+ setTimeout( checkResults, 1 );
+ }, 1 );
+ return;
+ }
+ equal( count, 2, "request with 2 characters is second" );
+ response([ "two" ]);
+ }
+ });
+
+ element.autocomplete( "search", "a" );
+ element.autocomplete( "search", "ab" );
+
+ function checkResults() {
+ equal( element.autocomplete( "widget" ).find( ".ui-menu-item" ).text(), "two",
+ "correct results displayed" );
+ start();
+ }
+});
+
+asyncTest( "simultaneous searches (#9334)", function() {
+ expect( 2 );
+ var element = $( "#autocomplete" ).autocomplete({
+ source: function( request, response ) {
+ setTimeout(function() {
+ response([ request.term ]);
+ });
+ },
+ response: function() {
+ ok( true, "response from first instance" );
+ }
+ }),
+ element2 = $( "#autocomplete-textarea" ).autocomplete({
+ source: function( request, response ) {
+ setTimeout(function() {
+ response([ request.term ]);
+ });
+ },
+ response: function() {
+ ok( true, "response from second instance" );
+ start();
+ }
+ });
+
+ element.autocomplete( "search", "test" );
+ element2.autocomplete( "search", "test" );
+});
+
+test( "ARIA", function() {
+ expect( 7 );
+ var element = $( "#autocomplete" ).autocomplete({
+ source: [ "java", "javascript" ]
+ }),
+ liveRegion = element.data( "ui-autocomplete" ).liveRegion;
+
+ equal( liveRegion.text(), "", "Empty live region on create" );
+
+ element.autocomplete( "search", "j" );
+ equal( liveRegion.text(), "2 results are available, use up and down arrow keys to navigate.",
+ "Live region for multiple values" );
+
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( liveRegion.text(), "2 results are available, use up and down arrow keys to navigate.",
+ "Live region not changed on focus" );
+
+ element.one( "autocompletefocus", function( event ) {
+ event.preventDefault();
+ });
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( liveRegion.text(), "javascript",
+ "Live region updated when default focus is prevented" );
+
+ element.autocomplete( "search", "javas" );
+ equal( liveRegion.text(), "1 result is available, use up and down arrow keys to navigate.",
+ "Live region for one value" );
+
+ element.autocomplete( "search", "z" );
+ equal( liveRegion.text(), "No search results.",
+ "Live region for no values" );
+
+ element.autocomplete( "search", "j" );
+ equal( liveRegion.text(), "2 results are available, use up and down arrow keys to navigate.",
+ "Live region for multiple values" );
+});
+
+test( ".replaceWith() (#9172)", function() {
+ expect( 1 );
+
+ var element = $( "#autocomplete" ).autocomplete(),
+ replacement = "<div>test</div>",
+ parent = element.parent();
+ element.replaceWith( replacement );
+ equal( parent.html().toLowerCase(), replacement );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_events.js b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_events.js
new file mode 100644
index 0000000..fb1cf73
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_events.js
@@ -0,0 +1,182 @@
+(function( $ ) {
+
+module( "autocomplete: events" );
+
+var data = [ "Clojure", "COBOL", "ColdFusion", "Java", "JavaScript", "Scala", "Scheme" ];
+
+$.each([
+ {
+ type: "input",
+ selector: "#autocomplete",
+ valueMethod: "val"
+ },
+ {
+ type: "textarea",
+ selector: "#autocomplete-textarea",
+ valueMethod: "val"
+ },
+ {
+ type: "contenteditable",
+ selector: "#autocomplete-contenteditable",
+ valueMethod: "text"
+ }
+], function( i, settings ) {
+ asyncTest( "all events - " + settings.type, function() {
+ expect( 13 );
+ var element = $( settings.selector )
+ .autocomplete({
+ autoFocus: false,
+ delay: 0,
+ source: data,
+ search: function( event ) {
+ equal( event.originalEvent.type, "keydown", "search originalEvent" );
+ },
+ response: function( event, ui ) {
+ deepEqual( ui.content, [
+ { label: "Clojure", value: "Clojure" },
+ { label: "Java", value: "Java" },
+ { label: "JavaScript", value: "JavaScript" }
+ ], "response ui.content" );
+ ui.content.splice( 0, 1 );
+ },
+ open: function() {
+ ok( menu.is( ":visible" ), "menu open on open" );
+ },
+ focus: function( event, ui ) {
+ equal( event.originalEvent.type, "menufocus", "focus originalEvent" );
+ deepEqual( ui.item, { label: "Java", value: "Java" }, "focus ui.item" );
+ },
+ close: function( event ) {
+ equal( event.originalEvent.type, "menuselect", "close originalEvent" );
+ ok( menu.is( ":hidden" ), "menu closed on close" );
+ },
+ select: function( event, ui ) {
+ equal( event.originalEvent.type, "menuselect", "select originalEvent" );
+ deepEqual( ui.item, { label: "Java", value: "Java" }, "select ui.item" );
+ },
+ change: function( event, ui ) {
+ equal( event.originalEvent.type, "blur", "change originalEvent" );
+ deepEqual( ui.item, { label: "Java", value: "Java" }, "change ui.item" );
+ ok( menu.is( ":hidden" ), "menu closed on change" );
+ start();
+ }
+ }),
+ menu = element.autocomplete( "widget" );
+
+ element.simulate( "focus" )[ settings.valueMethod ]( "j" ).keydown();
+ setTimeout(function() {
+ ok( menu.is( ":visible" ), "menu is visible after delay" );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ // blur must be async for IE to handle it properly
+ setTimeout(function() {
+ element.simulate( "blur" );
+ }, 1 );
+ }, 50 );
+ });
+});
+
+asyncTest( "change without selection", function() {
+ expect( 1 );
+ var element = $( "#autocomplete" ).autocomplete({
+ delay: 0,
+ source: data,
+ change: function( event, ui ) {
+ strictEqual( ui.item, null );
+ start();
+ }
+ });
+ element.triggerHandler( "focus" );
+ element.val( "ja" ).triggerHandler( "blur" );
+});
+
+asyncTest( "cancel search", function() {
+ expect( 6 );
+ var first = true,
+ element = $( "#autocomplete" ).autocomplete({
+ delay: 0,
+ source: data,
+ search: function() {
+ if ( first ) {
+ equal( element.val(), "ja", "val on first search" );
+ first = false;
+ return false;
+ }
+ equal( element.val(), "java", "val on second search" );
+ },
+ open: function() {
+ ok( true, "menu opened" );
+ }
+ }),
+ menu = element.autocomplete( "widget" );
+ element.val( "ja" ).keydown();
+ setTimeout(function() {
+ ok( menu.is( ":hidden" ), "menu is hidden after first search" );
+ element.val( "java" ).keydown();
+ setTimeout(function() {
+ ok( menu.is( ":visible" ), "menu is visible after second search" );
+ equal( menu.find( ".ui-menu-item" ).length, 2, "# of menu items" );
+ start();
+ }, 50 );
+ }, 50 );
+});
+
+asyncTest( "cancel focus", function() {
+ expect( 1 );
+ var customVal = "custom value",
+ element = $( "#autocomplete" ).autocomplete({
+ delay: 0,
+ source: data,
+ focus: function() {
+ $( this ).val( customVal );
+ return false;
+ }
+ });
+ element.val( "ja" ).keydown();
+ setTimeout(function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( element.val(), customVal );
+ start();
+ }, 50 );
+});
+
+asyncTest( "cancel select", function() {
+ expect( 1 );
+ var customVal = "custom value",
+ element = $( "#autocomplete" ).autocomplete({
+ delay: 0,
+ source: data,
+ select: function() {
+ $( this ).val( customVal );
+ return false;
+ }
+ });
+ element.val( "ja" ).keydown();
+ setTimeout(function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equal( element.val(), customVal );
+ start();
+ }, 50 );
+});
+
+asyncTest( "blur during remote search", function() {
+ expect( 1 );
+ var ac = $( "#autocomplete" ).autocomplete({
+ delay: 0,
+ source: function( request, response ) {
+ ok( true, "trigger request" );
+ ac.simulate( "blur" );
+ setTimeout(function() {
+ response([ "result" ]);
+ start();
+ }, 100 );
+ },
+ open: function() {
+ ok( false, "opened after a blur" );
+ }
+ });
+ ac.val( "ro" ).keydown();
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_methods.js b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_methods.js
new file mode 100644
index 0000000..1bfa105
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_methods.js
@@ -0,0 +1,45 @@
+(function( $ ) {
+
+module( "autocomplete: methods" );
+
+test( "destroy", function() {
+ expect( 1 );
+ domEqual( "#autocomplete", function() {
+ $( "#autocomplete" ).autocomplete().autocomplete( "destroy" );
+ });
+});
+
+test( "search, close", function() {
+ expect( 6 );
+ var data = [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl" ],
+ element = $( "#autocomplete" ).autocomplete({
+ source: data,
+ minLength: 0
+ }),
+ menu = element.autocomplete( "widget" );
+
+ ok( menu.is( ":hidden" ), "menu is hidden on init" );
+
+ element.autocomplete( "search" );
+ ok( menu.is( ":visible" ), "menu is visible after search" );
+ equal( menu.find( ".ui-menu-item" ).length, data.length, "all items for a blank search" );
+
+ element.val( "has" ).autocomplete( "search" );
+ equal( menu.find( ".ui-menu-item" ).text(), "haskell", "only one item for set input value" );
+
+ element.autocomplete( "search", "ja" );
+ equal( menu.find( ".ui-menu-item" ).length, 2, "only java and javascript for 'ja'" );
+
+ element.autocomplete( "close" );
+ ok( menu.is( ":hidden" ), "menu is hidden after close" );
+});
+
+test( "widget", function() {
+ expect( 2 );
+ var element = $( "#autocomplete" ).autocomplete(),
+ widgetElement = element.autocomplete( "widget" );
+ equal( widgetElement.length, 1, "one element" );
+ ok( widgetElement.is( ".ui-menu" ), "menu element" );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_options.js b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_options.js
new file mode 100644
index 0000000..0a2e07b
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/autocomplete_options.js
@@ -0,0 +1,278 @@
+(function( $ ) {
+
+module( "autocomplete: options" );
+
+var data = [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby",
+ "python", "c", "scala", "groovy", "haskell", "perl" ];
+
+test( "appendTo", function() {
+ expect( 8 );
+ var detached = $( "<div>" ),
+ element = $( "#autocomplete" ).autocomplete();
+ equal( element.autocomplete( "widget" ).parent()[ 0 ], document.body,
+ "defaults to body" );
+ element.autocomplete( "destroy" );
+
+ element.autocomplete({
+ appendTo: ".autocomplete-wrap"
+ });
+ equal( element.autocomplete( "widget" ).parent()[ 0 ],
+ $( "#autocomplete-wrap1" )[ 0 ], "first found element" );
+ equal( $( "#autocomplete-wrap2 .ui-autocomplete" ).length, 0,
+ "only appends to one element" );
+ element.autocomplete( "destroy" );
+
+ $( "#autocomplete-wrap2" ).addClass( "ui-front" );
+ element.autocomplete();
+ equal( element.autocomplete( "widget" ).parent()[ 0 ],
+ $( "#autocomplete-wrap2" )[ 0 ], "null, inside .ui-front" );
+ element.autocomplete( "destroy" );
+ $( "#autocomlete-wrap2" ).removeClass( "ui-front" );
+
+ element.autocomplete().autocomplete( "option", "appendTo", "#autocomplete-wrap1" );
+ equal( element.autocomplete( "widget" ).parent()[ 0 ],
+ $( "#autocomplete-wrap1" )[ 0 ], "modified after init" );
+ element.autocomplete( "destroy" );
+
+ element.autocomplete({
+ appendTo: detached
+ });
+ equal( element.autocomplete( "widget" ).parent()[ 0 ], detached[ 0 ],
+ "detached jQuery object" );
+ element.autocomplete( "destroy" );
+
+ element.autocomplete({
+ appendTo: detached[ 0 ]
+ });
+ equal( element.autocomplete( "widget" ).parent()[ 0 ], detached[ 0 ],
+ "detached DOM element" );
+ element.autocomplete( "destroy" );
+
+ element.autocomplete().autocomplete( "option", "appendTo", detached );
+ equal( element.autocomplete( "widget" ).parent()[ 0 ], detached[ 0 ],
+ "detached DOM element via option()" );
+ element.autocomplete( "destroy" );
+});
+
+function autoFocusTest( afValue, focusedLength ) {
+ var element = $( "#autocomplete" ).autocomplete({
+ autoFocus: afValue,
+ delay: 0,
+ source: data,
+ open: function() {
+ equal(
+ element.autocomplete( "widget" )
+ .children( ".ui-menu-item:first" )
+ .find( ".ui-state-focus" )
+ .length,
+ focusedLength,
+ "first item is " + (afValue ? "" : "not") + " auto focused" );
+ start();
+ }
+ });
+ element.val( "ja" ).keydown();
+ stop();
+}
+
+test( "autoFocus: false", function() {
+ expect( 1 );
+ autoFocusTest( false, 0 );
+});
+
+test( "autoFocus: true", function() {
+ expect( 1 );
+ autoFocusTest( true, 1 );
+});
+
+asyncTest( "delay", function() {
+ expect( 2 );
+ var element = $( "#autocomplete" ).autocomplete({
+ source: data,
+ delay: 50
+ }),
+ menu = element.autocomplete( "widget" );
+ element.val( "ja" ).keydown();
+
+ ok( menu.is( ":hidden" ), "menu is closed immediately after search" );
+
+ setTimeout(function() {
+ ok( menu.is( ":visible" ), "menu is open after delay" );
+ start();
+ }, 100 );
+});
+
+asyncTest( "disabled", function() {
+ expect( 2 );
+ var element = $( "#autocomplete" ).autocomplete({
+ source: data,
+ delay: 0,
+ disabled: true
+ }),
+ menu = element.autocomplete( "widget" );
+ element.val( "ja" ).keydown();
+
+ ok( menu.is( ":hidden" ) );
+
+ setTimeout(function() {
+ ok( menu.is( ":hidden" ) );
+ start();
+ }, 50 );
+});
+
+test( "minLength", function() {
+ expect( 2 );
+ var element = $( "#autocomplete" ).autocomplete({
+ source: data
+ }),
+ menu = element.autocomplete( "widget" );
+ element.autocomplete( "search", "" );
+ ok( menu.is( ":hidden" ), "blank not enough for minLength: 1" );
+
+ element.autocomplete( "option", "minLength", 0 );
+ element.autocomplete( "search", "" );
+ ok( menu.is( ":visible" ), "blank enough for minLength: 0" );
+});
+
+asyncTest( "minLength, exceed then drop below", function() {
+ expect( 4 );
+ var element = $( "#autocomplete" ).autocomplete({
+ minLength: 2,
+ source: function( req, res ) {
+ equal( req.term, "12", "correct search term" );
+ setTimeout(function() {
+ res([ "item" ]);
+ }, 1 );
+ }
+ }),
+ menu = element.autocomplete( "widget" );
+
+ ok( menu.is( ":hidden" ), "menu is hidden before first search" );
+ element.autocomplete( "search", "12" );
+
+ ok( menu.is( ":hidden" ), "menu is hidden before second search" );
+ element.autocomplete( "search", "1" );
+
+ setTimeout(function() {
+ ok( menu.is( ":hidden" ), "menu is hidden after searches" );
+ start();
+ }, 50 );
+});
+
+test( "minLength, exceed then drop below then exceed", function() {
+ expect( 3 );
+ var _res = [],
+ element = $( "#autocomplete" ).autocomplete({
+ minLength: 2,
+ source: function( req, res ) {
+ _res.push( res );
+ }
+ }),
+ menu = element.autocomplete( "widget" );
+
+ // trigger a valid search
+ ok( menu.is( ":hidden" ), "menu is hidden before first search" );
+ element.autocomplete( "search", "12" );
+
+ // trigger a search below the minLength, to turn on cancelSearch flag
+ ok( menu.is( ":hidden" ), "menu is hidden before second search" );
+ element.autocomplete( "search", "1" );
+
+ // trigger a valid search
+ element.autocomplete( "search", "13" );
+ // react as if the first search was cancelled (default ajax behavior)
+ _res[ 0 ]([]);
+ // react to second search
+ _res[ 1 ]([ "13" ]);
+
+ ok( menu.is( ":visible" ), "menu is visible after searches" );
+});
+
+test( "source, local string array", function() {
+ expect( 1 );
+ var element = $( "#autocomplete" ).autocomplete({
+ source: data
+ }),
+ menu = element.autocomplete( "widget" );
+ element.val( "ja" ).autocomplete( "search" );
+ equal( menu.find( ".ui-menu-item" ).text(), "javajavascript" );
+});
+
+function sourceTest( source, async ) {
+ var element = $( "#autocomplete" ).autocomplete({
+ source: source
+ }),
+ menu = element.autocomplete( "widget" );
+ function result() {
+ equal( menu.find( ".ui-menu-item" ).text(), "javajavascript" );
+ element.autocomplete( "destroy" );
+ if ( async ) {
+ start();
+ }
+ }
+ if ( async ) {
+ stop();
+ $( document ).one( "ajaxStop", result );
+ }
+ element.val( "ja" ).autocomplete( "search" );
+ if ( !async ) {
+ result();
+ }
+}
+
+test( "source, local object array, only label property", function() {
+ expect( 1 );
+ sourceTest([
+ { label: "java" },
+ { label: "php" },
+ { label: "coldfusion" },
+ { label: "javascript" }
+ ]);
+});
+
+test( "source, local object array, only value property", function() {
+ expect( 1 );
+ sourceTest([
+ { value: "java" },
+ { value: "php" },
+ { value: "coldfusion" },
+ { value: "javascript" }
+ ]);
+});
+
+test( "source, url string with remote json string array", function() {
+ expect( 1 );
+ sourceTest( "remote_string_array.txt", true );
+});
+
+test( "source, url string with remote json object array, only value properties", function() {
+ expect( 1 );
+ sourceTest( "remote_object_array_values.txt", true );
+});
+
+test( "source, url string with remote json object array, only label properties", function() {
+ expect( 1 );
+ sourceTest( "remote_object_array_labels.txt", true );
+});
+
+test( "source, custom", function() {
+ expect( 2 );
+ sourceTest(function( request, response ) {
+ equal( request.term, "ja" );
+ response( ["java", "javascript"] );
+ });
+});
+
+test( "source, update after init", function() {
+ expect( 2 );
+ var element = $( "#autocomplete" ).autocomplete({
+ source: [ "java", "javascript", "haskell" ]
+ }),
+ menu = element.autocomplete( "widget" );
+ element.val( "ja" ).autocomplete( "search" );
+ equal( menu.find( ".ui-menu-item" ).text(), "javajavascript" );
+ element.autocomplete( "option", "source", [ "php", "asp" ] );
+ element.val( "ph" ).autocomplete( "search" );
+ equal( menu.find( ".ui-menu-item" ).text(), "php" );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_labels.txt b/apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_labels.txt
new file mode 100644
index 0000000..502496c
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_labels.txt
@@ -0,0 +1 @@
+[{"label":"java"},{"label":"javascript"}] \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_values.txt b/apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_values.txt
new file mode 100644
index 0000000..029cbb9
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/remote_object_array_values.txt
@@ -0,0 +1 @@
+[{"value":"java"},{"value":"javascript"}] \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/autocomplete/remote_string_array.txt b/apps/it/static/js/ui/tests/unit/autocomplete/remote_string_array.txt
new file mode 100644
index 0000000..3b24c8e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/autocomplete/remote_string_array.txt
@@ -0,0 +1 @@
+["java", "javascript"] \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/button/all.html b/apps/it/static/js/ui/tests/unit/button/all.html
new file mode 100644
index 0000000..871006f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/button/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Button Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "button" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Button Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/button/button.html b/apps/it/static/js/ui/tests/unit/button/button.html
new file mode 100644
index 0000000..223581e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/button/button.html
@@ -0,0 +1,78 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Button Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.button" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.button.js"
+ ]
+ });
+ </script>
+
+ <script src="button_common.js"></script>
+ <script src="button_core.js"></script>
+ <script src="button_events.js"></script>
+ <script src="button_methods.js"></script>
+ <script src="button_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Button Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div><button id="button" class="foo">Label</button></div>
+
+<div id="radio0" style="margin-top: 2em;">
+ <input type="radio" id="radio01" name="radio" checked="checked"><label for="radio01">Choice 1</label>
+ <input type="radio" id="radio02" name="radio"><label for="radio02">Choice 2</label>
+ <input type="radio" id="radio03" name="radio"><label for="radio03">Choice 3</label>
+</div>
+<form>
+ <div id="radio1" style="margin-top: 2em;">
+ <input type="radio" id="radio11" name="radio"><label for="radio11">Choice 1</label>
+ <input type="radio" id="radio12" name="radio" checked="checked"><label for="radio12">Choice 2</label>
+ <input type="radio" id="radio13" name="radio"><label for="radio13">Choice 3</label>
+ </div>
+</form>
+<form>
+ <div id="radio2" style="margin-top: 2em;">
+ <input type="radio" id="radio21" name="radio"><label for="radio21">Choice 1</label>
+ <input type="radio" id="radio22" name="radio"><label for="radio22">Choice 2</label>
+ <input type="radio" id="radio23" name="radio" checked="checked"><label for="radio23">Choice 3</label>
+ </div>
+</form>
+<form>
+ <div id="radio3">
+ <input type="radio" id="radio31" name="data['Page']['parse']"><label for="radio31">Choice 1</label>
+ <input type="radio" id="radio32" name="data['Page']['parse']" checked="checked"><label for="radio32">Choice 2</label>
+ <input type="radio" id="radio33" name="data['Page']['parse']"><label for="radio33">Choice 3</label>
+ </div>
+</form>
+
+<input type="checkbox" id="check"><label for="check">Toggle</label>
+<input type="checkbox" id="check2"><label for="check2">Checkbox</label>
+
+<div><input id="submit" type="submit" value="Label"></div>
+
+<button id="button1">Button</button>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/button/button_common.js b/apps/it/static/js/ui/tests/unit/button/button_common.js
new file mode 100644
index 0000000..ef22d30
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/button/button_common.js
@@ -0,0 +1,14 @@
+TestHelpers.commonWidgetTests( "button", {
+ defaults: {
+ disabled: null,
+ icons: {
+ primary: null,
+ secondary: null
+ },
+ label: null,
+ text: true,
+
+ // callbacks
+ create: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/button/button_core.js b/apps/it/static/js/ui/tests/unit/button/button_core.js
new file mode 100644
index 0000000..41623e0
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/button/button_core.js
@@ -0,0 +1,212 @@
+/*
+ * button_core.js
+ */
+
+
+(function($) {
+
+module("button: core");
+
+test("checkbox", function() {
+ expect( 4 );
+ var input = $("#check"),
+ label = $("label[for=check]");
+ ok( input.is(":visible") );
+ ok( label.is(":not(.ui-button)") );
+ input.button();
+ ok( input.is(".ui-helper-hidden-accessible") );
+ ok( label.is(".ui-button") );
+});
+
+test("radios", function() {
+ expect( 4 );
+ var inputs = $("#radio0 input"),
+ labels = $("#radio0 label");
+ ok( inputs.is(":visible") );
+ ok( labels.is(":not(.ui-button)") );
+ inputs.button();
+ ok( inputs.is(".ui-helper-hidden-accessible") );
+ ok( labels.is(".ui-button") );
+});
+
+function assert(noForm, form1, form2) {
+ ok( $("#radio0 .ui-button" + noForm).is(".ui-state-active") );
+ ok( $("#radio1 .ui-button" + form1).is(".ui-state-active") );
+ ok( $("#radio2 .ui-button" + form2).is(".ui-state-active") );
+}
+
+test("radio groups", function() {
+ expect( 12 );
+ $("input[type=radio]").button();
+ assert(":eq(0)", ":eq(1)", ":eq(2)");
+
+ // click outside of forms
+ $("#radio0 .ui-button:eq(1)").click();
+ assert(":eq(1)", ":eq(1)", ":eq(2)");
+
+ // click in first form
+ $("#radio1 .ui-button:eq(0)").click();
+ assert(":eq(1)", ":eq(0)", ":eq(2)");
+
+ // click in second form
+ $("#radio2 .ui-button:eq(0)").click();
+ assert(":eq(1)", ":eq(0)", ":eq(0)");
+});
+
+test("input type submit, don't create child elements", function() {
+ expect( 2 );
+ var input = $("#submit");
+ deepEqual( input.children().length, 0 );
+ input.button();
+ deepEqual( input.children().length, 0 );
+});
+
+test("buttonset", function() {
+ expect( 6 );
+ var set = $("#radio1").buttonset();
+ ok( set.is(".ui-buttonset") );
+ deepEqual( set.children(".ui-button").length, 3 );
+ deepEqual( set.children("input[type=radio].ui-helper-hidden-accessible").length, 3 );
+ ok( set.children("label:eq(0)").is(".ui-button.ui-corner-left:not(.ui-corner-all)") );
+ ok( set.children("label:eq(1)").is(".ui-button:not(.ui-corner-all)") );
+ ok( set.children("label:eq(2)").is(".ui-button.ui-corner-right:not(.ui-corner-all)") );
+});
+
+test("buttonset (rtl)", function() {
+ expect( 6 );
+ var set,
+ parent = $("#radio1").parent();
+ // Set to rtl
+ parent.attr("dir", "rtl");
+
+ set = $("#radio1").buttonset();
+ ok( set.is(".ui-buttonset") );
+ deepEqual( set.children(".ui-button").length, 3 );
+ deepEqual( set.children("input[type=radio].ui-helper-hidden-accessible").length, 3 );
+ ok( set.children("label:eq(0)").is(".ui-button.ui-corner-right:not(.ui-corner-all)") );
+ ok( set.children("label:eq(1)").is(".ui-button:not(.ui-corner-all)") );
+ ok( set.children("label:eq(2)").is(".ui-button.ui-corner-left:not(.ui-corner-all)") );
+});
+
+// TODO: simulated click events don't behave like real click events in IE
+// remove this when simulate properly simulates this
+// see http://yuilibrary.com/projects/yui2/ticket/2528826 fore more info
+if ( !$.ui.ie || ( document.documentMode && document.documentMode > 8 ) ) {
+ asyncTest( "ensure checked and aria after single click on checkbox label button, see #5518", function() {
+ expect( 3 );
+
+ $("#check2").button().change( function() {
+ var lbl = $( this ).button("widget");
+ ok( this.checked, "checked ok" );
+ ok( lbl.attr("aria-pressed") === "true", "aria ok" );
+ ok( lbl.hasClass("ui-state-active"), "ui-state-active ok" );
+ });
+
+ // support: Opera
+ // Opera doesn't trigger a change event when this is done synchronously.
+ // This seems to be a side effect of another test, but until that can be
+ // tracked down, this delay will have to do.
+ setTimeout(function() {
+ $("#check2").button("widget").simulate("click");
+ start();
+ }, 1 );
+ });
+}
+
+test( "#7092 - button creation that requires a matching label does not find label in all cases", function() {
+ expect( 5 );
+ var group = $( "<span><label for='t7092a'></label><input type='checkbox' id='t7092a'></span>" );
+ group.find( "input[type=checkbox]" ).button();
+ ok( group.find( "label" ).is( ".ui-button" ) );
+
+ group = $( "<input type='checkbox' id='t7092b'><label for='t7092b'></label>" );
+ group.filter( "input[type=checkbox]" ).button();
+ ok( group.filter( "label" ).is( ".ui-button" ) );
+
+ group = $( "<span><input type='checkbox' id='t7092c'></span><label for='t7092c'></label>" );
+ group.find( "input[type=checkbox]" ).button();
+ ok( group.filter( "label" ).is( ".ui-button" ) );
+
+ group = $( "<span><input type='checkbox' id='t7092d'></span><span><label for='t7092d'></label></span>" );
+ group.find( "input[type=checkbox]" ).button();
+ ok( group.find( "label" ).is( ".ui-button" ) );
+
+ group = $( "<input type='checkbox' id='t7092e'><span><label for='t7092e'></label></span>" );
+ group.filter( "input[type=checkbox]" ).button();
+ ok( group.find( "label" ).is( ".ui-button" ) );
+});
+
+test( "#5946 - buttonset should ignore buttons that are not :visible", function() {
+ expect( 2 );
+ $( "#radio01" ).next().addBack().hide();
+ var set = $( "#radio0" ).buttonset({ items: "input[type=radio]:visible" });
+ ok( set.find( "label:eq(0)" ).is( ":not(.ui-button):not(.ui-corner-left)" ) );
+ ok( set.find( "label:eq(1)" ).is( ".ui-button.ui-corner-left" ) );
+});
+
+test( "#6262 - buttonset not applying ui-corner to invisible elements", function() {
+ expect( 3 );
+ $( "#radio0" ).hide();
+ var set = $( "#radio0" ).buttonset();
+ ok( set.find( "label:eq(0)" ).is( ".ui-button.ui-corner-left" ) );
+ ok( set.find( "label:eq(1)" ).is( ".ui-button" ) );
+ ok( set.find( "label:eq(2)" ).is( ".ui-button.ui-corner-right" ) );
+});
+
+asyncTest( "Resetting a button's form should refresh the visual state of the button widget to match.", function() {
+ expect( 2 );
+ var form = $( "<form>" +
+ "<button></button>" +
+ "<label for='c1'></label><input id='c1' type='checkbox' checked>" +
+ "</form>" ),
+ button = form.find( "button" ).button(),
+ checkbox = form.find( "input[type=checkbox]" ).button();
+
+ checkbox.prop( "checked", false ).button( "refresh" );
+ ok( !checkbox.button( "widget" ).hasClass( "ui-state-active" ) );
+
+ form.get( 0 ).reset();
+
+ // #9213: If a button has been removed, refresh should not be called on it when
+ // its corresponding form is reset.
+ button.remove();
+
+ setTimeout(function() {
+ ok( checkbox.button( "widget" ).hasClass( "ui-state-active" ));
+ start();
+ }, 1 );
+});
+
+asyncTest( "#6711 Checkbox/Radiobutton do not Show Focused State when using Keyboard Navigation", function() {
+ expect( 2 );
+ var check = $( "#check" ).button(),
+ label = $( "label[for='check']" );
+ ok( !label.is( ".ui-state-focus" ) );
+ check.focus();
+ setTimeout(function() {
+ ok( label.is( ".ui-state-focus" ) );
+ start();
+ });
+});
+
+test( "#7534 - Button label selector works for ids with \":\"", function() {
+ expect( 1 );
+ var group = $( "<span><input type='checkbox' id='check:7534'><label for='check:7534'>Label</label></span>" );
+ group.find( "input" ).button();
+ ok( group.find( "label" ).is( ".ui-button" ), "Found an id with a :" );
+});
+
+asyncTest( "#9169 - Disabled button maintains ui-state-focus", function() {
+ expect( 2 );
+ var element = $( "#button1" ).button();
+ element[ 0 ].focus();
+ setTimeout(function() {
+ ok( element.hasClass( "ui-state-focus" ), "button has ui-state-focus" );
+ element.button( "disable" );
+ ok( !element.hasClass( "ui-state-focus" ),
+ "button does not have ui-state-focus when disabled" );
+ start();
+ });
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/button/button_events.js b/apps/it/static/js/ui/tests/unit/button/button_events.js
new file mode 100644
index 0000000..2fd0383
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/button/button_events.js
@@ -0,0 +1,36 @@
+/*
+ * button_events.js
+ */
+(function($) {
+
+module("button: events");
+
+test("buttonset works with single-quote named elements (#7505)", function() {
+ expect( 1 );
+ $("#radio3").buttonset();
+ $("#radio33").click( function(){
+ ok( true, "button clicks work with single-quote named elements" );
+ }).click();
+});
+
+asyncTest( "when button loses focus, ensure active state is removed (#8559)", function() {
+ expect( 1 );
+
+ var element = $( "#button" ).button();
+
+ element.one( "keypress", function() {
+ element.one( "blur", function() {
+ ok( !element.is(".ui-state-active"), "button loses active state appropriately" );
+ start();
+ }).blur();
+ });
+
+ element.focus();
+ setTimeout(function() {
+ element
+ .simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } )
+ .simulate( "keypress", { keyCode: $.ui.keyCode.ENTER } );
+ });
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/button/button_methods.js b/apps/it/static/js/ui/tests/unit/button/button_methods.js
new file mode 100644
index 0000000..467938f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/button/button_methods.js
@@ -0,0 +1,52 @@
+/*
+ * button_methods.js
+ */
+(function($) {
+
+
+module("button: methods");
+
+test("destroy", function() {
+ expect( 1 );
+ domEqual( "#button", function() {
+ $( "#button" ).button().button( "destroy" );
+ });
+});
+
+test( "refresh: Ensure disabled state is preserved correctly.", function() {
+ expect( 8 );
+
+ var element = $( "<a href='#'></a>" );
+ element.button({ disabled: true }).button( "refresh" );
+ ok( element.button( "option", "disabled" ), "Anchor button should remain disabled after refresh" ); //See #8237
+
+ element = $( "<div></div>" );
+ element.button({ disabled: true }).button( "refresh" );
+ ok( element.button( "option", "disabled" ), "<div> buttons should remain disabled after refresh" );
+
+ element = $( "<button></button>" );
+ element.button( { disabled: true} ).button( "refresh" );
+ ok( element.button( "option", "disabled" ), "<button> should remain disabled after refresh");
+
+ element = $( "<input type='checkbox'>" );
+ element.button( { disabled: true} ).button( "refresh" );
+ ok( element.button( "option", "disabled" ), "Checkboxes should remain disabled after refresh");
+
+ element = $( "<input type='radio'>" );
+ element.button( { disabled: true} ).button( "refresh" );
+ ok( element.button( "option", "disabled" ), "Radio buttons should remain disabled after refresh");
+
+ element = $( "<button></button>" );
+ element.button( { disabled: true} ).prop( "disabled", false ).button( "refresh" );
+ ok( !element.button( "option", "disabled" ), "Changing a <button>'s disabled property should update the state after refresh."); //See #8828
+
+ element = $( "<input type='checkbox'>" );
+ element.button( { disabled: true} ).prop( "disabled", false ).button( "refresh" );
+ ok( !element.button( "option", "disabled" ), "Changing a checkbox's disabled property should update the state after refresh.");
+
+ element = $( "<input type='radio'>" );
+ element.button( { disabled: true} ).prop( "disabled", false ).button( "refresh" );
+ ok( !element.button( "option", "disabled" ), "Changing a radio button's disabled property should update the state after refresh.");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/button/button_options.js b/apps/it/static/js/ui/tests/unit/button/button_options.js
new file mode 100644
index 0000000..e1931a5
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/button/button_options.js
@@ -0,0 +1,117 @@
+/*
+ * button_options.js
+ */
+(function($) {
+
+module("button: options");
+
+test("disabled, explicit value", function() {
+ expect( 4 );
+ $("#radio01").button({ disabled: false });
+ deepEqual(false, $("#radio01").button("option", "disabled"),
+ "disabled option set to false");
+ deepEqual(false, $("#radio01").prop("disabled"), "element is disabled");
+
+ $("#radio02").button({ disabled: true });
+ deepEqual(true, $("#radio02").button("option", "disabled"),
+ "disabled option set to true");
+ deepEqual(true, $("#radio02").prop("disabled"), "element is not disabled");
+});
+
+test("disabled, null", function() {
+ expect( 4 );
+ $("#radio01").button({ disabled: null });
+ deepEqual(false, $("#radio01").button("option", "disabled"),
+ "disabled option set to false");
+ deepEqual(false, $("#radio01").prop("disabled"), "element is disabled");
+
+ $("#radio02").prop("disabled", true).button({ disabled: null });
+ deepEqual(true, $("#radio02").button("option", "disabled"),
+ "disabled option set to true");
+ deepEqual(true, $("#radio02").prop("disabled"), "element is not disabled");
+});
+
+test("text false without icon", function() {
+ expect( 1 );
+ $("#button").button({
+ text: false
+ });
+ ok( $("#button").is(".ui-button-text-only:not(.ui-button-icon-only)") );
+
+ $("#button").button("destroy");
+});
+
+test("text false with icon", function() {
+ expect( 1 );
+ $("#button").button({
+ text: false,
+ icons: {
+ primary: "iconclass"
+ }
+ });
+ ok( $("#button").is(".ui-button-icon-only:not(.ui-button-text):has(span.ui-icon.iconclass)") );
+
+ $("#button").button("destroy");
+});
+
+test("label, default", function() {
+ expect( 2 );
+ $("#button").button();
+ deepEqual( $("#button").text(), "Label" );
+ deepEqual( $( "#button").button( "option", "label" ), "Label" );
+
+ $("#button").button("destroy");
+});
+
+test("label", function() {
+ expect( 2 );
+ $("#button").button({
+ label: "xxx"
+ });
+ deepEqual( $("#button").text(), "xxx" );
+ deepEqual( $("#button").button( "option", "label" ), "xxx" );
+
+ $("#button").button("destroy");
+});
+
+test("label default with input type submit", function() {
+ expect( 2 );
+ deepEqual( $("#submit").button().val(), "Label" );
+ deepEqual( $("#submit").button( "option", "label" ), "Label" );
+});
+
+test("label with input type submit", function() {
+ expect( 2 );
+ var label = $("#submit").button({
+ label: "xxx"
+ }).val();
+ deepEqual( label, "xxx" );
+ deepEqual( $("#submit").button( "option", "label" ), "xxx" );
+});
+
+test("icons", function() {
+ expect( 1 );
+ $("#button").button({
+ text: false,
+ icons: {
+ primary: "iconclass",
+ secondary: "iconclass2"
+ }
+ });
+ ok( $("#button").is(":has(span.ui-icon.ui-button-icon-primary.iconclass):has(span.ui-icon.ui-button-icon-secondary.iconclass2)") );
+
+ $("#button").button("destroy");
+});
+
+test( "#5295 - button does not remove hoverstate if disabled" , function() {
+ expect( 1 );
+ var btn = $("#button").button();
+ btn.hover( function() {
+ btn.button( "disable" );
+ });
+ btn.trigger( "mouseenter" );
+ btn.trigger( "mouseleave" );
+ ok( !btn.is( ".ui-state-hover") );
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/core/all.html b/apps/it/static/js/ui/tests/unit/core/all.html
new file mode 100644
index 0000000..b24a472
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/core/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Core Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "core" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Core Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/core/core.html b/apps/it/static/js/ui/tests/unit/core/core.html
new file mode 100644
index 0000000..41c8db8
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/core/core.html
@@ -0,0 +1,135 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Core Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ js: [ "ui/jquery.ui.core.js" ]
+ });
+ </script>
+
+ <script src="core.js"></script>
+ <script src="selector.js"></script>
+
+ <script src="../swarminject.js"></script>
+ <style>
+ .zindex {
+ z-index: 100;
+ }
+ .absolute {
+ position: absolute;
+ }
+ </style>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Core Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<img src="../images/jqueryui_32x32.png" usemap="#mymap" width="10" height="10" alt="">
+<map name="mymap">
+ <area shape="rect" coords="1,1,2,2" href="foo.html" id="areaCoordsHref" alt="">
+ <area href="foo.html" id="areaNoCoordsHref" alt="">
+</map>
+<map name="mymap2">
+ <area shape="rect" coords="1,1,2,2" href="foo.html" id="areaNoImg" alt="">
+</map>
+
+<form id="formNoTabindex"></form>
+<form id="formTabindex" tabindex="1"></form>
+
+<div>
+ <input id="visibleAncestor-inputTypeNone">
+ <input type="text" id="visibleAncestor-inputTypeText">
+ <input type="checkbox" id="visibleAncestor-inputTypeCheckbox">
+ <input type="radio" id="visibleAncestor-inputTypeRadio">
+ <input type="button" id="visibleAncestor-inputTypeButton" value="visibleAncestor-inputTypeButton">
+ <input type="hidden" id="visibleAncestor-inputTypeHidden">
+ <button id="visibleAncestor-button">x</button>
+ <select id="visibleAncestor-select">
+ <option>option</option>
+ </select>
+ <textarea id="visibleAncestor-textarea">x</textarea>
+ <object id="visibleAncestor-object" codebase="about:blank">xxx</object>
+ <a href="#" id="visibleAncestor-anchorWithHref">anchor</a>
+ <a id="visibleAncestor-anchorWithoutHref">anchor</a>
+ <span id="visibleAncestor-span">x</span>
+ <div id="visibleAncestor-div">x</div>
+ <span id="visibleAncestor-spanWithTabindex" tabindex="1">x</span>
+ <div id="visibleAncestor-divWithNegativeTabindex" tabindex="-1">x</div>
+</div>
+
+<div>
+ <input id="disabledElement-inputTypeNone" disabled="disabled">
+ <input type="text" id="disabledElement-inputTypeText" disabled="disabled">
+ <input type="checkbox" id="disabledElement-inputTypeCheckbox" disabled="disabled">
+ <input type="radio" id="disabledElement-inputTypeRadio" disabled="disabled">
+ <input type="button" id="disabledElement-inputTypeButton" disabled="disabled" value="disabledElement-inputTypeButton">
+ <input type="hidden" id="disabledElement-inputTypeHidden" disabled="disabled">
+ <button id="disabledElement-button" disabled="disabled"></button>
+ <select id="disabledElement-select" disabled="disabled"></select>
+ <textarea id="disabledElement-textarea" disabled="disabled"></textarea>
+</div>
+
+<div>
+ <div id="displayNoneAncestor" style="display: none;">
+ <input id="displayNoneAncestor-input">
+ <span tabindex="1" id="displayNoneAncestor-span">.</span>
+ </div>
+
+ <div id="visibilityHiddenAncestor" style="visibility: hidden;">
+ <input id="visibilityHiddenAncestor-input">
+ <span tabindex="1" id="visibilityHiddenAncestor-span">.</span>
+ </div>
+
+ <span tabindex="1" id="displayNone-span" style="display: none;">.</span>
+ <span tabindex="1" id="visibilityHidden-span" style="visibility: hidden;">.</span>
+
+ <input id="displayNone-input" style="display: none;">
+ <input id="visibilityHidden-input" style="visibility: hidden;">
+</div>
+
+<div>
+ <input id="inputTabindex0" tabindex="0">
+ <input id="inputTabindex10" tabindex="10">
+ <input id="inputTabindex-1" tabindex="-1">
+ <input id="inputTabindex-50" tabindex="-50">
+
+ <span id="spanTabindex0" tabindex="0">.</span>
+ <span id="spanTabindex10" tabindex="10">.</span>
+ <span id="spanTabindex-1" tabindex="-1">.</span>
+ <span id="spanTabindex-50" tabindex="-50">.</span>
+</div>
+
+<div style="width: 0; height: 0;">
+ <input id="dimensionlessParent">
+ <input id="dimensionlessParent-dimensionless" style="height: 0; width: 0;">
+</div>
+
+<div id="zIndex100" style="z-index: 100; position: absolute">
+ <div id="zIndexAutoWithParent">.</div>
+</div>
+<div id="zIndex100ViaCSS" class="zindex">
+ <div id="zIndexAutoWithParentViaCSS">.</div>
+</div>
+<div id="zIndex100ViaCSSPositioned" class="zindex absolute">
+ <div id="zIndexAutoWithParentViaCSSPositioned">.</div>
+</div>
+<div id="zIndexAutoNoParent"></div>
+
+<div id="dimensions" style="float: left; height: 50px; width: 100px; margin: 1px 12px 11px 2px; border-style: solid; border-width: 3px 14px 13px 4px; padding: 5px 16px 15px 6px;"></div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/core/core.js b/apps/it/static/js/ui/tests/unit/core/core.js
new file mode 100644
index 0000000..ab19aad
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/core/core.js
@@ -0,0 +1,191 @@
+(function( $ ) {
+
+module( "core - jQuery extensions" );
+
+TestHelpers.testJshint( "core" );
+
+asyncTest( "focus - original functionality", function() {
+ expect( 1 );
+ $( "#inputTabindex0" )
+ .one( "focus", function() {
+ ok( true, "event triggered" );
+ start();
+ })
+ .focus();
+});
+
+asyncTest( "focus", function() {
+ expect( 2 );
+
+ // support: IE 8
+ // IE sometimes gets confused about what's focused if we don't explicitly
+ // focus a different element first
+ $( "body" ).focus();
+
+ $( "#inputTabindex0" )
+ .one( "focus", function() {
+ ok( true, "event triggered" );
+ start();
+ })
+ .focus( 500, function() {
+ ok( true, "callback triggered" );
+ });
+});
+
+test( "zIndex", function() {
+ expect( 7 );
+ var el = $( "#zIndexAutoWithParent" ),
+ parent = el.parent();
+ equal( el.zIndex(), 100, "zIndex traverses up to find value" );
+ equal( parent.zIndex(200 ), parent, "zIndex setter is chainable" );
+ equal( el.zIndex(), 200, "zIndex setter changed zIndex" );
+
+ el = $( "#zIndexAutoWithParentViaCSS" );
+ equal( el.zIndex(), 0, "zIndex traverses up to find CSS value, not found because not positioned" );
+
+ el = $( "#zIndexAutoWithParentViaCSSPositioned" );
+ equal( el.zIndex(), 100, "zIndex traverses up to find CSS value" );
+ el.parent().zIndex( 200 );
+ equal( el.zIndex(), 200, "zIndex setter changed zIndex, overriding CSS" );
+
+ equal( $( "#zIndexAutoNoParent" ).zIndex(), 0, "zIndex never explicitly set in hierarchy" );
+});
+
+test( "innerWidth - getter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ equal( el.innerWidth(), 122, "getter passthru" );
+ el.hide();
+ equal( el.innerWidth(), 122, "getter passthru when hidden" );
+});
+
+test( "innerWidth - setter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ el.innerWidth( 120 );
+ equal( el.width(), 98, "width set properly" );
+ el.hide();
+ el.innerWidth( 100 );
+ equal( el.width(), 78, "width set properly when hidden" );
+});
+
+test( "innerHeight - getter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ equal( el.innerHeight(), 70, "getter passthru" );
+ el.hide();
+ equal( el.innerHeight(), 70, "getter passthru when hidden" );
+});
+
+test( "innerHeight - setter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ el.innerHeight( 60 );
+ equal( el.height(), 40, "height set properly" );
+ el.hide();
+ el.innerHeight( 50 );
+ equal( el.height(), 30, "height set properly when hidden" );
+});
+
+test( "outerWidth - getter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ equal( el.outerWidth(), 140, "getter passthru" );
+ el.hide();
+ equal( el.outerWidth(), 140, "getter passthru when hidden" );
+});
+
+test( "outerWidth - setter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ el.outerWidth( 130 );
+ equal( el.width(), 90, "width set properly" );
+ el.hide();
+ el.outerWidth( 120 );
+ equal( el.width(), 80, "width set properly when hidden" );
+});
+
+test( "outerWidth(true) - getter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ equal( el.outerWidth(true), 154, "getter passthru w/ margin" );
+ el.hide();
+ equal( el.outerWidth(true), 154, "getter passthru w/ margin when hidden" );
+});
+
+test( "outerWidth(true) - setter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ el.outerWidth( 130, true );
+ equal( el.width(), 76, "width set properly" );
+ el.hide();
+ el.outerWidth( 120, true );
+ equal( el.width(), 66, "width set properly when hidden" );
+});
+
+test( "outerHeight - getter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ equal( el.outerHeight(), 86, "getter passthru" );
+ el.hide();
+ equal( el.outerHeight(), 86, "getter passthru when hidden" );
+});
+
+test( "outerHeight - setter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ el.outerHeight( 80 );
+ equal( el.height(), 44, "height set properly" );
+ el.hide();
+ el.outerHeight( 70 );
+ equal( el.height(), 34, "height set properly when hidden" );
+});
+
+test( "outerHeight(true) - getter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ equal( el.outerHeight(true), 98, "getter passthru w/ margin" );
+ el.hide();
+ equal( el.outerHeight(true), 98, "getter passthru w/ margin when hidden" );
+});
+
+test( "outerHeight(true) - setter", function() {
+ expect( 2 );
+ var el = $( "#dimensions" );
+
+ el.outerHeight( 90, true );
+ equal( el.height(), 42, "height set properly" );
+ el.hide();
+ el.outerHeight( 80, true );
+ equal( el.height(), 32, "height set properly when hidden" );
+});
+
+test( "uniqueId / removeUniqueId", function() {
+ expect( 3 );
+ var el = $( "img" ).eq( 0 );
+
+ // support: jQuery <1.6.2
+ // support: IE <8
+ // We should use strictEqual( id, undefined ) when dropping jQuery 1.6.1 support (or IE6/7)
+ ok( !el.attr( "id" ), "element has no initial id" );
+ el.uniqueId();
+ ok( /ui-id-\d+$/.test( el.attr( "id" ) ), "element has generated id" );
+ el.removeUniqueId();
+ // support: jQuery <1.6.2
+ // support: IE <8
+ // see above
+ ok( !el.attr( "id" ), "unique id has been removed from element" );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/core/selector.js b/apps/it/static/js/ui/tests/unit/core/selector.js
new file mode 100644
index 0000000..f86526b
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/core/selector.js
@@ -0,0 +1,251 @@
+/*
+ * selector unit tests
+ */
+(function($) {
+
+module("core - selectors");
+
+function isFocusable(selector, msg) {
+ QUnit.push($(selector).is(":focusable"), null, null, msg + " - selector " + selector + " is focusable");
+}
+
+function isNotFocusable(selector, msg) {
+ QUnit.push($(selector).length && !$(selector).is(":focusable"), null, null, msg + " - selector " + selector + " is not focusable");
+}
+
+function isTabbable(selector, msg) {
+ QUnit.push($(selector).is(":tabbable"), null, null, msg + " - selector " + selector + " is tabbable");
+}
+
+function isNotTabbable(selector, msg) {
+ QUnit.push($(selector).length && !$(selector).is(":tabbable"), null, null, msg + " - selector " + selector + " is not tabbable");
+}
+
+test("data", function() {
+ expect(15);
+
+ var el;
+ function shouldHaveData(msg) {
+ ok(el.is(":data(test)"), msg);
+ }
+ function shouldNotHaveData(msg) {
+ ok(!el.is(":data(test)"), msg);
+ }
+
+ el = $("<div>");
+ shouldNotHaveData("data never set");
+
+ el = $("<div>").data("test", null);
+ shouldNotHaveData("data is null");
+
+ el = $("<div>").data("test", true);
+ shouldHaveData("data set to true");
+
+ el = $("<div>").data("test", false);
+ shouldNotHaveData("data set to false");
+
+ el = $("<div>").data("test", 0);
+ shouldNotHaveData("data set to 0");
+
+ el = $("<div>").data("test", 1);
+ shouldHaveData("data set to 1");
+
+ el = $("<div>").data("test", "");
+ shouldNotHaveData("data set to empty string");
+
+ el = $("<div>").data("test", "foo");
+ shouldHaveData("data set to string");
+
+ el = $("<div>").data("test", []);
+ shouldHaveData("data set to empty array");
+
+ el = $("<div>").data("test", [1]);
+ shouldHaveData("data set to array");
+
+ el = $("<div>").data("test", {});
+ shouldHaveData("data set to empty object");
+
+ el = $("<div>").data("test", {foo: "bar"});
+ shouldHaveData("data set to object");
+
+ el = $("<div>").data("test", new Date());
+ shouldHaveData("data set to date");
+
+ el = $("<div>").data("test", /test/);
+ shouldHaveData("data set to regexp");
+
+ el = $("<div>").data("test", function() {});
+ shouldHaveData("data set to function");
+});
+
+test("focusable - visible, enabled elements", function() {
+ expect(18);
+
+ isNotFocusable("#formNoTabindex", "form");
+ isFocusable("#formTabindex", "form with tabindex");
+ isFocusable("#visibleAncestor-inputTypeNone", "input, no type");
+ isFocusable("#visibleAncestor-inputTypeText", "input, type text");
+ isFocusable("#visibleAncestor-inputTypeCheckbox", "input, type checkbox");
+ isFocusable("#visibleAncestor-inputTypeRadio", "input, type radio");
+ isFocusable("#visibleAncestor-inputTypeButton", "input, type button");
+ isNotFocusable("#visibleAncestor-inputTypeHidden", "input, type hidden");
+ isFocusable("#visibleAncestor-button", "button");
+ isFocusable("#visibleAncestor-select", "select");
+ isFocusable("#visibleAncestor-textarea", "textarea");
+ isFocusable("#visibleAncestor-object", "object");
+ isFocusable("#visibleAncestor-anchorWithHref", "anchor with href");
+ isNotFocusable("#visibleAncestor-anchorWithoutHref", "anchor without href");
+ isNotFocusable("#visibleAncestor-span", "span");
+ isNotFocusable("#visibleAncestor-div", "div");
+ isFocusable("#visibleAncestor-spanWithTabindex", "span with tabindex");
+ isFocusable("#visibleAncestor-divWithNegativeTabindex", "div with tabindex");
+});
+
+test("focusable - disabled elements", function() {
+ expect(9);
+
+ isNotFocusable("#disabledElement-inputTypeNone", "input, no type");
+ isNotFocusable("#disabledElement-inputTypeText", "input, type text");
+ isNotFocusable("#disabledElement-inputTypeCheckbox", "input, type checkbox");
+ isNotFocusable("#disabledElement-inputTypeRadio", "input, type radio");
+ isNotFocusable("#disabledElement-inputTypeButton", "input, type button");
+ isNotFocusable("#disabledElement-inputTypeHidden", "input, type hidden");
+ isNotFocusable("#disabledElement-button", "button");
+ isNotFocusable("#disabledElement-select", "select");
+ isNotFocusable("#disabledElement-textarea", "textarea");
+});
+
+test("focusable - hidden styles", function() {
+ expect(8);
+
+ isNotFocusable("#displayNoneAncestor-input", "input, display: none parent");
+ isNotFocusable("#displayNoneAncestor-span", "span with tabindex, display: none parent");
+
+ isNotFocusable("#visibilityHiddenAncestor-input", "input, visibility: hidden parent");
+ isNotFocusable("#visibilityHiddenAncestor-span", "span with tabindex, visibility: hidden parent");
+
+ isNotFocusable("#displayNone-input", "input, display: none");
+ isNotFocusable("#visibilityHidden-input", "input, visibility: hidden");
+
+ isNotFocusable("#displayNone-span", "span with tabindex, display: none");
+ isNotFocusable("#visibilityHidden-span", "span with tabindex, visibility: hidden");
+});
+
+test("focusable - natively focusable with various tabindex", function() {
+ expect(4);
+
+ isFocusable("#inputTabindex0", "input, tabindex 0");
+ isFocusable("#inputTabindex10", "input, tabindex 10");
+ isFocusable("#inputTabindex-1", "input, tabindex -1");
+ isFocusable("#inputTabindex-50", "input, tabindex -50");
+});
+
+test("focusable - not natively focusable with various tabindex", function() {
+ expect(4);
+
+ isFocusable("#spanTabindex0", "span, tabindex 0");
+ isFocusable("#spanTabindex10", "span, tabindex 10");
+ isFocusable("#spanTabindex-1", "span, tabindex -1");
+ isFocusable("#spanTabindex-50", "span, tabindex -50");
+});
+
+test("focusable - area elements", function() {
+ expect( 3 );
+
+ isFocusable("#areaCoordsHref", "coords and href");
+ isFocusable("#areaNoCoordsHref", "href but no coords");
+ isNotFocusable("#areaNoImg", "not associated with an image");
+});
+
+test( "focusable - dimensionless parent with overflow", function() {
+ expect( 1 );
+
+ isFocusable( "#dimensionlessParent", "input" );
+});
+
+test("tabbable - visible, enabled elements", function() {
+ expect(18);
+
+ isNotTabbable("#formNoTabindex", "form");
+ isTabbable("#formTabindex", "form with tabindex");
+ isTabbable("#visibleAncestor-inputTypeNone", "input, no type");
+ isTabbable("#visibleAncestor-inputTypeText", "input, type text");
+ isTabbable("#visibleAncestor-inputTypeCheckbox", "input, type checkbox");
+ isTabbable("#visibleAncestor-inputTypeRadio", "input, type radio");
+ isTabbable("#visibleAncestor-inputTypeButton", "input, type button");
+ isNotTabbable("#visibleAncestor-inputTypeHidden", "input, type hidden");
+ isTabbable("#visibleAncestor-button", "button");
+ isTabbable("#visibleAncestor-select", "select");
+ isTabbable("#visibleAncestor-textarea", "textarea");
+ isTabbable("#visibleAncestor-object", "object");
+ isTabbable("#visibleAncestor-anchorWithHref", "anchor with href");
+ isNotTabbable("#visibleAncestor-anchorWithoutHref", "anchor without href");
+ isNotTabbable("#visibleAncestor-span", "span");
+ isNotTabbable("#visibleAncestor-div", "div");
+ isTabbable("#visibleAncestor-spanWithTabindex", "span with tabindex");
+ isNotTabbable("#visibleAncestor-divWithNegativeTabindex", "div with tabindex");
+});
+
+test("tabbable - disabled elements", function() {
+ expect(9);
+
+ isNotTabbable("#disabledElement-inputTypeNone", "input, no type");
+ isNotTabbable("#disabledElement-inputTypeText", "input, type text");
+ isNotTabbable("#disabledElement-inputTypeCheckbox", "input, type checkbox");
+ isNotTabbable("#disabledElement-inputTypeRadio", "input, type radio");
+ isNotTabbable("#disabledElement-inputTypeButton", "input, type button");
+ isNotTabbable("#disabledElement-inputTypeHidden", "input, type hidden");
+ isNotTabbable("#disabledElement-button", "button");
+ isNotTabbable("#disabledElement-select", "select");
+ isNotTabbable("#disabledElement-textarea", "textarea");
+});
+
+test("tabbable - hidden styles", function() {
+ expect(8);
+
+ isNotTabbable("#displayNoneAncestor-input", "input, display: none parent");
+ isNotTabbable("#displayNoneAncestor-span", "span with tabindex, display: none parent");
+
+ isNotTabbable("#visibilityHiddenAncestor-input", "input, visibility: hidden parent");
+ isNotTabbable("#visibilityHiddenAncestor-span", "span with tabindex, visibility: hidden parent");
+
+ isNotTabbable("#displayNone-input", "input, display: none");
+ isNotTabbable("#visibilityHidden-input", "input, visibility: hidden");
+
+ isNotTabbable("#displayNone-span", "span with tabindex, display: none");
+ isNotTabbable("#visibilityHidden-span", "span with tabindex, visibility: hidden");
+});
+
+test("tabbable - natively tabbable with various tabindex", function() {
+ expect(4);
+
+ isTabbable("#inputTabindex0", "input, tabindex 0");
+ isTabbable("#inputTabindex10", "input, tabindex 10");
+ isNotTabbable("#inputTabindex-1", "input, tabindex -1");
+ isNotTabbable("#inputTabindex-50", "input, tabindex -50");
+});
+
+test("tabbable - not natively tabbable with various tabindex", function() {
+ expect(4);
+
+ isTabbable("#spanTabindex0", "span, tabindex 0");
+ isTabbable("#spanTabindex10", "span, tabindex 10");
+ isNotTabbable("#spanTabindex-1", "span, tabindex -1");
+ isNotTabbable("#spanTabindex-50", "span, tabindex -50");
+});
+
+test("tabbable - area elements", function() {
+ expect( 3 );
+
+ isTabbable("#areaCoordsHref", "coords and href");
+ isTabbable("#areaNoCoordsHref", "href but no coords");
+ isNotTabbable("#areaNoImg", "not associated with an image");
+});
+
+test( "tabbable - dimensionless parent with overflow", function() {
+ expect( 1 );
+
+ isTabbable( "#dimensionlessParent", "input" );
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/all.html b/apps/it/static/js/ui/tests/unit/datepicker/all.html
new file mode 100644
index 0000000..a5b68ed
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Datepicker Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "datepicker" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Datepicker Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/datepicker.html b/apps/it/static/js/ui/tests/unit/datepicker/datepicker.html
new file mode 100644
index 0000000..8ef2de5
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/datepicker.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Datepicker Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.datepicker" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.datepicker.js",
+ "ui/i18n/jquery.ui.datepicker-fr.js",
+ "ui/i18n/jquery.ui.datepicker-he.js",
+ "ui/i18n/jquery.ui.datepicker-zh-CN.js"
+ ]
+ });
+ </script>
+
+ <script src="datepicker_common.js"></script>
+ <script src="datepicker_core.js"></script>
+ <script src="datepicker_events.js"></script>
+ <script src="datepicker_methods.js"></script>
+ <script src="datepicker_options.js"></script>
+ <script src="datepicker_test_helpers.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Datepicker Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div><input type="text" id="inp"><input type="text" id="alt"><div id="inl"></div></div>
+<p><input type="text" id="inp2"></p>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/datepicker_common.js b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_common.js
new file mode 100644
index 0000000..1eecc85
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_common.js
@@ -0,0 +1,7 @@
+/*
+TestHelpers.commonWidgetTests( "datepicker", {
+ defaults: {
+ disabled: false
+ }
+});
+*/
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/datepicker_core.js b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_core.js
new file mode 100644
index 0000000..0bc5723
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_core.js
@@ -0,0 +1,524 @@
+/*
+ * datepicker_core.js
+ */
+
+(function($) {
+
+module("datepicker: core");
+
+TestHelpers.testJshint( "datepicker" );
+
+test("initialization - Reinitialization after body had been emptied.", function() {
+ expect( 1 );
+ var bodyContent = $("body").children(), inp = $("#inp");
+ $("#inp").datepicker();
+ $("body").empty().append(inp);
+ $("#inp").datepicker();
+ ok( $("#"+$.datepicker._mainDivId).length===1, "Datepicker container added" );
+ $("body").empty().append(bodyContent); // Returning to initial state for later tests
+});
+
+test( "widget method - empty collection", function() {
+ expect( 1 );
+ $( "#nonExist" ).datepicker(); // should create nothing
+ ok( !$( "#ui-datepicker-div" ).length, "Non init on empty collection" );
+});
+
+test("widget method", function() {
+ expect( 1 );
+ var actual = $("#inp").datepicker().datepicker("widget")[0];
+ deepEqual($("body > #ui-datepicker-div:last-child")[0], actual);
+});
+
+asyncTest( "baseStructure", function() {
+ expect( 58 );
+ var header, title, table, thead, week, panel, inl, child,
+ inp = TestHelpers.datepicker.initNewInput(),
+ dp = $( "#ui-datepicker-div" );
+
+ function step1() {
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ":visible" ), "Structure - datepicker visible" );
+ ok( !dp.is( ".ui-datepicker-rtl" ), "Structure - not right-to-left" );
+ ok( !dp.is( ".ui-datepicker-multi" ), "Structure - not multi-month" );
+ equal( dp.children().length, 2, "Structure - child count" );
+
+ header = dp.children( ":first" );
+ ok( header.is( "div.ui-datepicker-header" ), "Structure - header division" );
+ equal( header.children().length, 3, "Structure - header child count" );
+ ok( header.children( ":first" ).is( "a.ui-datepicker-prev" ) && header.children( ":first" ).html() !== "", "Structure - prev link" );
+ ok( header.children( ":eq(1)" ).is( "a.ui-datepicker-next" ) && header.children( ":eq(1)" ).html() !== "", "Structure - next link" );
+
+ title = header.children( ":last" );
+ ok( title.is( "div.ui-datepicker-title" ) && title.html() !== "","Structure - title division" );
+ equal( title.children().length, 2, "Structure - title child count" );
+ ok( title.children( ":first" ).is( "span.ui-datepicker-month" ) && title.children( ":first" ).text() !== "", "Structure - month text" );
+ ok( title.children( ":last" ).is( "span.ui-datepicker-year" ) && title.children( ":last" ).text() !== "", "Structure - year text" );
+
+ table = dp.children( ":eq(1)" );
+ ok( table.is( "table.ui-datepicker-calendar" ), "Structure - month table" );
+ ok( table.children( ":first" ).is( "thead" ), "Structure - month table thead" );
+
+ thead = table.children( ":first" ).children( ":first" );
+ ok( thead.is( "tr" ), "Structure - month table title row" );
+ equal( thead.find( "th" ).length, 7, "Structure - month table title cells" );
+ ok( table.children( ":eq(1)" ).is( "tbody" ), "Structure - month table body" );
+ ok( table.children( ":eq(1)" ).children( "tr" ).length >= 4, "Structure - month table week count" );
+
+ week = table.children( ":eq(1)" ).children( ":first" );
+ ok( week.is( "tr" ), "Structure - month table week row" );
+ equal( week.children().length, 7, "Structure - week child count" );
+ ok( week.children( ":first" ).is( "td.ui-datepicker-week-end" ), "Structure - month table first day cell" );
+ ok( week.children( ":last" ).is( "td.ui-datepicker-week-end" ), "Structure - month table second day cell" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step2();
+ });
+ }
+
+ function step2() {
+ // Editable month/year and button panel
+ inp = TestHelpers.datepicker.initNewInput({
+ changeMonth: true,
+ changeYear: true,
+ showButtonPanel: true
+ });
+ TestHelpers.datepicker.onFocus( inp, function() {
+ title = dp.find( "div.ui-datepicker-title" );
+ ok( title.children( ":first" ).is( "select.ui-datepicker-month" ), "Structure - month selector" );
+ ok( title.children( ":last" ).is( "select.ui-datepicker-year" ), "Structure - year selector" );
+
+ panel = dp.children( ":last" );
+ ok( panel.is( "div.ui-datepicker-buttonpane" ), "Structure - button panel division" );
+ equal( panel.children().length, 2, "Structure - button panel child count" );
+ ok( panel.children( ":first" ).is( "button.ui-datepicker-current" ), "Structure - today button" );
+ ok( panel.children( ":last" ).is( "button.ui-datepicker-close" ), "Structure - close button" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step3();
+ });
+ }
+
+ function step3() {
+ // Multi-month 2
+ inp = TestHelpers.datepicker.initNewInput({ numberOfMonths: 2 });
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ".ui-datepicker-multi" ), "Structure multi [2] - multi-month" );
+ equal( dp.children().length, 3, "Structure multi [2] - child count" );
+
+ child = dp.children( ":first" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2] - first month division" );
+
+ child = dp.children( ":eq(1)" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2] - second month division" );
+
+ child = dp.children( ":eq(2)" );
+ ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2] - row break" );
+ ok( dp.is( ".ui-datepicker-multi-2" ), "Structure multi [2] - multi-2" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step4();
+ });
+ }
+
+ function step4() {
+ // Multi-month 3
+ inp = TestHelpers.datepicker.initNewInput({ numberOfMonths: 3 });
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ".ui-datepicker-multi-3" ), "Structure multi [3] - multi-3" );
+ ok( !dp.is( ".ui-datepicker-multi-2" ), "Structure multi [3] - Trac #6704" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step5();
+ });
+ }
+
+ function step5() {
+ // Multi-month [2, 2]
+ inp = TestHelpers.datepicker.initNewInput({ numberOfMonths: [ 2, 2 ] });
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ".ui-datepicker-multi" ), "Structure multi - multi-month" );
+ equal( dp.children().length, 6, "Structure multi [2,2] - child count" );
+
+ child = dp.children( ":first" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2,2] - first month division" );
+
+ child = dp.children( ":eq(1)" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2,2] - second month division" );
+
+ child = dp.children( ":eq(2)" );
+ ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2,2] - row break" );
+
+ child = dp.children( ":eq(3)" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2,2] - third month division" );
+
+ child = dp.children( ":eq(4)" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2,2] - fourth month division" );
+
+ child = dp.children( ":eq(5)" );
+ ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2,2] - row break" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+
+ // Inline
+ inl = TestHelpers.datepicker.init( "#inl" );
+ dp = inl.children();
+
+ ok( dp.is( ".ui-datepicker-inline" ), "Structure inline - main div" );
+ ok( !dp.is( ".ui-datepicker-rtl" ), "Structure inline - not right-to-left" );
+ ok( !dp.is( ".ui-datepicker-multi" ), "Structure inline - not multi-month" );
+ equal( dp.children().length, 2, "Structure inline - child count" );
+
+ header = dp.children( ":first" );
+ ok( header.is( "div.ui-datepicker-header" ), "Structure inline - header division" );
+ equal( header.children().length, 3, "Structure inline - header child count" );
+
+ table = dp.children( ":eq(1)" );
+ ok( table.is( "table.ui-datepicker-calendar" ), "Structure inline - month table" );
+ ok( table.children( ":first" ).is( "thead" ), "Structure inline - month table thead" );
+ ok( table.children( ":eq(1)" ).is( "tbody" ), "Structure inline - month table body" );
+
+ inl.datepicker( "destroy" );
+
+ // Inline multi-month
+ inl = TestHelpers.datepicker.init( "#inl", { numberOfMonths: 2 } );
+ dp = inl.children();
+
+ ok( dp.is( ".ui-datepicker-inline" ) && dp.is( ".ui-datepicker-multi" ), "Structure inline multi - main div" );
+ equal( dp.children().length, 3, "Structure inline multi - child count" );
+
+ child = dp.children( ":first" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure inline multi - first month division" );
+
+ child = dp.children( ":eq(1)" );
+ ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure inline multi - second month division" );
+
+ child = dp.children( ":eq(2)" );
+ ok( child.is( "div.ui-datepicker-row-break" ), "Structure inline multi - row break" );
+
+ inl.datepicker( "destroy" );
+ start();
+ });
+ }
+
+ step1();
+});
+
+asyncTest( "customStructure", function() {
+ expect( 20 );
+ var header, panel, title, thead,
+ inp = TestHelpers.datepicker.initNewInput( $.datepicker.regional.he ),
+ dp = $( "#ui-datepicker-div" );
+
+ function step1() {
+ inp.datepicker( "option", "showButtonPanel", true );
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ".ui-datepicker-rtl" ), "Structure RTL - right-to-left" );
+
+ header = dp.children( ":first" );
+ ok( header.is( "div.ui-datepicker-header" ), "Structure RTL - header division" );
+ equal( header.children().length, 3, "Structure RTL - header child count" );
+ ok( header.children( ":first" ).is( "a.ui-datepicker-next" ), "Structure RTL - prev link" );
+ ok( header.children( ":eq(1)" ).is( "a.ui-datepicker-prev" ), "Structure RTL - next link" );
+
+ panel = dp.children( ":last" );
+ ok( panel.is( "div.ui-datepicker-buttonpane" ), "Structure RTL - button division" );
+ equal( panel.children().length, 2, "Structure RTL - button panel child count" );
+ ok( panel.children( ":first" ).is( "button.ui-datepicker-close" ), "Structure RTL - close button" );
+ ok( panel.children( ":last" ).is( "button.ui-datepicker-current" ), "Structure RTL - today button" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step2();
+ });
+ }
+
+ // Hide prev/next
+ function step2() {
+ inp = TestHelpers.datepicker.initNewInput({
+ hideIfNoPrevNext: true,
+ minDate: new Date( 2008, 2 - 1, 4 ),
+ maxDate: new Date( 2008, 2 - 1, 14 )
+ });
+ inp.val( "02/10/2008" );
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ header = dp.children( ":first" );
+ ok( header.is( "div.ui-datepicker-header" ), "Structure hide prev/next - header division" );
+ equal( header.children().length, 1, "Structure hide prev/next - links child count" );
+ ok( header.children( ":first" ).is( "div.ui-datepicker-title" ), "Structure hide prev/next - title division" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step3();
+ });
+ }
+
+ // Changeable Month with read-only year
+ function step3() {
+ inp = TestHelpers.datepicker.initNewInput({ changeMonth: true });
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ title = dp.children( ":first" ).children( ":last" );
+ equal( title.children().length, 2, "Structure changeable month - title child count" );
+ ok( title.children( ":first" ).is( "select.ui-datepicker-month" ), "Structure changeable month - month selector" );
+ ok( title.children( ":last" ).is( "span.ui-datepicker-year" ), "Structure changeable month - read-only year" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step4();
+ });
+ }
+
+ // Changeable year with read-only month
+ function step4() {
+ inp = TestHelpers.datepicker.initNewInput({ changeYear: true });
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ title = dp.children( ":first" ).children( ":last" );
+ equal( title.children().length, 2, "Structure changeable year - title child count" );
+ ok( title.children( ":first" ).is( "span.ui-datepicker-month" ), "Structure changeable year - read-only month" );
+ ok( title.children( ":last" ).is( "select.ui-datepicker-year" ), "Structure changeable year - year selector" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ step5();
+ });
+ }
+
+ // Read-only first day of week
+ function step5() {
+ inp = TestHelpers.datepicker.initNewInput({ changeFirstDay: false });
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ thead = dp.find( ".ui-datepicker-calendar thead tr" );
+ equal( thead.children().length, 7, "Structure read-only first day - thead child count" );
+ equal( thead.find( "a" ).length, 0, "Structure read-only first day - thead links count" );
+
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+ start();
+ });
+ }
+
+ // TODO: figure out why this setTimeout is needed in IE,
+ // it only is necessary when the previous baseStructure tests runs first
+ // Support: IE
+ setTimeout( step1 );
+});
+
+test("keystrokes", function() {
+ expect( 26 );
+ var inp = TestHelpers.datepicker.init("#inp"),
+ date = new Date();
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke enter");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
+ "Keystroke enter - preset");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+home");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
+ ok(inp.datepicker("getDate") == null, "Keystroke ctrl+end");
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
+ ok(inp.datepicker("getDate") == null, "Keystroke esc");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
+ "Keystroke esc - preset");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
+ "Keystroke esc - abandoned");
+ // Moving by day or week
+ inp.val("").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.LEFT}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() - 1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+left");
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.LEFT}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke left");
+ inp.val("").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.RIGHT}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+right");
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.RIGHT}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() - 1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke right");
+ inp.val("").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() - 7);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+up");
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 7);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke up");
+ inp.val("").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 7);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+down");
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() - 7);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Keystroke down");
+ // Moving by month or year
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 1 - 1, 4),
+ "Keystroke pgup");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 3 - 1, 4),
+ "Keystroke pgdn");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2007, 2 - 1, 4),
+ "Keystroke ctrl+pgup");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2009, 2 - 1, 4),
+ "Keystroke ctrl+pgdn");
+ // Check for moving to short months
+ inp.val("03/31/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 29),
+ "Keystroke pgup - Feb");
+ inp.val("01/30/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 29),
+ "Keystroke pgdn - Feb");
+ inp.val("02/29/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2007, 2 - 1, 28),
+ "Keystroke ctrl+pgup - Feb");
+ inp.val("02/29/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2009, 2 - 1, 28),
+ "Keystroke ctrl+pgdn - Feb");
+ // Goto current
+ inp.datepicker("option", {gotoCurrent: true}).
+ datepicker("hide").val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
+ "Keystroke ctrl+home");
+ // Change steps
+ inp.datepicker("option", {stepMonths: 2, gotoCurrent: false}).
+ datepicker("hide").val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2007, 12 - 1, 4),
+ "Keystroke pgup step 2");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 4 - 1, 4),
+ "Keystroke pgdn step 2");
+});
+
+test("mouse", function() {
+ expect( 15 );
+ var inl,
+ inp = TestHelpers.datepicker.init("#inp"),
+ dp = $("#ui-datepicker-div"),
+ date = new Date();
+ inp.val("").datepicker("show");
+ $(".ui-datepicker-calendar tbody a:contains(10)", dp).simulate("click", {});
+ date.setDate(10);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Mouse click");
+ inp.val("02/04/2008").datepicker("show");
+ $(".ui-datepicker-calendar tbody a:contains(12)", dp).simulate("click", {});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 12),
+ "Mouse click - preset");
+ inp.val("02/04/2008").datepicker("show");
+ inp.val("").datepicker("show");
+ $("button.ui-datepicker-close", dp).simulate("click", {});
+ ok(inp.datepicker("getDate") == null, "Mouse click - close");
+ inp.val("02/04/2008").datepicker("show");
+ $("button.ui-datepicker-close", dp).simulate("click", {});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
+ "Mouse click - close + preset");
+ inp.val("02/04/2008").datepicker("show");
+ $("a.ui-datepicker-prev", dp).simulate("click", {});
+ $("button.ui-datepicker-close", dp).simulate("click", {});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
+ "Mouse click - abandoned");
+ // Current/previous/next
+ inp.val("02/04/2008").datepicker("option", {showButtonPanel: true}).datepicker("show");
+ $(".ui-datepicker-current", dp).simulate("click", {});
+ $(".ui-datepicker-calendar tbody a:contains(14)", dp).simulate("click", {});
+ date.setDate(14);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Mouse click - current");
+ inp.val("02/04/2008").datepicker("show");
+ $(".ui-datepicker-prev", dp).simulate("click");
+ $(".ui-datepicker-calendar tbody a:contains(16)", dp).simulate("click");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 1 - 1, 16),
+ "Mouse click - previous");
+ inp.val("02/04/2008").datepicker("show");
+ $(".ui-datepicker-next", dp).simulate("click");
+ $(".ui-datepicker-calendar tbody a:contains(18)", dp).simulate("click");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 3 - 1, 18),
+ "Mouse click - next");
+ // Previous/next with minimum/maximum
+ inp.datepicker("option", {minDate: new Date(2008, 2 - 1, 2),
+ maxDate: new Date(2008, 2 - 1, 26)}).val("02/04/2008").datepicker("show");
+ $(".ui-datepicker-prev", dp).simulate("click");
+ $(".ui-datepicker-calendar tbody a:contains(16)", dp).simulate("click");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 16),
+ "Mouse click - previous + min/max");
+ inp.val("02/04/2008").datepicker("show");
+ $(".ui-datepicker-next", dp).simulate("click");
+ $(".ui-datepicker-calendar tbody a:contains(18)", dp).simulate("click");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 18),
+ "Mouse click - next + min/max");
+ // Inline
+ inl = TestHelpers.datepicker.init("#inl");
+ dp = $(".ui-datepicker-inline", inl);
+ date = new Date();
+ inl.datepicker("setDate", date);
+ $(".ui-datepicker-calendar tbody a:contains(10)", dp).simulate("click", {});
+ date.setDate(10);
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), date, "Mouse click inline");
+ inl.datepicker("option", {showButtonPanel: true}).datepicker("setDate", new Date(2008, 2 - 1, 4));
+ $(".ui-datepicker-calendar tbody a:contains(12)", dp).simulate("click", {});
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), new Date(2008, 2 - 1, 12), "Mouse click inline - preset");
+ inl.datepicker("option", {showButtonPanel: true});
+ $(".ui-datepicker-current", dp).simulate("click", {});
+ $(".ui-datepicker-calendar tbody a:contains(14)", dp).simulate("click", {});
+ date.setDate(14);
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), date, "Mouse click inline - current");
+ inl.datepicker("setDate", new Date(2008, 2 - 1, 4));
+ $(".ui-datepicker-prev", dp).simulate("click");
+ $(".ui-datepicker-calendar tbody a:contains(16)", dp).simulate("click");
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), new Date(2008, 1 - 1, 16),
+ "Mouse click inline - previous");
+ inl.datepicker("setDate", new Date(2008, 2 - 1, 4));
+ $(".ui-datepicker-next", dp).simulate("click");
+ $(".ui-datepicker-calendar tbody a:contains(18)", dp).simulate("click");
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), new Date(2008, 3 - 1, 18),
+ "Mouse click inline - next");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/datepicker_events.js b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_events.js
new file mode 100644
index 0000000..dfc42cc
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_events.js
@@ -0,0 +1,153 @@
+/*
+ * datepicker_events.js
+ */
+(function($) {
+
+module("datepicker: events");
+
+var selectedThis = null,
+selectedDate = null,
+selectedInst = null;
+
+function callback(date, inst) {
+ selectedThis = this;
+ selectedDate = date;
+ selectedInst = inst;
+}
+
+function callback2(year, month, inst) {
+ selectedThis = this;
+ selectedDate = year + "/" + month;
+ selectedInst = inst;
+}
+
+test("events", function() {
+ expect( 26 );
+ var dateStr, newMonthYear, inp2,
+ inp = TestHelpers.datepicker.init("#inp", {onSelect: callback}),
+ date = new Date();
+ // onSelect
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ equal(selectedThis, inp[0], "Callback selected this");
+ equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback selected inst");
+ equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
+ "Callback selected date");
+ inp.val("").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 7);
+ equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
+ "Callback selected date - ctrl+down");
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
+ equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
+ "Callback selected date - esc");
+ dateStr = "02/04/2008";
+ inp.val(dateStr).datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ equal(dateStr, selectedDate,
+ "onSelect is called after enter keydown");
+ // onChangeMonthYear
+ inp.datepicker("option", {onChangeMonthYear: callback2, onSelect: null}).
+ val("").datepicker("show");
+ newMonthYear = function(date) {
+ return date.getFullYear() + "/" + (date.getMonth() + 1);
+ };
+ date = new Date();
+ date.setDate(1);
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP});
+ date.setMonth(date.getMonth() - 1);
+ equal(selectedThis, inp[0], "Callback change month/year this");
+ equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback change month/year inst");
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year date - pgup");
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
+ date.setMonth(date.getMonth() + 1);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year date - pgdn");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
+ date.setFullYear(date.getFullYear() - 1);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year date - ctrl+pgup");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME});
+ date.setFullYear(date.getFullYear() + 1);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year date - ctrl+home");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
+ date.setFullYear(date.getFullYear() + 1);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year date - ctrl+pgdn");
+ inp.datepicker("setDate", new Date(2007, 1 - 1, 26));
+ equal(selectedDate, "2007/1", "Callback change month/year date - setDate");
+ selectedDate = null;
+ inp.datepicker("setDate", new Date(2007, 1 - 1, 12));
+ ok(selectedDate == null, "Callback change month/year date - setDate no change");
+ // onChangeMonthYear step by 2
+ inp.datepicker("option", {stepMonths: 2}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP});
+ date.setMonth(date.getMonth() - 14);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year by 2 date - pgup");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
+ date.setMonth(date.getMonth() - 12);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year by 2 date - ctrl+pgup");
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
+ date.setMonth(date.getMonth() + 2);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year by 2 date - pgdn");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
+ date.setMonth(date.getMonth() + 12);
+ equal(selectedDate, newMonthYear(date),
+ "Callback change month/year by 2 date - ctrl+pgdn");
+ // onClose
+ inp.datepicker("option", {onClose: callback, onChangeMonthYear: null, stepMonths: 1}).
+ val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
+ equal(selectedThis, inp[0], "Callback close this");
+ equal(selectedInst, $.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Callback close inst");
+ equal(selectedDate, "", "Callback close date - esc");
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", new Date()),
+ "Callback close date - enter");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
+ equal(selectedDate, "02/04/2008", "Callback close date - preset");
+ inp.val("02/04/2008").datepicker("show").
+ simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
+ equal(selectedDate, "", "Callback close date - ctrl+end");
+
+ inp2 = TestHelpers.datepicker.init("#inp2");
+ inp2.datepicker().datepicker("option", {onClose: callback}).datepicker("show");
+ inp.datepicker("show");
+ equal(selectedThis, inp2[0], "Callback close this");
+});
+
+test("beforeShowDay-getDate", function() {
+ expect( 3 );
+ var inp = TestHelpers.datepicker.init("#inp", {beforeShowDay: function() { inp.datepicker("getDate"); return [true, ""]; }}),
+ dp = $("#ui-datepicker-div");
+ inp.val("01/01/2010").datepicker("show");
+ // contains non-breaking space
+ equal($("div.ui-datepicker-title").text(),
+ // support: IE <9, jQuery <1.8
+ // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways
+ $( "<span>January&#xa0;2010</span>" ).text(), "Initial month");
+ $("a.ui-datepicker-next", dp).click();
+ $("a.ui-datepicker-next", dp).click();
+ // contains non-breaking space
+ equal($("div.ui-datepicker-title").text(),
+ $( "<span>March&#xa0;2010</span>" ).text(), "After next clicks");
+ inp.datepicker("hide").datepicker("show");
+ $("a.ui-datepicker-prev", dp).click();
+ $("a.ui-datepicker-prev", dp).click();
+ // contains non-breaking space
+ equal($("div.ui-datepicker-title").text(),
+ $( "<span>November&#xa0;2009</span>" ).text(), "After prev clicks");
+ inp.datepicker("hide");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/datepicker_methods.js b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_methods.js
new file mode 100644
index 0000000..e52e126
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_methods.js
@@ -0,0 +1,125 @@
+/*
+ * datepicker_methods.js
+ */
+(function($) {
+
+module("datepicker: methods");
+
+test("destroy", function() {
+ expect( 33 );
+ var inl,
+ inp = TestHelpers.datepicker.init("#inp");
+ ok(inp.is(".hasDatepicker"), "Default - marker class set");
+ ok($.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Default - instance present");
+ ok(inp.next().is("#alt"), "Default - button absent");
+ inp.datepicker("destroy");
+ inp = $("#inp");
+ ok(!inp.is(".hasDatepicker"), "Default - marker class cleared");
+ ok(!$.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Default - instance absent");
+ ok(inp.next().is("#alt"), "Default - button absent");
+ // With button
+ inp= TestHelpers.datepicker.init("#inp", {showOn: "both"});
+ ok(inp.is(".hasDatepicker"), "Button - marker class set");
+ ok($.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Button - instance present");
+ ok(inp.next().text() === "...", "Button - button added");
+ inp.datepicker("destroy");
+ inp = $("#inp");
+ ok(!inp.is(".hasDatepicker"), "Button - marker class cleared");
+ ok(!$.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Button - instance absent");
+ ok(inp.next().is("#alt"), "Button - button removed");
+ // With append text
+ inp = TestHelpers.datepicker.init("#inp", {appendText: "Testing"});
+ ok(inp.is(".hasDatepicker"), "Append - marker class set");
+ ok($.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Append - instance present");
+ ok(inp.next().text() === "Testing", "Append - append text added");
+ inp.datepicker("destroy");
+ inp = $("#inp");
+ ok(!inp.is(".hasDatepicker"), "Append - marker class cleared");
+ ok(!$.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Append - instance absent");
+ ok(inp.next().is("#alt"), "Append - append text removed");
+ // With both
+ inp= TestHelpers.datepicker.init("#inp", {showOn: "both", buttonImageOnly: true,
+ buttonImage: "images/calendar.gif", appendText: "Testing"});
+ ok(inp.is(".hasDatepicker"), "Both - marker class set");
+ ok($.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Both - instance present");
+ ok(inp.next()[0].nodeName.toLowerCase() === "img", "Both - button added");
+ ok(inp.next().next().text() === "Testing", "Both - append text added");
+ inp.datepicker("destroy");
+ inp = $("#inp");
+ ok(!inp.is(".hasDatepicker"), "Both - marker class cleared");
+ ok(!$.data(inp[0], TestHelpers.datepicker.PROP_NAME), "Both - instance absent");
+ ok(inp.next().is("#alt"), "Both - button and append text absent");
+ // Inline
+ inl = TestHelpers.datepicker.init("#inl");
+ ok(inl.is(".hasDatepicker"), "Inline - marker class set");
+ ok(inl.html() !== "", "Inline - datepicker present");
+ ok($.data(inl[0], TestHelpers.datepicker.PROP_NAME), "Inline - instance present");
+ ok(inl.next().length === 0 || inl.next().is("p"), "Inline - button absent");
+ inl.datepicker("destroy");
+ inl = $("#inl");
+ ok(!inl.is(".hasDatepicker"), "Inline - marker class cleared");
+ ok(inl.html() === "", "Inline - datepicker absent");
+ ok(!$.data(inl[0], TestHelpers.datepicker.PROP_NAME), "Inline - instance absent");
+ ok(inl.next().length === 0 || inl.next().is("p"), "Inline - button absent");
+});
+
+test("enableDisable", function() {
+ expect( 33 );
+ var inl, dp,
+ inp = TestHelpers.datepicker.init("#inp");
+ ok(!inp.datepicker("isDisabled"), "Enable/disable - initially marked as enabled");
+ ok(!inp[0].disabled, "Enable/disable - field initially enabled");
+ inp.datepicker("disable");
+ ok(inp.datepicker("isDisabled"), "Enable/disable - now marked as disabled");
+ ok(inp[0].disabled, "Enable/disable - field now disabled");
+ inp.datepicker("enable");
+ ok(!inp.datepicker("isDisabled"), "Enable/disable - now marked as enabled");
+ ok(!inp[0].disabled, "Enable/disable - field now enabled");
+ inp.datepicker("destroy");
+ // With a button
+ inp = TestHelpers.datepicker.init("#inp", {showOn: "button"});
+ ok(!inp.datepicker("isDisabled"), "Enable/disable button - initially marked as enabled");
+ ok(!inp[0].disabled, "Enable/disable button - field initially enabled");
+ ok(!inp.next("button")[0].disabled, "Enable/disable button - button initially enabled");
+ inp.datepicker("disable");
+ ok(inp.datepicker("isDisabled"), "Enable/disable button - now marked as disabled");
+ ok(inp[0].disabled, "Enable/disable button - field now disabled");
+ ok(inp.next("button")[0].disabled, "Enable/disable button - button now disabled");
+ inp.datepicker("enable");
+ ok(!inp.datepicker("isDisabled"), "Enable/disable button - now marked as enabled");
+ ok(!inp[0].disabled, "Enable/disable button - field now enabled");
+ ok(!inp.next("button")[0].disabled, "Enable/disable button - button now enabled");
+ inp.datepicker("destroy");
+ // With an image button
+ inp = TestHelpers.datepicker.init("#inp", {showOn: "button", buttonImageOnly: true,
+ buttonImage: "images/calendar.gif"});
+ ok(!inp.datepicker("isDisabled"), "Enable/disable image - initially marked as enabled");
+ ok(!inp[0].disabled, "Enable/disable image - field initially enabled");
+ ok(parseFloat(inp.next("img").css("opacity")) === 1, "Enable/disable image - image initially enabled");
+ inp.datepicker("disable");
+ ok(inp.datepicker("isDisabled"), "Enable/disable image - now marked as disabled");
+ ok(inp[0].disabled, "Enable/disable image - field now disabled");
+ ok(parseFloat(inp.next("img").css("opacity")) !== 1, "Enable/disable image - image now disabled");
+ inp.datepicker("enable");
+ ok(!inp.datepicker("isDisabled"), "Enable/disable image - now marked as enabled");
+ ok(!inp[0].disabled, "Enable/disable image - field now enabled");
+ ok(parseFloat(inp.next("img").css("opacity")) === 1, "Enable/disable image - image now enabled");
+ inp.datepicker("destroy");
+ // Inline
+ inl = TestHelpers.datepicker.init("#inl", {changeYear: true});
+ dp = $(".ui-datepicker-inline", inl);
+ ok(!inl.datepicker("isDisabled"), "Enable/disable inline - initially marked as enabled");
+ ok(!dp.children().is(".ui-state-disabled"), "Enable/disable inline - not visually disabled initially");
+ ok(!dp.find("select").prop("disabled"), "Enable/disable inline - form element enabled initially");
+ inl.datepicker("disable");
+ ok(inl.datepicker("isDisabled"), "Enable/disable inline - now marked as disabled");
+ ok(dp.children().is(".ui-state-disabled"), "Enable/disable inline - visually disabled");
+ ok(dp.find("select").prop("disabled"), "Enable/disable inline - form element disabled");
+ inl.datepicker("enable");
+ ok(!inl.datepicker("isDisabled"), "Enable/disable inline - now marked as enabled");
+ ok(!dp.children().is(".ui-state-disabled"), "Enable/disable inline - not visiually disabled");
+ ok(!dp.find("select").prop("disabled"), "Enable/disable inline - form element enabled");
+ inl.datepicker("destroy");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/datepicker_options.js b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_options.js
new file mode 100644
index 0000000..b5dd4ca
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_options.js
@@ -0,0 +1,1113 @@
+/*
+ * datepicker_options.js
+ */
+
+(function($) {
+
+module("datepicker: options");
+
+test("setDefaults", function() {
+ expect( 3 );
+ TestHelpers.datepicker.init("#inp");
+ equal($.datepicker._defaults.showOn, "focus", "Initial showOn");
+ $.datepicker.setDefaults({showOn: "button"});
+ equal($.datepicker._defaults.showOn, "button", "Change default showOn");
+ $.datepicker.setDefaults({showOn: "focus"});
+ equal($.datepicker._defaults.showOn, "focus", "Restore showOn");
+});
+
+test("option", function() {
+ expect( 17 );
+ var inp = TestHelpers.datepicker.init("#inp"),
+ inst = $.data(inp[0], TestHelpers.datepicker.PROP_NAME);
+ // Set option
+ equal(inst.settings.showOn, null, "Initial setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "focus", "Initial instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Initial default showOn");
+ inp.datepicker("option", "showOn", "button");
+ equal(inst.settings.showOn, "button", "Change setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "button", "Change instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
+ inp.datepicker("option", {showOn: "both"});
+ equal(inst.settings.showOn, "both", "Change setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "both", "Change instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
+ inp.datepicker("option", "showOn", undefined);
+ equal(inst.settings.showOn, null, "Clear setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "focus", "Restore instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
+ // Get option
+ inp = TestHelpers.datepicker.init("#inp");
+ equal(inp.datepicker("option", "showOn"), "focus", "Initial setting showOn");
+ inp.datepicker("option", "showOn", "button");
+ equal(inp.datepicker("option", "showOn"), "button", "Change instance showOn");
+ inp.datepicker("option", "showOn", undefined);
+ equal(inp.datepicker("option", "showOn"), "focus", "Reset instance showOn");
+ deepEqual(inp.datepicker("option", "all"), {showAnim: ""}, "Get instance settings");
+ deepEqual(inp.datepicker("option", "defaults"), $.datepicker._defaults,
+ "Get default settings");
+});
+
+test( "disabled", function() {
+ expect(8);
+ var inp = TestHelpers.datepicker.init("#inp");
+ ok(!inp.datepicker("isDisabled"), "Initially marked as enabled");
+ ok(!inp[0].disabled, "Field initially enabled");
+ inp.datepicker("option", "disabled", true);
+ ok(inp.datepicker("isDisabled"), "Marked as disabled");
+ ok(inp[0].disabled, "Field now disabled");
+ inp.datepicker("option", "disabled", false);
+ ok(!inp.datepicker("isDisabled"), "Marked as enabled");
+ ok(!inp[0].disabled, "Field now enabled");
+ inp.datepicker("destroy");
+
+ inp = TestHelpers.datepicker.init("#inp", { disabled: true });
+ ok(inp.datepicker("isDisabled"), "Initially marked as disabled");
+ ok(inp[0].disabled, "Field initially disabled");
+});
+
+test("change", function() {
+ expect( 12 );
+ var inp = TestHelpers.datepicker.init("#inp"),
+ inst = $.data(inp[0], TestHelpers.datepicker.PROP_NAME);
+ equal(inst.settings.showOn, null, "Initial setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "focus", "Initial instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Initial default showOn");
+ inp.datepicker("change", "showOn", "button");
+ equal(inst.settings.showOn, "button", "Change setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "button", "Change instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
+ inp.datepicker("change", {showOn: "both"});
+ equal(inst.settings.showOn, "both", "Change setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "both", "Change instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
+ inp.datepicker("change", "showOn", undefined);
+ equal(inst.settings.showOn, null, "Clear setting showOn");
+ equal($.datepicker._get(inst, "showOn"), "focus", "Restore instance showOn");
+ equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
+});
+
+asyncTest( "invocation", function() {
+ var button, image,
+ isOldIE = $.ui.ie && ( !document.documentMode || document.documentMode < 9 ),
+ body = $( "body" );
+
+ expect( isOldIE ? 25 : 29 );
+
+ function step0() {
+ var inp = TestHelpers.datepicker.initNewInput(),
+ dp = $( "#ui-datepicker-div" );
+
+ button = inp.siblings( "button" );
+ ok( button.length === 0, "Focus - button absent" );
+ image = inp.siblings( "img" );
+ ok( image.length === 0, "Focus - image absent" );
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ":visible" ), "Focus - rendered on focus" );
+ inp.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ ok( !dp.is( ":visible" ), "Focus - hidden on exit" );
+ step1();
+ });
+ }
+
+ function step1() {
+
+ var inp = TestHelpers.datepicker.initNewInput(),
+ dp = $( "#ui-datepicker-div" );
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ":visible" ), "Focus - rendered on focus" );
+ body.simulate( "mousedown", {} );
+ ok( !dp.is( ":visible" ), "Focus - hidden on external click" );
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+
+ step2();
+ });
+ }
+
+ function step2() {
+ var inp = TestHelpers.datepicker.initNewInput({
+ showOn: "button",
+ buttonText: "Popup"
+ }),
+ dp = $( "#ui-datepicker-div" );
+
+ ok( !dp.is( ":visible" ), "Button - initially hidden" );
+ button = inp.siblings( "button" );
+ image = inp.siblings( "img" );
+ ok( button.length === 1, "Button - button present" );
+ ok( image.length === 0, "Button - image absent" );
+ equal( button.text(), "Popup", "Button - button text" );
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( !dp.is( ":visible" ), "Button - not rendered on focus" );
+ button.click();
+ ok( dp.is( ":visible" ), "Button - rendered on button click" );
+ button.click();
+ ok( !dp.is( ":visible" ), "Button - hidden on second button click" );
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+
+ step3();
+ });
+ }
+
+ function step3() {
+ var inp = TestHelpers.datepicker.initNewInput({
+ showOn: "button",
+ buttonImageOnly: true,
+ buttonImage: "images/calendar.gif",
+ buttonText: "Cal"
+ }),
+ dp = $( "#ui-datepicker-div" );
+
+ ok( !dp.is( ":visible" ), "Image button - initially hidden" );
+ button = inp.siblings( "button" );
+ ok( button.length === 0, "Image button - button absent" );
+ image = inp.siblings( "img" );
+ ok( image.length === 1, "Image button - image present" );
+ ok( /images\/calendar\.gif$/.test( image.attr( "src" ) ), "Image button - image source" );
+ equal( image.attr( "title" ), "Cal", "Image button - image text" );
+
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( !dp.is( ":visible" ), "Image button - not rendered on focus" );
+ image.click();
+ ok( dp.is( ":visible" ), "Image button - rendered on image click" );
+ image.click();
+ ok( !dp.is( ":visible" ), "Image button - hidden on second image click" );
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+
+ step4();
+ });
+ }
+
+ function step4() {
+ var inp = TestHelpers.datepicker.initNewInput({
+ showOn: "both",
+ buttonImage: "images/calendar.gif"
+ }),
+ dp = $( "#ui-datepicker-div" );
+
+ ok( !dp.is( ":visible" ), "Both - initially hidden" );
+ button = inp.siblings( "button" );
+ ok( button.length === 1, "Both - button present" );
+ image = inp.siblings( "img" );
+ ok( image.length === 0, "Both - image absent" );
+ image = button.children( "img" );
+ ok( image.length === 1, "Both - button image present" );
+
+ // TODO: occasionally this test flakily fails to focus in IE8 in browserstack
+ if ( !isOldIE ) {
+ TestHelpers.datepicker.onFocus( inp, function() {
+ ok( dp.is( ":visible" ), "Both - rendered on focus" );
+ body.simulate( "mousedown", {} );
+ ok( !dp.is( ":visible" ), "Both - hidden on external click" );
+ button.click();
+ ok( dp.is( ":visible" ), "Both - rendered on button click" );
+ button.click();
+ ok( !dp.is( ":visible" ), "Both - hidden on second button click" );
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+
+ start();
+ });
+ } else {
+ start();
+ }
+ }
+
+ step0();
+});
+
+test("otherMonths", function() {
+ expect( 8 );
+ var inp = TestHelpers.datepicker.init("#inp"),
+ pop = $("#ui-datepicker-div");
+ inp.val("06/01/2009").datepicker("show");
+ equal(pop.find("tbody").text(),
+ // support: IE <9, jQuery <1.8
+ // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways
+ $( "<span>\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0</span>" ).text(),
+ "Other months - none");
+ ok(pop.find("td:last *").length === 0, "Other months - no content");
+ inp.datepicker("hide").datepicker("option", "showOtherMonths", true).datepicker("show");
+ equal(pop.find("tbody").text(), "311234567891011121314151617181920212223242526272829301234",
+ "Other months - show");
+ ok(pop.find("td:last span").length === 1, "Other months - span content");
+ inp.datepicker("hide").datepicker("option", "selectOtherMonths", true).datepicker("show");
+ equal(pop.find("tbody").text(), "311234567891011121314151617181920212223242526272829301234",
+ "Other months - select");
+ ok(pop.find("td:last a").length === 1, "Other months - link content");
+ inp.datepicker("hide").datepicker("option", "showOtherMonths", false).datepicker("show");
+ equal(pop.find("tbody").text(),
+ // support: IE <9, jQuery <1.8
+ // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways
+ $( "<span>\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0</span>" ).text(),
+ "Other months - none");
+ ok(pop.find("td:last *").length === 0, "Other months - no content");
+});
+
+test("defaultDate", function() {
+ expect( 16 );
+ var inp = TestHelpers.datepicker.init("#inp"),
+ date = new Date();
+ inp.val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date null");
+
+ // Numeric values
+ inp.datepicker("option", {defaultDate: -2}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() - 2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date -2");
+
+ date = new Date();
+ inp.datepicker("option", {defaultDate: 3}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 3);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date 3");
+
+ date = new Date();
+ inp.datepicker("option", {defaultDate: 1 / "a"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date NaN");
+
+ // String offset values
+ inp.datepicker("option", {defaultDate: "-1d"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() - 1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date -1d");
+ inp.datepicker("option", {defaultDate: "+3D"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 4);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date +3D");
+ inp.datepicker("option", {defaultDate: " -2 w "}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = new Date();
+ date.setDate(date.getDate() - 14);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date -2 w");
+ inp.datepicker("option", {defaultDate: "+1 W"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setDate(date.getDate() + 21);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date +1 W");
+ inp.datepicker("option", {defaultDate: " -1 m "}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = TestHelpers.datepicker.addMonths(new Date(), -1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date -1 m");
+ inp.datepicker("option", {defaultDate: "+2M"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = TestHelpers.datepicker.addMonths(new Date(), 2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date +2M");
+ inp.datepicker("option", {defaultDate: "-2y"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = new Date();
+ date.setFullYear(date.getFullYear() - 2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date -2y");
+ inp.datepicker("option", {defaultDate: "+1 Y "}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date.setFullYear(date.getFullYear() + 3);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date +1 Y");
+ inp.datepicker("option", {defaultDate: "+1M +10d"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = TestHelpers.datepicker.addMonths(new Date(), 1);
+ date.setDate(date.getDate() + 10);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date +1M +10d");
+ // String date values
+ inp.datepicker("option", {defaultDate: "07/04/2007"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = new Date(2007, 7 - 1, 4);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date 07/04/2007");
+ inp.datepicker("option", {dateFormat: "yy-mm-dd", defaultDate: "2007-04-02"}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = new Date(2007, 4 - 1, 2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date 2007-04-02");
+ // Date value
+ date = new Date(2007, 1 - 1, 26);
+ inp.datepicker("option", {dateFormat: "mm/dd/yy", defaultDate: date}).
+ datepicker("hide").val("").datepicker("show").
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date, "Default date 01/26/2007");
+});
+
+test("miscellaneous", function() {
+ expect( 19 );
+ var curYear, longNames, shortNames, date,
+ dp = $("#ui-datepicker-div"),
+ inp = TestHelpers.datepicker.init("#inp");
+ // Year range
+ function genRange(start, offset) {
+ var i = start,
+ range = "";
+ for (; i < start + offset; i++) {
+ range += i;
+ }
+ return range;
+ }
+ curYear = new Date().getFullYear();
+ inp.val("02/04/2008").datepicker("show");
+ equal(dp.find(".ui-datepicker-year").text(), "2008", "Year range - read-only default");
+ inp.datepicker("hide").datepicker("option", {changeYear: true}).datepicker("show");
+ equal(dp.find(".ui-datepicker-year").text(), genRange(2008 - 10, 21), "Year range - changeable default");
+ inp.datepicker("hide").datepicker("option", {yearRange: "c-6:c+2", changeYear: true}).datepicker("show");
+ equal(dp.find(".ui-datepicker-year").text(), genRange(2008 - 6, 9), "Year range - c-6:c+2");
+ inp.datepicker("hide").datepicker("option", {yearRange: "2000:2010", changeYear: true}).datepicker("show");
+ equal(dp.find(".ui-datepicker-year").text(), genRange(2000, 11), "Year range - 2000:2010");
+ inp.datepicker("hide").datepicker("option", {yearRange: "-5:+3", changeYear: true}).datepicker("show");
+ equal(dp.find(".ui-datepicker-year").text(), genRange(curYear - 5, 9), "Year range - -5:+3");
+ inp.datepicker("hide").datepicker("option", {yearRange: "2000:-5", changeYear: true}).datepicker("show");
+ equal(dp.find(".ui-datepicker-year").text(), genRange(2000, curYear - 2004), "Year range - 2000:-5");
+ inp.datepicker("hide").datepicker("option", {yearRange: "", changeYear: true}).datepicker("show");
+ equal(dp.find(".ui-datepicker-year").text(), genRange(curYear, 1), "Year range - -6:+2");
+
+ // Navigation as date format
+ inp.datepicker("option", {showButtonPanel: true});
+ equal(dp.find(".ui-datepicker-prev").text(), "Prev", "Navigation prev - default");
+ equal(dp.find(".ui-datepicker-current").text(), "Today", "Navigation current - default");
+ equal(dp.find(".ui-datepicker-next").text(), "Next", "Navigation next - default");
+ inp.datepicker("hide").datepicker("option", {navigationAsDateFormat: true, prevText: "< M", currentText: "MM", nextText: "M >"}).
+ val("02/04/2008").datepicker("show");
+ longNames = $.datepicker.regional[""].monthNames;
+ shortNames = $.datepicker.regional[""].monthNamesShort;
+ date = new Date();
+ equal(dp.find(".ui-datepicker-prev").text(), "< " + shortNames[0], "Navigation prev - as date format");
+ equal(dp.find(".ui-datepicker-current").text(),
+ longNames[date.getMonth()], "Navigation current - as date format");
+ equal(dp.find(".ui-datepicker-next").text(),
+ shortNames[2] + " >", "Navigation next - as date format");
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
+ equal(dp.find(".ui-datepicker-prev").text(),
+ "< " + shortNames[1], "Navigation prev - as date format + pgdn");
+ equal(dp.find(".ui-datepicker-current").text(),
+ longNames[date.getMonth()], "Navigation current - as date format + pgdn");
+ equal(dp.find(".ui-datepicker-next").text(),
+ shortNames[3] + " >", "Navigation next - as date format + pgdn");
+ inp.datepicker("hide").datepicker("option", {gotoCurrent: true}).
+ val("02/04/2008").datepicker("show");
+ equal(dp.find(".ui-datepicker-prev").text(),
+ "< " + shortNames[0], "Navigation prev - as date format + goto current");
+ equal(dp.find(".ui-datepicker-current").text(),
+ longNames[1], "Navigation current - as date format + goto current");
+ equal(dp.find(".ui-datepicker-next").text(),
+ shortNames[2] + " >", "Navigation next - as date format + goto current");
+});
+
+test("minMax", function() {
+ expect( 23 );
+ var date,
+ inp = TestHelpers.datepicker.init("#inp"),
+ dp = $("#ui-datepicker-div"),
+ lastYear = new Date(2007, 6 - 1, 4),
+ nextYear = new Date(2009, 6 - 1, 4),
+ minDate = new Date(2008, 2 - 1, 29),
+ maxDate = new Date(2008, 12 - 1, 7);
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), lastYear,
+ "Min/max - null, null - ctrl+pgup");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), nextYear,
+ "Min/max - null, null - ctrl+pgdn");
+ inp.datepicker("option", {minDate: minDate}).
+ datepicker("hide").val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), minDate,
+ "Min/max - 02/29/2008, null - ctrl+pgup");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), nextYear,
+ "Min/max - 02/29/2008, null - ctrl+pgdn");
+ inp.datepicker("option", {maxDate: maxDate}).
+ datepicker("hide").val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), minDate,
+ "Min/max - 02/29/2008, 12/07/2008 - ctrl+pgup");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), maxDate,
+ "Min/max - 02/29/2008, 12/07/2008 - ctrl+pgdn");
+ inp.datepicker("option", {minDate: null}).
+ datepicker("hide").val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), lastYear,
+ "Min/max - null, 12/07/2008 - ctrl+pgup");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), maxDate,
+ "Min/max - null, 12/07/2008 - ctrl+pgdn");
+ // Relative dates
+ date = new Date();
+ date.setDate(date.getDate() - 7);
+ inp.datepicker("option", {minDate: "-1w", maxDate: "+1 M +10 D "}).
+ datepicker("hide").val("").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date,
+ "Min/max - -1w, +1 M +10 D - ctrl+pgup");
+ date = TestHelpers.datepicker.addMonths(new Date(), 1);
+ date.setDate(date.getDate() + 10);
+ inp.val("").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date,
+ "Min/max - -1w, +1 M +10 D - ctrl+pgdn");
+ // With existing date
+ inp = TestHelpers.datepicker.init("#inp");
+ inp.val("06/04/2008").datepicker("option", {minDate: minDate});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 6 - 1, 4), "Min/max - setDate > min");
+ inp.datepicker("option", {minDate: null}).val("01/04/2008").datepicker("option", {minDate: minDate});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), minDate, "Min/max - setDate < min");
+ inp.datepicker("option", {minDate: null}).val("06/04/2008").datepicker("option", {maxDate: maxDate});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 6 - 1, 4), "Min/max - setDate < max");
+ inp.datepicker("option", {maxDate: null}).val("01/04/2009").datepicker("option", {maxDate: maxDate});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), maxDate, "Min/max - setDate > max");
+ inp.datepicker("option", {maxDate: null}).val("01/04/2008").datepicker("option", {minDate: minDate, maxDate: maxDate});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), minDate, "Min/max - setDate < min");
+ inp.datepicker("option", {maxDate: null}).val("06/04/2008").datepicker("option", {minDate: minDate, maxDate: maxDate});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), new Date(2008, 6 - 1, 4), "Min/max - setDate > min, < max");
+ inp.datepicker("option", {maxDate: null}).val("01/04/2009").datepicker("option", {minDate: minDate, maxDate: maxDate});
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), maxDate, "Min/max - setDate > max");
+
+ inp.datepicker("option", {yearRange: "-0:+1"}).val("01/01/" + new Date().getFullYear());
+ ok(dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - previous button disabled at 1/1/minYear");
+ inp.datepicker("setDate", "12/30/" + new Date().getFullYear());
+ ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - next button disabled at 12/30/maxYear");
+
+ inp.datepicker("option", {
+ minDate: new Date(1900, 0, 1),
+ maxDate: "-6Y",
+ yearRange: "1900:-6"
+ }).val( "" );
+ ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - next button disabled");
+ ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - prev button enabled");
+
+ inp.datepicker("option", {
+ minDate: new Date(1900, 0, 1),
+ maxDate: "1/25/2007",
+ yearRange: "1900:2007"
+ }).val( "" );
+ ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - next button disabled");
+ ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - prev button enabled");
+});
+
+test("setDate", function() {
+ expect( 24 );
+ var inl, alt, minDate, maxDate, dateAndTimeToSet, dateAndTimeClone,
+ inp = TestHelpers.datepicker.init("#inp"),
+ date1 = new Date(2008, 6 - 1, 4),
+ date2 = new Date();
+ ok(inp.datepicker("getDate") == null, "Set date - default");
+ inp.datepicker("setDate", date1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date1, "Set date - 2008-06-04");
+ date1 = new Date();
+ date1.setDate(date1.getDate() + 7);
+ inp.datepicker("setDate", +7);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date1, "Set date - +7");
+ date2.setFullYear(date2.getFullYear() + 2);
+ inp.datepicker("setDate", "+2y");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date2, "Set date - +2y");
+ inp.datepicker("setDate", date1, date2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date1, "Set date - two dates");
+ inp.datepicker("setDate");
+ ok(inp.datepicker("getDate") == null, "Set date - null");
+ // Relative to current date
+ date1 = new Date();
+ date1.setDate(date1.getDate() + 7);
+ inp.datepicker("setDate", "c +7");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date1, "Set date - c +7");
+ date1.setDate(date1.getDate() + 7);
+ inp.datepicker("setDate", "c+7");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date1, "Set date - c+7");
+ date1.setDate(date1.getDate() - 21);
+ inp.datepicker("setDate", "c -3 w");
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date1, "Set date - c -3 w");
+ // Inline
+ inl = TestHelpers.datepicker.init("#inl");
+ date1 = new Date(2008, 6 - 1, 4);
+ date2 = new Date();
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), date2, "Set date inline - default");
+ inl.datepicker("setDate", date1);
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), date1, "Set date inline - 2008-06-04");
+ date1 = new Date();
+ date1.setDate(date1.getDate() + 7);
+ inl.datepicker("setDate", +7);
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), date1, "Set date inline - +7");
+ date2.setFullYear(date2.getFullYear() + 2);
+ inl.datepicker("setDate", "+2y");
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), date2, "Set date inline - +2y");
+ inl.datepicker("setDate", date1, date2);
+ TestHelpers.datepicker.equalsDate(inl.datepicker("getDate"), date1, "Set date inline - two dates");
+ inl.datepicker("setDate");
+ ok(inl.datepicker("getDate") == null, "Set date inline - null");
+ // Alternate field
+ alt = $("#alt");
+ inp.datepicker("option", {altField: "#alt", altFormat: "yy-mm-dd"});
+ date1 = new Date(2008, 6 - 1, 4);
+ inp.datepicker("setDate", date1);
+ equal(inp.val(), "06/04/2008", "Set date alternate - 06/04/2008");
+ equal(alt.val(), "2008-06-04", "Set date alternate - 2008-06-04");
+ // With minimum/maximum
+ inp = TestHelpers.datepicker.init("#inp");
+ date1 = new Date(2008, 1 - 1, 4);
+ date2 = new Date(2008, 6 - 1, 4);
+ minDate = new Date(2008, 2 - 1, 29);
+ maxDate = new Date(2008, 3 - 1, 28);
+ inp.val("").datepicker("option", {minDate: minDate}).datepicker("setDate", date2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date2, "Set date min/max - setDate > min");
+ inp.datepicker("setDate", date1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), minDate, "Set date min/max - setDate < min");
+ inp.val("").datepicker("option", {maxDate: maxDate, minDate: null}).datepicker("setDate", date1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), date1, "Set date min/max - setDate < max");
+ inp.datepicker("setDate", date2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), maxDate, "Set date min/max - setDate > max");
+ inp.val("").datepicker("option", {minDate: minDate}).datepicker("setDate", date1);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), minDate, "Set date min/max - setDate < min");
+ inp.datepicker("setDate", date2);
+ TestHelpers.datepicker.equalsDate(inp.datepicker("getDate"), maxDate, "Set date min/max - setDate > max");
+ dateAndTimeToSet = new Date(2008, 3 - 1, 28, 1, 11, 0);
+ dateAndTimeClone = new Date(2008, 3 - 1, 28, 1, 11, 0);
+ inp.datepicker("setDate", dateAndTimeToSet);
+ equal(dateAndTimeToSet.getTime(), dateAndTimeClone.getTime(), "Date object passed should not be changed by setDate");
+});
+
+test("altField", function() {
+ expect( 10 );
+ var inp = TestHelpers.datepicker.init("#inp"),
+ alt = $("#alt");
+ // No alternate field set
+ alt.val("");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ equal(inp.val(), "06/04/2008", "Alt field - dp - enter");
+ equal(alt.val(), "", "Alt field - alt not set");
+ // Alternate field set
+ alt.val("");
+ inp.datepicker("option", {altField: "#alt", altFormat: "yy-mm-dd"}).
+ val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ equal(inp.val(), "06/04/2008", "Alt field - dp - enter");
+ equal(alt.val(), "2008-06-04", "Alt field - alt - enter");
+ // Move from initial date
+ alt.val("");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ equal(inp.val(), "07/04/2008", "Alt field - dp - pgdn");
+ equal(alt.val(), "2008-07-04", "Alt field - alt - pgdn");
+ // Alternate field set - closed
+ alt.val("");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
+ simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
+ equal(inp.val(), "06/04/2008", "Alt field - dp - pgdn/esc");
+ equal(alt.val(), "", "Alt field - alt - pgdn/esc");
+ // Clear date and alternate
+ alt.val("");
+ inp.val("06/04/2008").datepicker("show");
+ inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
+ equal(inp.val(), "", "Alt field - dp - ctrl+end");
+ equal(alt.val(), "", "Alt field - alt - ctrl+end");
+});
+
+test("autoSize", function() {
+ expect( 15 );
+ var inp = TestHelpers.datepicker.init("#inp");
+ equal(inp.prop("size"), 20, "Auto size - default");
+ inp.datepicker("option", "autoSize", true);
+ equal(inp.prop("size"), 10, "Auto size - mm/dd/yy");
+ inp.datepicker("option", "dateFormat", "m/d/yy");
+ equal(inp.prop("size"), 10, "Auto size - m/d/yy");
+ inp.datepicker("option", "dateFormat", "D M d yy");
+ equal(inp.prop("size"), 15, "Auto size - D M d yy");
+ inp.datepicker("option", "dateFormat", "DD, MM dd, yy");
+ equal(inp.prop("size"), 29, "Auto size - DD, MM dd, yy");
+
+ // French
+ inp.datepicker("option", $.extend({autoSize: false}, $.datepicker.regional.fr));
+ equal(inp.prop("size"), 29, "Auto size - fr - default");
+ inp.datepicker("option", "autoSize", true);
+ equal(inp.prop("size"), 10, "Auto size - fr - dd/mm/yy");
+ inp.datepicker("option", "dateFormat", "m/d/yy");
+ equal(inp.prop("size"), 10, "Auto size - fr - m/d/yy");
+ inp.datepicker("option", "dateFormat", "D M d yy");
+ equal(inp.prop("size"), 18, "Auto size - fr - D M d yy");
+ inp.datepicker("option", "dateFormat", "DD, MM dd, yy");
+ equal(inp.prop("size"), 28, "Auto size - fr - DD, MM dd, yy");
+
+ // Hebrew
+ inp.datepicker("option", $.extend({autoSize: false}, $.datepicker.regional.he));
+ equal(inp.prop("size"), 28, "Auto size - he - default");
+ inp.datepicker("option", "autoSize", true);
+ equal(inp.prop("size"), 10, "Auto size - he - dd/mm/yy");
+ inp.datepicker("option", "dateFormat", "m/d/yy");
+ equal(inp.prop("size"), 10, "Auto size - he - m/d/yy");
+ inp.datepicker("option", "dateFormat", "D M d yy");
+ equal(inp.prop("size"), 16, "Auto size - he - D M d yy");
+ inp.datepicker("option", "dateFormat", "DD, MM dd, yy");
+ equal(inp.prop("size"), 23, "Auto size - he - DD, MM dd, yy");
+});
+
+test("daylightSaving", function() {
+ expect( 25 );
+ var inp = TestHelpers.datepicker.init("#inp"),
+ dp = $("#ui-datepicker-div");
+ ok(true, "Daylight saving - " + new Date());
+ // Australia, Sydney - AM change, southern hemisphere
+ inp.val("04/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(6) a", dp).simulate("click");
+ equal(inp.val(), "04/05/2008", "Daylight saving - Australia 04/05/2008");
+ inp.val("04/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(7) a", dp).simulate("click");
+ equal(inp.val(), "04/06/2008", "Daylight saving - Australia 04/06/2008");
+ inp.val("04/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(8) a", dp).simulate("click");
+ equal(inp.val(), "04/07/2008", "Daylight saving - Australia 04/07/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(6) a", dp).simulate("click");
+ equal(inp.val(), "10/04/2008", "Daylight saving - Australia 10/04/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(7) a", dp).simulate("click");
+ equal(inp.val(), "10/05/2008", "Daylight saving - Australia 10/05/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(8) a", dp).simulate("click");
+ equal(inp.val(), "10/06/2008", "Daylight saving - Australia 10/06/2008");
+ // Brasil, Brasilia - midnight change, southern hemisphere
+ inp.val("02/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(20) a", dp).simulate("click");
+ equal(inp.val(), "02/16/2008", "Daylight saving - Brasil 02/16/2008");
+ inp.val("02/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(21) a", dp).simulate("click");
+ equal(inp.val(), "02/17/2008", "Daylight saving - Brasil 02/17/2008");
+ inp.val("02/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(22) a", dp).simulate("click");
+ equal(inp.val(), "02/18/2008", "Daylight saving - Brasil 02/18/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(13) a", dp).simulate("click");
+ equal(inp.val(), "10/11/2008", "Daylight saving - Brasil 10/11/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(14) a", dp).simulate("click");
+ equal(inp.val(), "10/12/2008", "Daylight saving - Brasil 10/12/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(15) a", dp).simulate("click");
+ equal(inp.val(), "10/13/2008", "Daylight saving - Brasil 10/13/2008");
+ // Lebanon, Beirut - midnight change, northern hemisphere
+ inp.val("03/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(34) a", dp).simulate("click");
+ equal(inp.val(), "03/29/2008", "Daylight saving - Lebanon 03/29/2008");
+ inp.val("03/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(35) a", dp).simulate("click");
+ equal(inp.val(), "03/30/2008", "Daylight saving - Lebanon 03/30/2008");
+ inp.val("03/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(36) a", dp).simulate("click");
+ equal(inp.val(), "03/31/2008", "Daylight saving - Lebanon 03/31/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(27) a", dp).simulate("click");
+ equal(inp.val(), "10/25/2008", "Daylight saving - Lebanon 10/25/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(28) a", dp).simulate("click");
+ equal(inp.val(), "10/26/2008", "Daylight saving - Lebanon 10/26/2008");
+ inp.val("10/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(29) a", dp).simulate("click");
+ equal(inp.val(), "10/27/2008", "Daylight saving - Lebanon 10/27/2008");
+ // US, Eastern - AM change, northern hemisphere
+ inp.val("03/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(13) a", dp).simulate("click");
+ equal(inp.val(), "03/08/2008", "Daylight saving - US 03/08/2008");
+ inp.val("03/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(14) a", dp).simulate("click");
+ equal(inp.val(), "03/09/2008", "Daylight saving - US 03/09/2008");
+ inp.val("03/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(15) a", dp).simulate("click");
+ equal(inp.val(), "03/10/2008", "Daylight saving - US 03/10/2008");
+ inp.val("11/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(6) a", dp).simulate("click");
+ equal(inp.val(), "11/01/2008", "Daylight saving - US 11/01/2008");
+ inp.val("11/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(7) a", dp).simulate("click");
+ equal(inp.val(), "11/02/2008", "Daylight saving - US 11/02/2008");
+ inp.val("11/01/2008").datepicker("show");
+ $(".ui-datepicker-calendar td:eq(8) a", dp).simulate("click");
+ equal(inp.val(), "11/03/2008", "Daylight saving - US 11/03/2008");
+});
+
+var beforeShowThis = null,
+ beforeShowInput = null,
+ beforeShowInst = null,
+ beforeShowDayThis = null,
+ beforeShowDayOK = true;
+
+
+function beforeAll(input, inst) {
+ beforeShowThis = this;
+ beforeShowInput = input;
+ beforeShowInst = inst;
+ return {currentText: "Current"};
+}
+
+function beforeDay(date) {
+ beforeShowDayThis = this;
+ beforeShowDayOK &= (date > new Date(2008, 1 - 1, 26) &&
+ date < new Date(2008, 3 - 1, 6));
+ return [(date.getDate() % 2 === 0), (date.getDate() % 10 === 0 ? "day10" : ""),
+ (date.getDate() % 3 === 0 ? "Divisble by 3" : "")];
+}
+
+test("callbacks", function() {
+ expect( 13 );
+ // Before show
+ var dp, day20, day21,
+ inp = TestHelpers.datepicker.init("#inp", {beforeShow: beforeAll}),
+ inst = $.data(inp[0], "datepicker");
+ equal($.datepicker._get(inst, "currentText"), "Today", "Before show - initial");
+ inp.val("02/04/2008").datepicker("show");
+ equal($.datepicker._get(inst, "currentText"), "Current", "Before show - changed");
+ ok(beforeShowThis.id === inp[0].id, "Before show - this OK");
+ ok(beforeShowInput.id === inp[0].id, "Before show - input OK");
+ deepEqual(beforeShowInst, inst, "Before show - inst OK");
+ inp.datepicker("hide").datepicker("destroy");
+ // Before show day
+ inp = TestHelpers.datepicker.init("#inp", {beforeShowDay: beforeDay});
+ dp = $("#ui-datepicker-div");
+ inp.val("02/04/2008").datepicker("show");
+ ok(beforeShowDayThis.id === inp[0].id, "Before show day - this OK");
+ ok(beforeShowDayOK, "Before show day - dates OK");
+ day20 = dp.find(".ui-datepicker-calendar td:contains('20')");
+ day21 = dp.find(".ui-datepicker-calendar td:contains('21')");
+ ok(!day20.is(".ui-datepicker-unselectable"), "Before show day - unselectable 20");
+ ok(day21.is(".ui-datepicker-unselectable"), "Before show day - unselectable 21");
+ ok(day20.is(".day10"), "Before show day - CSS 20");
+ ok(!day21.is(".day10"), "Before show day - CSS 21");
+ ok(!day20.attr("title"), "Before show day - title 20");
+ ok(day21.attr("title") === "Divisble by 3", "Before show day - title 21");
+ inp.datepicker("hide").datepicker("destroy");
+});
+
+test("beforeShowDay - tooltips with quotes", function() {
+ expect( 1 );
+ var inp, dp;
+ inp = TestHelpers.datepicker.init("#inp", {
+ beforeShowDay: function() {
+ return [ true, "", "'" ];
+ }
+ });
+ dp = $("#ui-datepicker-div");
+
+ inp.datepicker("show");
+ equal( dp.find( ".ui-datepicker-calendar td:contains('9')").attr( "title" ), "'" );
+ inp.datepicker("hide").datepicker("destroy");
+});
+
+test("localisation", function() {
+ expect( 24 );
+ var dp, month, day, date,
+ inp = TestHelpers.datepicker.init("#inp", $.datepicker.regional.fr);
+ inp.datepicker("option", {dateFormat: "DD, d MM yy", showButtonPanel:true, changeMonth:true, changeYear:true}).val("").datepicker("show");
+ dp = $("#ui-datepicker-div");
+ equal($(".ui-datepicker-close", dp).text(), "Fermer", "Localisation - close");
+ $(".ui-datepicker-close", dp).simulate("mouseover");
+ equal($(".ui-datepicker-prev", dp).text(), "Précédent", "Localisation - previous");
+ equal($(".ui-datepicker-current", dp).text(), "Aujourd'hui", "Localisation - current");
+ equal($(".ui-datepicker-next", dp).text(), "Suivant", "Localisation - next");
+ month = 0;
+ $(".ui-datepicker-month option", dp).each(function() {
+ equal($(this).text(), $.datepicker.regional.fr.monthNamesShort[month],
+ "Localisation - month " + month);
+ month++;
+ });
+ day = 1;
+ $(".ui-datepicker-calendar th", dp).each(function() {
+ equal($(this).text(), $.datepicker.regional.fr.dayNamesMin[day],
+ "Localisation - day " + day);
+ day = (day + 1) % 7;
+ });
+ inp.simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
+ date = new Date();
+ equal(inp.val(), $.datepicker.regional.fr.dayNames[date.getDay()] + ", " +
+ date.getDate() + " " + $.datepicker.regional.fr.monthNames[date.getMonth()] +
+ " " + date.getFullYear(), "Localisation - formatting");
+});
+
+test("noWeekends", function() {
+ expect( 31 );
+ var i, date;
+ for (i = 1; i <= 31; i++) {
+ date = new Date(2001, 1 - 1, i);
+ deepEqual($.datepicker.noWeekends(date), [(i + 1) % 7 >= 2, ""],
+ "No weekends " + date);
+ }
+});
+
+test("iso8601Week", function() {
+ expect( 12 );
+ var date = new Date(2000, 12 - 1, 31);
+ equal($.datepicker.iso8601Week(date), 52, "ISO 8601 week " + date);
+ date = new Date(2001, 1 - 1, 1);
+ equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
+ date = new Date(2001, 1 - 1, 7);
+ equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
+ date = new Date(2001, 1 - 1, 8);
+ equal($.datepicker.iso8601Week(date), 2, "ISO 8601 week " + date);
+ date = new Date(2003, 12 - 1, 28);
+ equal($.datepicker.iso8601Week(date), 52, "ISO 8601 week " + date);
+ date = new Date(2003, 12 - 1, 29);
+ equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
+ date = new Date(2004, 1 - 1, 4);
+ equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
+ date = new Date(2004, 1 - 1, 5);
+ equal($.datepicker.iso8601Week(date), 2, "ISO 8601 week " + date);
+ date = new Date(2009, 12 - 1, 28);
+ equal($.datepicker.iso8601Week(date), 53, "ISO 8601 week " + date);
+ date = new Date(2010, 1 - 1, 3);
+ equal($.datepicker.iso8601Week(date), 53, "ISO 8601 week " + date);
+ date = new Date(2010, 1 - 1, 4);
+ equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
+ date = new Date(2010, 1 - 1, 10);
+ equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
+});
+
+test("parseDate", function() {
+ expect( 26 );
+ TestHelpers.datepicker.init("#inp");
+ var currentYear, gmtDate, fr, settings, zh;
+ ok($.datepicker.parseDate("d m y", "") == null, "Parse date empty");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("d m y", "3 2 01"),
+ new Date(2001, 2 - 1, 3), "Parse date d m y");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("dd mm yy", "03 02 2001"),
+ new Date(2001, 2 - 1, 3), "Parse date dd mm yy");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("d m y", "13 12 01"),
+ new Date(2001, 12 - 1, 13), "Parse date d m y");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("dd mm yy", "13 12 2001"),
+ new Date(2001, 12 - 1, 13), "Parse date dd mm yy");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-o", "01-34"),
+ new Date(2001, 2 - 1, 3), "Parse date y-o");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("yy-oo", "2001-347"),
+ new Date(2001, 12 - 1, 13), "Parse date yy-oo");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("oo yy", "348 2004"),
+ new Date(2004, 12 - 1, 13), "Parse date oo yy");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("D d M y", "Sat 3 Feb 01"),
+ new Date(2001, 2 - 1, 3), "Parse date D d M y");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("d MM DD yy", "3 February Saturday 2001"),
+ new Date(2001, 2 - 1, 3), "Parse date dd MM DD yy");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("DD, MM d, yy", "Saturday, February 3, 2001"),
+ new Date(2001, 2 - 1, 3), "Parse date DD, MM d, yy");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("'day' d 'of' MM (''DD''), yy",
+ "day 3 of February ('Saturday'), 2001"), new Date(2001, 2 - 1, 3),
+ "Parse date 'day' d 'of' MM (''DD''), yy");
+ currentYear = new Date().getFullYear();
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000) + "-02-03"),
+ new Date(currentYear, 2 - 1, 3), "Parse date y-m-d - default cutuff");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 10) + "-02-03"),
+ new Date(currentYear+10, 2 - 1, 3), "Parse date y-m-d - default cutuff");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 11) + "-02-03"),
+ new Date(currentYear-89, 2 - 1, 3), "Parse date y-m-d - default cutuff");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-m-d", "80-02-03", {shortYearCutoff: 80}),
+ new Date(2080, 2 - 1, 3), "Parse date y-m-d - cutoff 80");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-m-d", "81-02-03", {shortYearCutoff: 80}),
+ new Date(1981, 2 - 1, 3), "Parse date y-m-d - cutoff 80");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 60) + "-02-03", {shortYearCutoff: "+60"}),
+ new Date(currentYear + 60, 2 - 1, 3), "Parse date y-m-d - cutoff +60");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 61) + "-02-03", {shortYearCutoff: "+60"}),
+ new Date(currentYear - 39, 2 - 1, 3), "Parse date y-m-d - cutoff +60");
+ gmtDate = new Date(2001, 2 - 1, 3);
+ gmtDate.setMinutes(gmtDate.getMinutes() - gmtDate.getTimezoneOffset());
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("@", "981158400000"), gmtDate, "Parse date @");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("!", "631167552000000000"), gmtDate, "Parse date !");
+
+ fr = $.datepicker.regional.fr;
+ settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames,
+ monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames};
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("D d M y", "Lun. 9 Avril 01", settings),
+ new Date(2001, 4 - 1, 9), "Parse date D M y with settings");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("d MM DD yy", "9 Avril Lundi 2001", settings),
+ new Date(2001, 4 - 1, 9), "Parse date d MM DD yy with settings");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("DD, MM d, yy", "Lundi, Avril 9, 2001", settings),
+ new Date(2001, 4 - 1, 9), "Parse date DD, MM d, yy with settings");
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("'jour' d 'de' MM (''DD''), yy", "jour 9 de Avril ('Lundi'), 2001", settings),
+ new Date(2001, 4 - 1, 9), "Parse date 'jour' d 'de' MM (''DD''), yy with settings");
+
+ zh = $.datepicker.regional["zh-CN"];
+ TestHelpers.datepicker.equalsDate($.datepicker.parseDate("yy M d", "2011 十一月 22", zh),
+ new Date(2011, 11 - 1, 22), "Parse date yy M d with zh-CN");
+});
+
+test("parseDateErrors", function() {
+ expect( 17 );
+ TestHelpers.datepicker.init("#inp");
+ var fr, settings;
+ function expectError(expr, value, error) {
+ try {
+ expr();
+ ok(false, "Parsed error " + value);
+ }
+ catch (e) {
+ equal(e, error, "Parsed error " + value);
+ }
+ }
+ expectError(function() { $.datepicker.parseDate(null, "Sat 2 01"); },
+ "Sat 2 01", "Invalid arguments");
+ expectError(function() { $.datepicker.parseDate("d m y", null); },
+ "null", "Invalid arguments");
+ expectError(function() { $.datepicker.parseDate("d m y", "Sat 2 01"); },
+ "Sat 2 01 - d m y", "Missing number at position 0");
+ expectError(function() { $.datepicker.parseDate("dd mm yy", "Sat 2 01"); },
+ "Sat 2 01 - dd mm yy", "Missing number at position 0");
+ expectError(function() { $.datepicker.parseDate("d m y", "3 Feb 01"); },
+ "3 Feb 01 - d m y", "Missing number at position 2");
+ expectError(function() { $.datepicker.parseDate("dd mm yy", "3 Feb 01"); },
+ "3 Feb 01 - dd mm yy", "Missing number at position 2");
+ expectError(function() { $.datepicker.parseDate("d m y", "3 2 AD01"); },
+ "3 2 AD01 - d m y", "Missing number at position 4");
+ expectError(function() { $.datepicker.parseDate("d m yy", "3 2 AD01"); },
+ "3 2 AD01 - dd mm yy", "Missing number at position 4");
+ expectError(function() { $.datepicker.parseDate("y-o", "01-D01"); },
+ "2001-D01 - y-o", "Missing number at position 3");
+ expectError(function() { $.datepicker.parseDate("yy-oo", "2001-D01"); },
+ "2001-D01 - yy-oo", "Missing number at position 5");
+ expectError(function() { $.datepicker.parseDate("D d M y", "D7 3 Feb 01"); },
+ "D7 3 Feb 01 - D d M y", "Unknown name at position 0");
+ expectError(function() { $.datepicker.parseDate("D d M y", "Sat 3 M2 01"); },
+ "Sat 3 M2 01 - D d M y", "Unknown name at position 6");
+ expectError(function() { $.datepicker.parseDate("DD, MM d, yy", "Saturday- Feb 3, 2001"); },
+ "Saturday- Feb 3, 2001 - DD, MM d, yy", "Unexpected literal at position 8");
+ expectError(function() { $.datepicker.parseDate("'day' d 'of' MM (''DD''), yy",
+ "day 3 of February (\"Saturday\"), 2001"); },
+ "day 3 of Mon2 ('Day7'), 2001", "Unexpected literal at position 19");
+ expectError(function() { $.datepicker.parseDate("d m y", "29 2 01"); },
+ "29 2 01 - d m y", "Invalid date");
+ fr = $.datepicker.regional.fr;
+ settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames,
+ monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames};
+ expectError(function() { $.datepicker.parseDate("D d M y", "Mon 9 Avr 01", settings); },
+ "Mon 9 Avr 01 - D d M y", "Unknown name at position 0");
+ expectError(function() { $.datepicker.parseDate("D d M y", "Lun. 9 Apr 01", settings); },
+ "Lun. 9 Apr 01 - D d M y", "Unknown name at position 7");
+});
+
+test("Ticket #7244: date parser does not fail when too many numbers are passed into the date function", function() {
+ expect( 4 );
+ var date;
+ try{
+ date = $.datepicker.parseDate("dd/mm/yy", "18/04/19881");
+ ok(false, "Did not properly detect an invalid date");
+ }catch(e){
+ ok("invalid date detected");
+ }
+
+ try {
+ date = $.datepicker.parseDate("dd/mm/yy", "18/04/1988 @ 2:43 pm");
+ equal(date.getDate(), 18);
+ equal(date.getMonth(), 3);
+ equal(date.getFullYear(), 1988);
+ } catch(e) {
+ ok(false, "Did not properly parse date with extra text separated by whitespace");
+ }
+});
+
+test("formatDate", function() {
+ expect( 16 );
+ TestHelpers.datepicker.init("#inp");
+ var gmtDate, fr, settings;
+ equal($.datepicker.formatDate("d m y", new Date(2001, 2 - 1, 3)),
+ "3 2 01", "Format date d m y");
+ equal($.datepicker.formatDate("dd mm yy", new Date(2001, 2 - 1, 3)),
+ "03 02 2001", "Format date dd mm yy");
+ equal($.datepicker.formatDate("d m y", new Date(2001, 12 - 1, 13)),
+ "13 12 01", "Format date d m y");
+ equal($.datepicker.formatDate("dd mm yy", new Date(2001, 12 - 1, 13)),
+ "13 12 2001", "Format date dd mm yy");
+ equal($.datepicker.formatDate("yy-o", new Date(2001, 2 - 1, 3)),
+ "2001-34", "Format date yy-o");
+ equal($.datepicker.formatDate("yy-oo", new Date(2001, 2 - 1, 3)),
+ "2001-034", "Format date yy-oo");
+ equal($.datepicker.formatDate("D M y", new Date(2001, 2 - 1, 3)),
+ "Sat Feb 01", "Format date D M y");
+ equal($.datepicker.formatDate("DD MM yy", new Date(2001, 2 - 1, 3)),
+ "Saturday February 2001", "Format date DD MM yy");
+ equal($.datepicker.formatDate("DD, MM d, yy", new Date(2001, 2 - 1, 3)),
+ "Saturday, February 3, 2001", "Format date DD, MM d, yy");
+ equal($.datepicker.formatDate("'day' d 'of' MM (''DD''), yy",
+ new Date(2001, 2 - 1, 3)), "day 3 of February ('Saturday'), 2001",
+ "Format date 'day' d 'of' MM ('DD'), yy");
+ gmtDate = new Date(2001, 2 - 1, 3);
+ gmtDate.setMinutes(gmtDate.getMinutes() - gmtDate.getTimezoneOffset());
+ equal($.datepicker.formatDate("@", gmtDate), "981158400000", "Format date @");
+ equal($.datepicker.formatDate("!", gmtDate), "631167552000000000", "Format date !");
+ fr = $.datepicker.regional.fr;
+ settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames,
+ monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames};
+ equal($.datepicker.formatDate("D M y", new Date(2001, 4 - 1, 9), settings),
+ "lun. avril 01", "Format date D M y with settings");
+ equal($.datepicker.formatDate("DD MM yy", new Date(2001, 4 - 1, 9), settings),
+ "lundi avril 2001", "Format date DD MM yy with settings");
+ equal($.datepicker.formatDate("DD, MM d, yy", new Date(2001, 4 - 1, 9), settings),
+ "lundi, avril 9, 2001", "Format date DD, MM d, yy with settings");
+ equal($.datepicker.formatDate("'jour' d 'de' MM (''DD''), yy",
+ new Date(2001, 4 - 1, 9), settings), "jour 9 de avril ('lundi'), 2001",
+ "Format date 'jour' d 'de' MM (''DD''), yy with settings");
+});
+
+// TODO: Fix this test so it isn't mysteriously flaky in Browserstack on certain OS/Browser combos
+// test("Ticket 6827: formatDate day of year calculation is wrong during day lights savings time", function(){
+// expect( 1 );
+// var time = $.datepicker.formatDate("oo", new Date("2010/03/30 12:00:00 CDT"));
+// equal(time, "089");
+// });
+
+test( "Ticket 7602: Stop datepicker from appearing with beforeShow event handler", function() {
+ expect( 3 );
+
+ var inp, dp;
+
+ inp = TestHelpers.datepicker.init( "#inp", {
+ beforeShow: function() {
+ }
+ });
+ dp = $( "#ui-datepicker-div" );
+ inp.datepicker( "show" );
+ equal( dp.css( "display" ), "block", "beforeShow returns nothing" );
+ inp.datepicker( "hide" ).datepicker( "destroy" );
+
+ inp = TestHelpers.datepicker.init( "#inp", {
+ beforeShow: function() {
+ return true;
+ }
+ });
+ dp = $( "#ui-datepicker-div" );
+ inp.datepicker( "show" );
+ equal( dp.css( "display" ), "block", "beforeShow returns true" );
+ inp.datepicker( "hide" );
+ inp.datepicker( "destroy" );
+
+ inp = TestHelpers.datepicker.init( "#inp", {
+ beforeShow: function() {
+ return false;
+ }
+ });
+ dp = $( "#ui-datepicker-div" );
+ inp.datepicker( "show" );
+ equal( dp.css( "display" ), "none","beforeShow returns false" );
+ inp.datepicker( "destroy" );
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/datepicker_test_helpers.js b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_test_helpers.js
new file mode 100644
index 0000000..9cb63c9
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/datepicker_test_helpers.js
@@ -0,0 +1,37 @@
+TestHelpers.datepicker = {
+ addMonths: function(date, offset) {
+ var maxDay = 32 - new Date(date.getFullYear(), date.getMonth() + offset, 32).getDate();
+ date.setDate(Math.min(date.getDate(), maxDay));
+ date.setMonth(date.getMonth() + offset);
+ return date;
+ },
+ equalsDate: function(d1, d2, message) {
+ if (!d1 || !d2) {
+ ok(false, message + " - missing date");
+ return;
+ }
+ d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate());
+ d2 = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate());
+ equal(d1.toString(), d2.toString(), message);
+ },
+ init: function( id, options ) {
+ $.datepicker.setDefaults( $.datepicker.regional[ "" ] );
+ return $( id ).datepicker( $.extend( { showAnim: "" }, options || {} ) );
+ },
+ initNewInput: function( options ) {
+ var id = $( "<input>" ).appendTo( "#qunit-fixture" );
+ return TestHelpers.datepicker.init( id, options );
+ },
+ onFocus: function( element, onFocus ) {
+ var fn = function( event ){
+ if( !event.originalEvent ) {
+ return;
+ }
+ element.unbind( "focus", fn );
+ onFocus();
+ };
+
+ element.bind( "focus", fn )[ 0 ].focus();
+ },
+ PROP_NAME: "datepicker"
+}; \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/datepicker/images/calendar.gif b/apps/it/static/js/ui/tests/unit/datepicker/images/calendar.gif
new file mode 100644
index 0000000..d0abaa7
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/datepicker/images/calendar.gif
Binary files differ
diff --git a/apps/it/static/js/ui/tests/unit/dialog/all.html b/apps/it/static/js/ui/tests/unit/dialog/all.html
new file mode 100644
index 0000000..9efbe3e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Dialog Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "dialog" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Dialog Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog.html b/apps/it/static/js/ui/tests/unit/dialog/dialog.html
new file mode 100644
index 0000000..d8506a1
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Dialog Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <script>
+ $.uiBackCompat = false;
+ </script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.dialog" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.position.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.draggable.js",
+ "ui/jquery.ui.resizable.js",
+ "ui/jquery.ui.button.js",
+ "ui/jquery.ui.effect.js",
+ "ui/jquery.ui.effect-blind.js",
+ "ui/jquery.ui.effect-clip.js",
+ "ui/jquery.ui.effect-explode.js",
+ "ui/jquery.ui.dialog.js"
+ ]
+ });
+ </script>
+
+ <script src="dialog_common.js"></script>
+ <script src="dialog_core.js"></script>
+ <script src="dialog_events.js"></script>
+ <script src="dialog_methods.js"></script>
+ <script src="dialog_options.js"></script>
+ <script src="dialog_test_helpers.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Dialog Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+ <div id="dialog1"></div>
+ <div id="dialog2"></div>
+ <div id="form-dialog" title="Profile Information">
+ <!-- create a spacer to ensure there's enough space to scroll -->
+ <div style="height: 250px;">...</div>
+ <fieldset>
+ <legend>Please share some personal information</legend>
+ <label for="favorite-animal">Your favorite animal</label><input id="favorite-animal">
+ <label for="favorite-color">Your favorite color</label><input id="favorite-color">
+ </fieldset>
+ <div role="group" aria-describedby="section2">
+ <p id="section2">Some more (optional) information</p>
+ <label for="favorite-food">Favorite food</label><input id="favorite-food">
+ </div>
+ </div>
+ <div class="wrap" id="wrap1"></div>
+ <div class="wrap" id="wrap2"></div>
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_common.js b/apps/it/static/js/ui/tests/unit/dialog/dialog_common.js
new file mode 100644
index 0000000..ea4c917
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_common.js
@@ -0,0 +1,43 @@
+TestHelpers.commonWidgetTests( "dialog", {
+ defaults: {
+ appendTo: "body",
+ autoOpen: true,
+ buttons: [],
+ closeOnEscape: true,
+ closeText: "close",
+ disabled: false,
+ dialogClass: "",
+ draggable: true,
+ height: "auto",
+ hide: null,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 150,
+ minWidth: 150,
+ modal: false,
+ position: {
+ my: "center",
+ at: "center",
+ of: window,
+ collision: "fit",
+ using: $.ui.dialog.prototype.options.position.using
+ },
+ resizable: true,
+ show: null,
+ title: null,
+ width: 300,
+
+ // callbacks
+ beforeClose: null,
+ close: null,
+ create: null,
+ drag: null,
+ dragStart: null,
+ dragStop: null,
+ focus: null,
+ open: null,
+ resize: null,
+ resizeStart: null,
+ resizeStop: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_core.js b/apps/it/static/js/ui/tests/unit/dialog/dialog_core.js
new file mode 100644
index 0000000..e85759d
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_core.js
@@ -0,0 +1,163 @@
+/*
+ * dialog_core.js
+ */
+
+(function($) {
+
+module("dialog: core");
+
+test("title id", function() {
+ expect(1);
+
+ var titleId,
+ element = $("<div></div>").dialog();
+
+ titleId = element.dialog("widget").find(".ui-dialog-title").attr("id");
+ ok( /ui-id-\d+$/.test( titleId ), "auto-numbered title id");
+ element.remove();
+});
+
+test( "ARIA", function() {
+ expect( 4 );
+
+ var element = $( "<div></div>" ).dialog(),
+ wrapper = element.dialog( "widget" );
+ equal( wrapper.attr( "role" ), "dialog", "dialog role" );
+ equal( wrapper.attr( "aria-labelledby" ), wrapper.find( ".ui-dialog-title" ).attr( "id" ) );
+ equal( wrapper.attr( "aria-describedby" ), element.attr( "id" ), "aria-describedby added" );
+ element.remove();
+
+ element = $("<div><div aria-describedby='section2'><p id='section2'>descriotion</p></div></div>").dialog();
+ strictEqual( element.dialog( "widget" ).attr( "aria-describedby" ), undefined, "no aria-describedby added, as already present in markup" );
+ element.remove();
+});
+
+test("widget method", function() {
+ expect( 1 );
+ var dialog = $("<div>").appendTo("#qunit-fixture").dialog();
+ deepEqual(dialog.parent()[0], dialog.dialog("widget")[0]);
+ dialog.remove();
+});
+
+asyncTest( "focus tabbable", function() {
+ expect( 5 );
+ var element,
+ options = {
+ buttons: [{
+ text: "Ok",
+ click: $.noop
+ }]
+ };
+
+ function checkFocus( markup, options, testFn, next ) {
+ element = $( markup ).dialog( options );
+ setTimeout(function() {
+ testFn();
+ element.remove();
+ setTimeout( next );
+ });
+ }
+
+ function step1() {
+ checkFocus( "<div><input><input autofocus></div>", options, function() {
+ equal( document.activeElement, element.find( "input" )[ 1 ],
+ "1. first element inside the dialog matching [autofocus]" );
+ }, step2 );
+ }
+
+ function step2() {
+ checkFocus( "<div><input><input></div>", options, function() {
+ equal( document.activeElement, element.find( "input" )[ 0 ],
+ "2. tabbable element inside the content element" );
+ }, step3 );
+ }
+
+ function step3() {
+ checkFocus( "<div>text</div>", options, function() {
+ equal( document.activeElement,
+ element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" )[ 0 ],
+ "3. tabbable element inside the buttonpane" );
+ }, step4 );
+ }
+
+ function step4() {
+ checkFocus( "<div>text</div>", {}, function() {
+ equal( document.activeElement,
+ element.dialog( "widget" ).find( ".ui-dialog-titlebar .ui-dialog-titlebar-close" )[ 0 ],
+ "4. the close button" );
+ }, step5 );
+ }
+
+ function step5() {
+ element = $( "<div>text</div>" ).dialog({
+ autoOpen: false
+ });
+ element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).hide();
+ element.dialog( "open" );
+ setTimeout(function() {
+ equal( document.activeElement, element.parent()[ 0 ], "5. the dialog itself" );
+ element.remove();
+ start();
+ });
+ }
+
+ step1();
+});
+
+test( "#7960: resizable handles below modal overlays", function() {
+ expect( 1 );
+
+ var resizable = $( "<div>" ).resizable(),
+ dialog = $( "<div>" ).dialog({ modal: true }),
+ resizableZindex = parseInt( resizable.find( ".ui-resizable-handle" ).css( "zIndex" ), 10 ),
+ overlayZindex = parseInt( $( ".ui-widget-overlay" ).css( "zIndex" ), 10 );
+
+ ok( resizableZindex < overlayZindex, "Resizable handles have lower z-index than modal overlay" );
+ dialog.dialog( "destroy" );
+});
+
+asyncTest( "Prevent tabbing out of dialogs", function() {
+ expect( 3 );
+
+ var element = $( "<div><input><input></div>" ).dialog(),
+ inputs = element.find( "input" ),
+ widget = element.dialog( "widget" )[ 0 ];
+
+ function checkTab() {
+ ok( $.contains( widget, document.activeElement ), "Tab key event moved focus within the modal" );
+
+ // check shift tab
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.TAB, shiftKey: true });
+ setTimeout( checkShiftTab );
+ }
+
+ function checkShiftTab() {
+ ok( $.contains( widget, document.activeElement ), "Shift-Tab key event moved focus within the modal" );
+
+ element.remove();
+ setTimeout( start );
+ }
+
+ inputs[1].focus();
+ setTimeout(function() {
+ equal( document.activeElement, inputs[1], "Focus set on second input" );
+ inputs.eq( 1 ).simulate( "keydown", { keyCode: $.ui.keyCode.TAB });
+
+ setTimeout( checkTab );
+ });
+});
+
+asyncTest( "#9048: multiple modal dialogs opened and closed in different order", function() {
+ expect( 1 );
+ $( "#dialog1, #dialog2" ).dialog({ autoOpen: false, modal:true });
+ $( "#dialog1" ).dialog( "open" );
+ $( "#dialog2" ).dialog( "open" );
+ $( "#dialog1" ).dialog( "close" );
+ setTimeout(function() {
+ $( "#dialog2" ).dialog( "close" );
+ $( "#favorite-animal" ).focus();
+ ok( true, "event handlers cleaned up (no errors thrown)" );
+ start();
+ });
+});
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.html b/apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.html
new file mode 100644
index 0000000..1f8bac6
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Dialog Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.dialog" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.position.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.draggable.js",
+ "ui/jquery.ui.resizable.js",
+ "ui/jquery.ui.button.js",
+ "ui/jquery.ui.effect.js",
+ "ui/jquery.ui.effect-blind.js",
+ "ui/jquery.ui.effect-clip.js",
+ "ui/jquery.ui.effect-explode.js",
+ "ui/jquery.ui.dialog.js"
+ ]
+ });
+ </script>
+
+ <script src="dialog_common.js"></script>
+ <script src="dialog_core.js"></script>
+ <script src="dialog_events.js"></script>
+ <script src="dialog_methods.js"></script>
+ <script src="dialog_options.js"></script>
+ <script src="dialog_test_helpers.js"></script>
+ <script src="dialog_deprecated.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Dialog Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+ <div id="dialog1"></div>
+ <div id="dialog2"></div>
+ <div id="form-dialog" title="Profile Information">
+ <fieldset>
+ <legend>Please share some personal information</legend>
+ <label for="favorite-animal">Your favorite animal</label><input id="favorite-animal">
+ <label for="favorite-color">Your favorite color</label><input id="favorite-color">
+ </fieldset>
+ <div role="group" aria-describedby="section2">
+ <p id="section2">Some more (optional) information</p>
+ <label for="favorite-food">Favorite food</label><input id="favorite-food">
+ </div>
+ </div>
+ <div class="wrap" id="wrap1"></div>
+ <div class="wrap" id="wrap2"></div>
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.js b/apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.js
new file mode 100644
index 0000000..ff6284e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_deprecated.js
@@ -0,0 +1,63 @@
+module("dialog (deprecated): position option with string and array");
+
+test( "position, right bottom on window w/array", function() {
+ expect( 2 );
+
+ // dialogs alter the window width and height in FF and IE7
+ // so we collect that information before creating the dialog
+ // Support: FF, IE7
+ var winWidth = $( window ).width(),
+ winHeight = $( window ).height(),
+ element = $("<div></div>").dialog({ position: [ "right", "bottom" ] }),
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+ closeEnough( offset.left, winWidth - dialog.outerWidth() + $( window ).scrollLeft(), 1, "offset left of right bottom on window w/array" );
+ closeEnough( offset.top, winHeight - dialog.outerHeight() + $( window ).scrollTop(), 1, "offset top of right bottom on window w/array" );
+ element.remove();
+});
+
+test( "position, right bottom on window", function() {
+ expect( 2 );
+
+ // dialogs alter the window width and height in FF and IE7
+ // so we collect that information before creating the dialog
+ // Support: FF, IE7
+ var winWidth = $( window ).width(),
+ winHeight = $( window ).height(),
+ element = $("<div></div>").dialog({ position: "right bottom" }),
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+ closeEnough( offset.left, winWidth - dialog.outerWidth() + $( window ).scrollLeft(), 1, "offset left of right bottom on window" );
+ closeEnough( offset.top, winHeight - dialog.outerHeight() + $( window ).scrollTop(), 1, "offset top of right bottom on window" );
+ element.remove();
+});
+
+test("position, offset from top left w/array", function() {
+ expect( 2 );
+ var element = $("<div></div>").dialog({ position: [10, 10] }),
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+ closeEnough(offset.left, 10 + $(window).scrollLeft(), 1);
+ closeEnough(offset.top, 10 + $(window).scrollTop(), 1);
+ element.remove();
+});
+
+test("position, top on window", function() {
+ expect( 2 );
+ var element = $("<div></div>").dialog({ position: "top" }),
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+ closeEnough(offset.left, Math.round($(window).width() / 2 - dialog.outerWidth() / 2) + $(window).scrollLeft(), 1);
+ closeEnough(offset.top, $(window).scrollTop(), 1);
+ element.remove();
+});
+
+test("position, left on window", function() {
+ expect( 2 );
+ var element = $("<div></div>").dialog({ position: "left" }),
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+ closeEnough(offset.left, 0, 1);
+ closeEnough(offset.top, Math.round($(window).height() / 2 - dialog.outerHeight() / 2) + $(window).scrollTop(), 1);
+ element.remove();
+});
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_events.js b/apps/it/static/js/ui/tests/unit/dialog/dialog_events.js
new file mode 100644
index 0000000..7bcd567
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_events.js
@@ -0,0 +1,370 @@
+/*
+ * dialog_events.js
+ */
+(function($) {
+
+module("dialog: events");
+
+test("open", function() {
+ expect(13);
+
+ var element = $("<div></div>");
+ element.dialog({
+ open: function(ev, ui) {
+ ok(element.data("ui-dialog")._isOpen, "interal _isOpen flag is set");
+ ok(true, "autoOpen: true fires open callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogopen", "event type in callback");
+ deepEqual(ui, {}, "ui hash in callback");
+ }
+ });
+ element.remove();
+
+ element = $("<div></div>");
+ element.dialog({
+ autoOpen: false,
+ open: function(ev, ui) {
+ ok(true, ".dialog('open') fires open callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogopen", "event type in callback");
+ deepEqual(ui, {}, "ui hash in callback");
+ }
+ }).bind("dialogopen", function(ev, ui) {
+ ok(element.data("ui-dialog")._isOpen, "interal _isOpen flag is set");
+ ok(true, "dialog('open') fires open event");
+ equal(this, element[0], "context of event");
+ deepEqual(ui, {}, "ui hash in event");
+ });
+ element.dialog("open");
+ element.remove();
+});
+
+
+test( "focus", function() {
+ expect( 5 );
+ var element, other;
+ element = $("#dialog1").dialog({
+ autoOpen: false
+ });
+ other = $("#dialog2").dialog({
+ autoOpen: false
+ });
+
+ element.one( "dialogopen", function() {
+ ok( true, "open, just once" );
+ });
+ element.one( "dialogfocus", function() {
+ ok( true, "focus on open" );
+ });
+ other.dialog( "open" );
+
+ element.one( "dialogfocus", function() {
+ ok( true, "when opening and already open and wasn't on top" );
+ });
+ other.dialog( "open" );
+ element.dialog( "open" );
+
+ element.one( "dialogfocus", function() {
+ ok( true, "when calling moveToTop and wasn't on top" );
+ });
+ other.dialog( "moveToTop" );
+ element.dialog( "moveToTop" );
+
+ element.bind( "dialogfocus", function() {
+ ok( true, "when mousedown anywhere on the dialog and it wasn't on top" );
+ });
+ other.dialog( "moveToTop" );
+ element.trigger( "mousedown" );
+
+ // triggers just once when already on top
+ element.dialog( "open" );
+ element.dialog( "moveToTop" );
+ element.trigger( "mousedown" );
+
+ element.add( other ).remove();
+});
+
+test("dragStart", function() {
+ expect(9);
+
+ var handle,
+ element = $("<div></div>").dialog({
+ dragStart: function(ev, ui) {
+ ok(true, "dragging fires dragStart callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogdragstart", "event type in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.offset !== undefined, "ui.offset in callback");
+ }
+ }).bind("dialogdragstart", function(ev, ui) {
+ ok(true, "dragging fires dialogdragstart event");
+ equal(this, element[0], "context of event");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.offset !== undefined, "ui.offset in callback");
+ });
+
+ handle = $(".ui-dialog-titlebar", element.dialog("widget"));
+ TestHelpers.dialog.drag(element, handle, 50, 50);
+ element.remove();
+});
+
+test("drag", function() {
+ expect(9);
+ var handle,
+ hasDragged = false,
+ element = $("<div></div>").dialog({
+ drag: function(ev, ui) {
+ if (!hasDragged) {
+ ok(true, "dragging fires drag callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogdrag", "event type in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.offset !== undefined, "ui.offset in callback");
+
+ hasDragged = true;
+ }
+ }
+ }).one("dialogdrag", function(ev, ui) {
+ ok(true, "dragging fires dialogdrag event");
+ equal(this, element[0], "context of event");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.offset !== undefined, "ui.offset in callback");
+ });
+
+ handle = $(".ui-dialog-titlebar", element.dialog("widget"));
+ TestHelpers.dialog.drag(element, handle, 50, 50);
+ element.remove();
+});
+
+test("dragStop", function() {
+ expect(9);
+
+ var handle,
+ element = $("<div></div>").dialog({
+ dragStop: function(ev, ui) {
+ ok(true, "dragging fires dragStop callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogdragstop", "event type in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.offset !== undefined, "ui.offset in callback");
+ }
+ }).bind("dialogdragstop", function(ev, ui) {
+ ok(true, "dragging fires dialogdragstop event");
+ equal(this, element[0], "context of event");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.offset !== undefined, "ui.offset in callback");
+ });
+
+ handle = $(".ui-dialog-titlebar", element.dialog("widget"));
+ TestHelpers.dialog.drag(element, handle, 50, 50);
+ element.remove();
+});
+
+test("resizeStart", function() {
+ expect(13);
+
+ var handle,
+ element = $("<div></div>").dialog({
+ resizeStart: function(ev, ui) {
+ ok(true, "resizing fires resizeStart callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogresizestart", "event type in callback");
+ ok(ui.originalPosition !== undefined, "ui.originalPosition in callback");
+ ok(ui.originalSize !== undefined, "ui.originalSize in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.size !== undefined, "ui.size in callback");
+ }
+ }).bind("dialogresizestart", function(ev, ui) {
+ ok(true, "resizing fires dialogresizestart event");
+ equal(this, element[0], "context of event");
+ ok(ui.originalPosition !== undefined, "ui.originalPosition in callback");
+ ok(ui.originalSize !== undefined, "ui.originalSize in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.size !== undefined, "ui.size in callback");
+ });
+
+ handle = $(".ui-resizable-se", element.dialog("widget"));
+ TestHelpers.dialog.drag(element, handle, 50, 50);
+ element.remove();
+});
+
+test("resize", function() {
+ expect(13);
+ var handle,
+ hasResized = false,
+ element = $("<div></div>").dialog({
+ resize: function(ev, ui) {
+ if (!hasResized) {
+ ok(true, "resizing fires resize callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogresize", "event type in callback");
+ ok(ui.originalPosition !== undefined, "ui.originalPosition in callback");
+ ok(ui.originalSize !== undefined, "ui.originalSize in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.size !== undefined, "ui.size in callback");
+
+ hasResized = true;
+ }
+ }
+ }).one("dialogresize", function(ev, ui) {
+ ok(true, "resizing fires dialogresize event");
+ equal(this, element[0], "context of event");
+ ok(ui.originalPosition !== undefined, "ui.originalPosition in callback");
+ ok(ui.originalSize !== undefined, "ui.originalSize in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.size !== undefined, "ui.size in callback");
+ });
+
+ handle = $(".ui-resizable-se", element.dialog("widget"));
+ TestHelpers.dialog.drag(element, handle, 50, 50);
+ element.remove();
+});
+
+test("resizeStop", function() {
+ expect(13);
+
+ var handle,
+ element = $("<div></div>").dialog({
+ resizeStop: function(ev, ui) {
+ ok(true, "resizing fires resizeStop callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogresizestop", "event type in callback");
+ ok(ui.originalPosition !== undefined, "ui.originalPosition in callback");
+ ok(ui.originalSize !== undefined, "ui.originalSize in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.size !== undefined, "ui.size in callback");
+ }
+ }).bind("dialogresizestop", function(ev, ui) {
+ ok(true, "resizing fires dialogresizestop event");
+ equal(this, element[0], "context of event");
+ ok(ui.originalPosition !== undefined, "ui.originalPosition in callback");
+ ok(ui.originalSize !== undefined, "ui.originalSize in callback");
+ ok(ui.position !== undefined, "ui.position in callback");
+ ok(ui.size !== undefined, "ui.size in callback");
+ });
+
+ handle = $(".ui-resizable-se", element.dialog("widget"));
+ TestHelpers.dialog.drag(element, handle, 50, 50);
+ element.remove();
+});
+
+asyncTest("close", function() {
+ expect(14);
+
+ var element = $("<div></div>").dialog({
+ close: function(ev, ui) {
+ ok(true, ".dialog('close') fires close callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogclose", "event type in callback");
+ deepEqual(ui, {}, "ui hash in callback");
+ }
+ }).bind("dialogclose", function(ev, ui) {
+ ok(true, ".dialog('close') fires dialogclose event");
+ equal(this, element[0], "context of event");
+ deepEqual(ui, {}, "ui hash in event");
+ });
+ element.dialog("close");
+ element.remove();
+
+ // Close event with an effect
+ element = $("<div></div>").dialog({
+ hide: 10,
+ close: function(ev, ui) {
+ ok(true, ".dialog('close') fires close callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogclose", "event type in callback");
+ deepEqual(ui, {}, "ui hash in callback");
+ start();
+ }
+ }).bind("dialogclose", function(ev, ui) {
+ ok(true, ".dialog('close') fires dialogclose event");
+ equal(this, element[0], "context of event");
+ deepEqual(ui, {}, "ui hash in event");
+ });
+ element.dialog("close");
+});
+
+test("beforeClose", function() {
+ expect(14);
+
+ var element = $("<div></div>").dialog({
+ beforeClose: function(ev, ui) {
+ ok(true, ".dialog('close') fires beforeClose callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogbeforeclose", "event type in callback");
+ deepEqual(ui, {}, "ui hash in callback");
+ return false;
+ }
+ });
+
+ element.dialog("close");
+ ok( element.dialog("widget").is(":visible"), "beforeClose callback should prevent dialog from closing");
+ element.remove();
+
+ element = $("<div></div>").dialog();
+ element.dialog("option", "beforeClose", function(ev, ui) {
+ ok(true, ".dialog('close') fires beforeClose callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.type, "dialogbeforeclose", "event type in callback");
+ deepEqual(ui, {}, "ui hash in callback");
+ return false;
+ });
+ element.dialog("close");
+
+ ok( element.dialog("widget").is(":visible"), "beforeClose callback should prevent dialog from closing");
+ element.remove();
+
+ element = $("<div></div>").dialog().bind("dialogbeforeclose", function(ev, ui) {
+ ok(true, ".dialog('close') triggers dialogbeforeclose event");
+ equal(this, element[0], "context of event");
+ deepEqual(ui, {}, "ui hash in event");
+ return false;
+ });
+ element.dialog("close");
+ ok( element.dialog("widget").is(":visible"), "dialogbeforeclose event should prevent dialog from closing");
+ element.remove();
+});
+
+// #8789 and #8838
+asyncTest("ensure dialog's container doesn't scroll on resize and focus", function() {
+ expect(2);
+
+ var element = $("#dialog1").dialog(),
+ initialScroll = $(window).scrollTop();
+ element.dialog("option", "height", 600);
+ equal($(window).scrollTop(), initialScroll, "scroll hasn't moved after height change");
+ setTimeout( function(){
+ $(".ui-dialog-titlebar-close").simulate("mousedown");
+ equal($(window).scrollTop(), initialScroll, "scroll hasn't moved after focus moved to dialog");
+ element.dialog("destroy");
+ start();
+ }, 500);
+});
+
+test("#5184: isOpen in dialogclose event is true", function() {
+ expect( 3 );
+
+ var element = $( "<div></div>" ).dialog({
+ close: function() {
+ ok( !element.dialog("isOpen"), "dialog is not open during close" );
+ }
+ });
+ ok( element.dialog("isOpen"), "dialog is open after init" );
+ element.dialog( "close" );
+ ok( !element.dialog("isOpen"), "dialog is not open after close" );
+ element.remove();
+});
+
+test("ensure dialog keeps focus when clicking modal overlay", function() {
+ expect( 2 );
+
+ var element = $( "<div></div>" ).dialog({
+ modal: true
+ });
+ ok( $(":focus").closest(".ui-dialog").length, "focus is in dialog" );
+ $(".ui-widget-overlay").simulate("mousedown");
+ ok( $(":focus").closest(".ui-dialog").length, "focus is still in dialog" );
+ element.remove();
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_methods.js b/apps/it/static/js/ui/tests/unit/dialog/dialog_methods.js
new file mode 100644
index 0000000..b9c8cad
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_methods.js
@@ -0,0 +1,252 @@
+/*
+ * dialog_methods.js
+ */
+(function($) {
+
+module("dialog: methods", {
+ teardown: function() {
+ $("body>.ui-dialog").remove();
+ }
+});
+
+test("init", function() {
+ expect(6);
+
+ $("<div></div>").appendTo("body").dialog().remove();
+ ok(true, ".dialog() called on element");
+
+ $([]).dialog().remove();
+ ok(true, ".dialog() called on empty collection");
+
+ $("<div></div>").dialog().remove();
+ ok(true, ".dialog() called on disconnected DOMElement - never connected");
+
+ $("<div></div>").appendTo("body").remove().dialog().remove();
+ ok(true, ".dialog() called on disconnected DOMElement - removed");
+
+ var element = $("<div></div>").dialog();
+ element.dialog("option", "foo");
+ element.remove();
+ ok(true, "arbitrary option getter after init");
+
+ $("<div></div>").dialog().dialog("option", "foo", "bar").remove();
+ ok(true, "arbitrary option setter after init");
+});
+
+test("destroy", function() {
+ expect( 17 );
+
+ var element, element2;
+
+ $( "#dialog1, #form-dialog" ).hide();
+ domEqual( "#dialog1", function() {
+ var dialog = $( "#dialog1" ).dialog().dialog( "destroy" );
+ equal( dialog.parent()[ 0 ], $( "#qunit-fixture" )[ 0 ] );
+ equal( dialog.index(), 0 );
+ });
+ domEqual( "#form-dialog", function() {
+ var dialog = $( "#form-dialog" ).dialog().dialog( "destroy" );
+ equal( dialog.parent()[ 0 ], $( "#qunit-fixture" )[ 0 ] );
+ equal( dialog.index(), 2 );
+ });
+
+ // Ensure dimensions are restored (#8119)
+ $( "#dialog1" ).show().css({
+ width: "400px",
+ minHeight: "100px",
+ height: "200px"
+ });
+ domEqual( "#dialog1", function() {
+ $( "#dialog1" ).dialog().dialog( "destroy" );
+ });
+
+ // Don't throw errors when destroying a never opened modal dialog (#9004)
+ $( "#dialog1" ).dialog({ autoOpen: false, modal: true }).dialog( "destroy" );
+ equal( $( ".ui-widget-overlay" ).length, 0, "overlay does not exist" );
+ equal( $.ui.dialog.overlayInstances, 0, "overlayInstances equals the number of open overlays");
+
+ element = $( "#dialog1" ).dialog({ modal: true }),
+ element2 = $( "#dialog2" ).dialog({ modal: true });
+ equal( $( ".ui-widget-overlay" ).length, 2, "overlays created when dialogs are open" );
+ equal( $.ui.dialog.overlayInstances, 2, "overlayInstances equals the number of open overlays" );
+ element.dialog( "close" );
+ equal( $( ".ui-widget-overlay" ).length, 1, "overlay remains after closing one dialog" );
+ equal( $.ui.dialog.overlayInstances, 1, "overlayInstances equals the number of open overlays" );
+ element.dialog( "destroy" );
+ equal( $( ".ui-widget-overlay" ).length, 1, "overlay remains after destroying one dialog" );
+ equal( $.ui.dialog.overlayInstances, 1, "overlayInstances equals the number of open overlays" );
+ element2.dialog( "destroy" );
+ equal( $( ".ui-widget-overlay" ).length, 0, "overlays removed when all dialogs are destoryed" );
+ equal( $.ui.dialog.overlayInstances, 0, "overlayInstances equals the number of open overlays" );
+});
+
+asyncTest("#9000: Dialog leaves broken event handler after close/destroy in certain cases", function() {
+ expect( 1 );
+ $( "#dialog1" ).dialog({ modal:true }).dialog( "close" ).dialog( "destroy" );
+ setTimeout(function() {
+ $( "#favorite-animal" ).focus();
+ ok( true, "close and destroy modal dialog before its really opened" );
+ start();
+ }, 2 );
+});
+
+test("#4980: Destroy should place element back in original DOM position", function(){
+ expect( 2 );
+ var container = $("<div id='container'><div id='modal'>Content</div></div>"),
+ modal = container.find("#modal");
+ modal.dialog();
+ ok(!$.contains(container[0], modal[0]), "dialog should move modal element to outside container element");
+ modal.dialog("destroy");
+ ok($.contains(container[0], modal[0]), "dialog(destroy) should place element back in original DOM position");
+});
+
+test( "enable/disable disabled", function() {
+ expect( 2 );
+ var element = $( "<div></div>" ).dialog();
+ element.dialog( "disable" );
+ equal(element.dialog( "option", "disabled" ), false, "disable method doesn't do anything" );
+ ok( !element.dialog( "widget" ).hasClass( "ui-dialog-disabled" ), "disable method doesn't add ui-dialog-disabled class" );
+});
+
+test("close", function() {
+ expect( 3 );
+
+ var element,
+ expected = $("<div></div>").dialog(),
+ actual = expected.dialog("close");
+ equal(actual, expected, "close is chainable");
+
+ element = $("<div></div>").dialog();
+ ok(element.dialog("widget").is(":visible") && !element.dialog("widget").is(":hidden"), "dialog visible before close method called");
+ element.dialog("close");
+ ok(element.dialog("widget").is(":hidden") && !element.dialog("widget").is(":visible"), "dialog hidden after close method called");
+});
+
+test("isOpen", function() {
+ expect(4);
+
+ var element = $("<div></div>").dialog();
+ equal(element.dialog("isOpen"), true, "dialog is open after init");
+ element.dialog("close");
+ equal(element.dialog("isOpen"), false, "dialog is closed");
+ element.remove();
+
+ element = $("<div></div>").dialog({autoOpen: false});
+ equal(element.dialog("isOpen"), false, "dialog is closed after init");
+ element.dialog("open");
+ equal(element.dialog("isOpen"), true, "dialog is open");
+ element.remove();
+});
+
+test("moveToTop", function() {
+ expect( 5 );
+ function order() {
+ var actual = $( ".ui-dialog" ).map(function() {
+ return +$( this ).find( ".ui-dialog-content" ).attr( "id" ).replace( /\D+/, "" );
+ }).get().reverse();
+ deepEqual( actual, $.makeArray( arguments ) );
+ }
+ var dialog1, dialog2,
+ focusOn = "dialog1";
+ dialog1 = $( "#dialog1" ).dialog({
+ focus: function() {
+ equal( focusOn, "dialog1" );
+ }
+ });
+ focusOn = "dialog2";
+ dialog2 = $( "#dialog2" ).dialog({
+ focus: function() {
+ equal( focusOn, "dialog2" );
+ }
+ });
+ order( 2, 1 );
+ focusOn = "dialog1";
+ dialog1.dialog( "moveToTop" );
+ order( 1, 2 );
+});
+
+test("open", function() {
+ expect( 3 );
+ var element,
+ expected = $("<div></div>").dialog(),
+ actual = expected.dialog("open");
+ equal(actual, expected, "open is chainable");
+
+ element = $("<div></div>").dialog({ autoOpen: false });
+ ok(element.dialog("widget").is(":hidden") && !element.dialog("widget").is(":visible"), "dialog hidden before open method called");
+ element.dialog("open");
+ ok(element.dialog("widget").is(":visible") && !element.dialog("widget").is(":hidden"), "dialog visible after open method called");
+});
+
+test("#6137: dialog('open') causes form elements to reset on IE7", function() {
+ expect(2);
+
+ var d1 = $("<form><input type='radio' name='radio' id='a' value='a' checked='checked'></input>" +
+ "<input type='radio' name='radio' id='b' value='b'>b</input></form>").appendTo( "body" ).dialog({autoOpen: false});
+
+ d1.find("#b").prop( "checked", true );
+ equal(d1.find("input:checked").val(), "b", "checkbox b is checked");
+
+ d1.dialog("open");
+ equal(d1.find("input:checked").val(), "b", "checkbox b is checked");
+
+ d1.remove();
+});
+
+asyncTest( "#8958: dialog can be opened while opening", function() {
+ expect( 1 );
+
+ var element = $( "<div>" ).dialog({
+ autoOpen: false,
+ modal: true,
+ open: function() {
+ equal( $( ".ui-widget-overlay" ).length, 1 );
+ start();
+ }
+ });
+
+ // Support: IE8
+ // For some reason the #favorite-color input doesn't get focus if we don't
+ // focus the body first, causing the test to hang.
+ $( "body" ).focus();
+
+ $( "#favorite-animal" )
+ // We focus the input to start the test. Once it receives focus, the
+ // dialog will open. Opening the dialog, will cause an element inside
+ // the dialog to gain focus, thus blurring the input.
+ .bind( "focus", function() {
+ element.dialog( "open" );
+ })
+ // When the input blurs, the dialog is in the process of opening. We
+ // try to open the dialog again, to make sure that dialogs properly
+ // handle a call to the open() method during the process of the dialog
+ // being opened.
+ .bind( "blur", function() {
+ element.dialog( "open" );
+ })
+ .focus();
+});
+
+test("#5531: dialog width should be at least minWidth on creation", function () {
+ expect( 4 );
+ var element = $("<div></div>").dialog({
+ width: 200,
+ minWidth: 300
+ });
+
+ equal(element.dialog("option", "width"), 300, "width is minWidth");
+ element.dialog("option", "width", 200);
+ equal(element.dialog("option", "width"), 300, "width unchanged when set to < minWidth");
+ element.dialog("option", "width", 320);
+ equal(element.dialog("option", "width"), 320, "width changed if set to > minWidth");
+ element.remove();
+
+ element = $("<div></div>").dialog({
+ minWidth: 300
+ });
+ ok(element.dialog("option", "width") >= 300, "width is at least 300");
+ element.remove();
+
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_options.js b/apps/it/static/js/ui/tests/unit/dialog/dialog_options.js
new file mode 100644
index 0000000..07c2d68
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_options.js
@@ -0,0 +1,584 @@
+/*
+ * dialog_options.js
+ */
+(function($) {
+
+module("dialog: options");
+
+test( "appendTo", function() {
+ expect( 16 );
+ var detached = $( "<div>" ),
+ element = $( "#dialog1" ).dialog({
+ modal: true
+ });
+ equal( element.dialog( "widget" ).parent()[0], document.body, "defaults to body" );
+ equal( $( ".ui-widget-overlay" ).parent()[0], document.body, "overlay defaults to body" );
+ element.dialog( "destroy" );
+
+ element.dialog({
+ appendTo: ".wrap",
+ modal: true
+ });
+ equal( element.dialog( "widget" ).parent()[0], $( "#wrap1" )[0], "first found element" );
+ equal( $( ".ui-widget-overlay" ).parent()[0], $( "#wrap1" )[0], "overlay first found element" );
+ equal( $( "#wrap2 .ui-dialog" ).length, 0, "only appends to one element" );
+ equal( $( "#wrap2 .ui-widget-overlay" ).length, 0, "overlay only appends to one element" );
+ element.dialog( "destroy" );
+
+ element.dialog({
+ appendTo: null,
+ modal: true
+ });
+ equal( element.dialog( "widget" ).parent()[0], document.body, "null" );
+ equal( $( ".ui-widget-overlay" ).parent()[0], document.body, "overlay null" );
+ element.dialog( "destroy" );
+
+ element.dialog({
+ autoOpen: false,
+ modal: true
+ }).dialog( "option", "appendTo", "#wrap1" ).dialog( "open" );
+ equal( element.dialog( "widget" ).parent()[0], $( "#wrap1" )[0], "modified after init" );
+ equal( $( ".ui-widget-overlay" ).parent()[0], $( "#wrap1" )[0], "overlay modified after init" );
+ element.dialog( "destroy" );
+
+ element.dialog({
+ appendTo: detached,
+ modal: true
+ });
+ equal( element.dialog( "widget" ).parent()[0], detached[0], "detached jQuery object" );
+ equal( detached.find( ".ui-widget-overlay" ).parent()[0], detached[0], "overlay detached jQuery object" );
+ element.dialog( "destroy" );
+
+ element.dialog({
+ appendTo: detached[0],
+ modal: true
+ });
+ equal( element.dialog( "widget" ).parent()[0], detached[0], "detached DOM element" );
+ equal( detached.find( ".ui-widget-overlay" ).parent()[0], detached[0], "overlay detached DOM element" );
+ element.dialog( "destroy" );
+
+ element.dialog({
+ autoOpen: false,
+ modal: true
+ }).dialog( "option", "appendTo", detached );
+ equal( element.dialog( "widget" ).parent()[0], detached[0], "detached DOM element via option()" );
+ equal( detached.find( ".ui-widget-overlay" ).length, 0, "overlay detached DOM element via option()" );
+ element.dialog( "destroy" );
+});
+
+test("autoOpen", function() {
+ expect(2);
+
+ var element = $("<div></div>").dialog({ autoOpen: false });
+ ok( !element.dialog("widget").is(":visible"), ".dialog({ autoOpen: false })");
+ element.remove();
+
+ element = $("<div></div>").dialog({ autoOpen: true });
+ ok( element.dialog("widget").is(":visible"), ".dialog({ autoOpen: true })");
+ element.remove();
+});
+
+test("buttons", function() {
+ expect(21);
+
+ var btn, i, newButtons,
+ buttons = {
+ "Ok": function( ev ) {
+ ok(true, "button click fires callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.target, btn[0], "event target");
+ },
+ "Cancel": function( ev ) {
+ ok(true, "button click fires callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.target, btn[1], "event target");
+ }
+ },
+ element = $("<div></div>").dialog({ buttons: buttons });
+
+ btn = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" );
+ equal(btn.length, 2, "number of buttons");
+
+ i = 0;
+ $.each(buttons, function( key ) {
+ equal(btn.eq(i).text(), key, "text of button " + (i+1));
+ i++;
+ });
+
+ ok(btn.parent().hasClass("ui-dialog-buttonset"), "buttons in container");
+ ok(element.parent().hasClass("ui-dialog-buttons"), "dialog wrapper adds class about having buttons");
+
+ btn.trigger("click");
+
+ newButtons = {
+ "Close": function( ev ) {
+ ok(true, "button click fires callback");
+ equal(this, element[0], "context of callback");
+ equal(ev.target, btn[0], "event target");
+ }
+ };
+
+ deepEqual(element.dialog("option", "buttons"), buttons, ".dialog('option', 'buttons') getter");
+ element.dialog("option", "buttons", newButtons);
+ deepEqual(element.dialog("option", "buttons"), newButtons, ".dialog('option', 'buttons', ...) setter");
+
+ btn = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" );
+ equal(btn.length, 1, "number of buttons after setter");
+ btn.trigger("click");
+
+ i = 0;
+ $.each(newButtons, function( key ) {
+ equal(btn.eq(i).text(), key, "text of button " + (i+1));
+ i += 1;
+ });
+
+ element.dialog("option", "buttons", null);
+ btn = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" );
+ equal(btn.length, 0, "all buttons have been removed");
+ equal(element.find(".ui-dialog-buttonset").length, 0, "buttonset has been removed");
+ equal(element.parent().hasClass("ui-dialog-buttons"), false, "dialog wrapper removes class about having buttons");
+
+ element.remove();
+});
+
+test("buttons - advanced", function() {
+ expect( 7 );
+
+ var buttons,
+ element = $("<div></div>").dialog({
+ buttons: [
+ {
+ text: "a button",
+ "class": "additional-class",
+ id: "my-button-id",
+ click: function() {
+ equal(this, element[0], "correct context");
+ },
+ icons: {
+ primary: "ui-icon-cancel"
+ },
+ showText: false
+ }
+ ]
+ });
+
+ buttons = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" );
+ equal(buttons.length, 1, "correct number of buttons");
+ equal(buttons.attr("id"), "my-button-id", "correct id");
+ equal(buttons.text(), "a button", "correct label");
+ ok(buttons.hasClass("additional-class"), "additional classes added");
+ deepEqual( buttons.button("option", "icons"), { primary: "ui-icon-cancel", secondary: null } );
+ equal( buttons.button( "option", "text" ), false );
+ buttons.click();
+
+ element.remove();
+});
+
+test("#9043: buttons with Array.prototype modification", function() {
+ expect( 1 );
+ Array.prototype.test = $.noop;
+ var element = $( "<div></div>" ).dialog();
+ equal( element.dialog( "widget" ).find( ".ui-dialog-buttonpane" ).length, 0,
+ "no button pane" );
+ element.remove();
+ delete Array.prototype.test;
+});
+
+test("closeOnEscape", function() {
+ expect( 6 );
+ var element = $("<div></div>").dialog({ closeOnEscape: false });
+ ok(true, "closeOnEscape: false");
+ ok(element.dialog("widget").is(":visible") && !element.dialog("widget").is(":hidden"), "dialog is open before ESC");
+ element.simulate("keydown", { keyCode: $.ui.keyCode.ESCAPE })
+ .simulate("keypress", { keyCode: $.ui.keyCode.ESCAPE })
+ .simulate("keyup", { keyCode: $.ui.keyCode.ESCAPE });
+ ok(element.dialog("widget").is(":visible") && !element.dialog("widget").is(":hidden"), "dialog is open after ESC");
+
+ element.remove();
+
+ element = $("<div></div>").dialog({ closeOnEscape: true });
+ ok(true, "closeOnEscape: true");
+ ok(element.dialog("widget").is(":visible") && !element.dialog("widget").is(":hidden"), "dialog is open before ESC");
+ element.simulate("keydown", { keyCode: $.ui.keyCode.ESCAPE })
+ .simulate("keypress", { keyCode: $.ui.keyCode.ESCAPE })
+ .simulate("keyup", { keyCode: $.ui.keyCode.ESCAPE });
+ ok(element.dialog("widget").is(":hidden") && !element.dialog("widget").is(":visible"), "dialog is closed after ESC");
+});
+
+test("closeText", function() {
+ expect(3);
+
+ var element = $("<div></div>").dialog();
+ equal(element.dialog("widget").find(".ui-dialog-titlebar-close span").text(), "close",
+ "default close text");
+ element.remove();
+
+ element = $("<div></div>").dialog({ closeText: "foo" });
+ equal(element.dialog("widget").find(".ui-dialog-titlebar-close span").text(), "foo",
+ "closeText on init");
+ element.remove();
+
+ element = $("<div></div>").dialog().dialog("option", "closeText", "bar");
+ equal(element.dialog("widget").find(".ui-dialog-titlebar-close span").text(), "bar",
+ "closeText via option method");
+ element.remove();
+});
+
+test("dialogClass", function() {
+ expect( 6 );
+
+ var element = $("<div></div>").dialog();
+ equal(element.dialog("widget").is(".foo"), false, "dialogClass not specified. foo class added");
+ element.remove();
+
+ element = $("<div></div>").dialog({ dialogClass: "foo" });
+ equal(element.dialog("widget").is(".foo"), true, "dialogClass in init. foo class added");
+ element.dialog( "option", "dialogClass", "foobar" );
+ equal( element.dialog("widget").is(".foo"), false, "dialogClass changed, previous one was removed" );
+ equal( element.dialog("widget").is(".foobar"), true, "dialogClass changed, new one was added" );
+ element.remove();
+
+ element = $("<div></div>").dialog({ dialogClass: "foo bar" });
+ equal(element.dialog("widget").is(".foo"), true, "dialogClass in init, two classes. foo class added");
+ equal(element.dialog("widget").is(".bar"), true, "dialogClass in init, two classes. bar class added");
+ element.remove();
+});
+
+test("draggable", function() {
+ expect(4);
+
+ var element = $("<div></div>").dialog({ draggable: false });
+
+ TestHelpers.dialog.testDrag(element, 50, -50, 0, 0);
+ element.dialog("option", "draggable", true);
+ TestHelpers.dialog.testDrag(element, 50, -50, 50, -50);
+ element.remove();
+
+ element = $("<div></div>").dialog({ draggable: true });
+ TestHelpers.dialog.testDrag(element, 50, -50, 50, -50);
+ element.dialog("option", "draggable", false);
+ TestHelpers.dialog.testDrag(element, 50, -50, 0, 0);
+ element.remove();
+});
+
+test("height", function() {
+ expect(4);
+
+ var element = $("<div></div>").dialog();
+ equal(element.dialog("widget").outerHeight(), 150, "default height");
+ element.remove();
+
+ element = $("<div></div>").dialog({ height: 237 });
+ equal(element.dialog("widget").outerHeight(), 237, "explicit height");
+ element.remove();
+
+ element = $("<div></div>").dialog();
+ element.dialog("option", "height", 238);
+ equal(element.dialog("widget").outerHeight(), 238, "explicit height set after init");
+ element.remove();
+
+ element = $("<div></div>").css("padding", "20px")
+ .dialog({ height: 240 });
+ equal(element.dialog("widget").outerHeight(), 240, "explicit height with padding");
+ element.remove();
+});
+
+asyncTest( "hide, #5860 - don't leave effects wrapper behind", function() {
+ expect( 1 );
+ $( "#dialog1" ).dialog({ hide: "clip" }).dialog( "close" ).dialog( "destroy" );
+ setTimeout(function() {
+ equal( $( ".ui-effects-wrapper" ).length, 0 );
+ start();
+ }, 500);
+});
+
+test("maxHeight", function() {
+ expect(3);
+
+ var element = $("<div></div>").dialog({ maxHeight: 200 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-s", 1000, 1000);
+ closeEnough(element.dialog("widget").height(), 200, 1, "maxHeight");
+ element.remove();
+
+ element = $("<div></div>").dialog({ maxHeight: 200 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-n", -1000, -1000);
+ closeEnough(element.dialog("widget").height(), 200, 1, "maxHeight");
+ element.remove();
+
+ element = $("<div></div>").dialog({ maxHeight: 200 }).dialog("option", "maxHeight", 300);
+ TestHelpers.dialog.drag(element, ".ui-resizable-s", 1000, 1000);
+ closeEnough(element.dialog("widget").height(), 300, 1, "maxHeight");
+ element.remove();
+});
+
+test("maxWidth", function() {
+ expect(3);
+
+ var element = $("<div></div>").dialog({ maxWidth: 200 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-e", 1000, 1000);
+ closeEnough(element.dialog("widget").width(), 200, 1, "maxWidth");
+ element.remove();
+
+ element = $("<div></div>").dialog({ maxWidth: 200 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-w", -1000, -1000);
+ closeEnough(element.dialog("widget").width(), 200, 1, "maxWidth");
+ element.remove();
+
+ element = $("<div></div>").dialog({ maxWidth: 200 }).dialog("option", "maxWidth", 300);
+ TestHelpers.dialog.drag(element, ".ui-resizable-w", -1000, -1000);
+ closeEnough(element.dialog("widget").width(), 300, 1, "maxWidth");
+ element.remove();
+});
+
+test("minHeight", function() {
+ expect(3);
+
+ var element = $("<div></div>").dialog({ minHeight: 10 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-s", -1000, -1000);
+ closeEnough(element.dialog("widget").height(), 10, 1, "minHeight");
+ element.remove();
+
+ element = $("<div></div>").dialog({ minHeight: 10 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-n", 1000, 1000);
+ closeEnough(element.dialog("widget").height(), 10, 1, "minHeight");
+ element.remove();
+
+ element = $("<div></div>").dialog({ minHeight: 10 }).dialog("option", "minHeight", 30);
+ TestHelpers.dialog.drag(element, ".ui-resizable-n", 1000, 1000);
+ closeEnough(element.dialog("widget").height(), 30, 1, "minHeight");
+ element.remove();
+});
+
+test("minWidth", function() {
+ expect(3);
+
+ var element = $("<div></div>").dialog({ minWidth: 10 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-e", -1000, -1000);
+ closeEnough(element.dialog("widget").width(), 10, 1, "minWidth");
+ element.remove();
+
+ element = $("<div></div>").dialog({ minWidth: 10 });
+ TestHelpers.dialog.drag(element, ".ui-resizable-w", 1000, 1000);
+ closeEnough(element.dialog("widget").width(), 10, 1, "minWidth");
+ element.remove();
+
+ element = $("<div></div>").dialog({ minWidth: 30 }).dialog("option", "minWidth", 30);
+ TestHelpers.dialog.drag(element, ".ui-resizable-w", 1000, 1000);
+ closeEnough(element.dialog("widget").width(), 30, 1, "minWidth");
+ element.remove();
+});
+
+test( "position, default center on window", function() {
+ expect( 2 );
+
+ // dialogs alter the window width and height in FF and IE7
+ // so we collect that information before creating the dialog
+ // Support: FF, IE7
+ var winWidth = $( window ).width(),
+ winHeight = $( window ).height(),
+ element = $("<div></div>").dialog(),
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+ closeEnough( offset.left, Math.round( winWidth / 2 - dialog.outerWidth() / 2 ) + $( window ).scrollLeft(), 1, "dialog left position of center on window on initilization" );
+ closeEnough( offset.top, Math.round( winHeight / 2 - dialog.outerHeight() / 2 ) + $( window ).scrollTop(), 1, "dialog top position of center on window on initilization" );
+ element.remove();
+});
+
+test( "position, right bottom at right bottom via ui.position args", function() {
+ expect( 2 );
+
+ // dialogs alter the window width and height in FF and IE7
+ // so we collect that information before creating the dialog
+ // Support: FF, IE7
+ var winWidth = $( window ).width(),
+ winHeight = $( window ).height(),
+ element = $("<div></div>").dialog({
+ position: {
+ my: "right bottom",
+ at: "right bottom"
+ }
+ }),
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+
+ closeEnough( offset.left, winWidth - dialog.outerWidth() + $( window ).scrollLeft(), 1, "dialog left position of right bottom at right bottom on initilization" );
+ closeEnough( offset.top, winHeight - dialog.outerHeight() + $( window ).scrollTop(), 1, "dialog top position of right bottom at right bottom on initilization" );
+ element.remove();
+});
+
+test( "position, at another element", function() {
+ expect( 4 );
+ var parent = $("<div></div>").css({
+ position: "absolute",
+ top: 400,
+ left: 600,
+ height: 10,
+ width: 10
+ }).appendTo("body"),
+
+ element = $("<div></div>").dialog({
+ position: {
+ my: "left top",
+ at: "left top",
+ of: parent,
+ collision: "none"
+ }
+ }),
+
+ dialog = element.dialog("widget"),
+ offset = dialog.offset();
+
+ closeEnough( offset.left, 600, 1, "dialog left position at another element on initilization" );
+ closeEnough( offset.top, 400, 1, "dialog top position at another element on initilization" );
+
+ element.dialog("option", "position", {
+ my: "left top",
+ at: "right bottom",
+ of: parent,
+ collision: "none"
+ });
+
+ offset = dialog.offset();
+
+ closeEnough( offset.left, 610, 1, "dialog left position at another element via setting option" );
+ closeEnough( offset.top, 410, 1, "dialog top position at another element via setting option" );
+
+ element.remove();
+ parent.remove();
+});
+
+test("resizable", function() {
+ expect(4);
+
+ var element = $("<div></div>").dialog();
+ TestHelpers.dialog.shouldResize(element, 50, 50, "[default]");
+ element.dialog("option", "resizable", false);
+ TestHelpers.dialog.shouldResize(element, 0, 0, "disabled after init");
+ element.remove();
+
+ element = $("<div></div>").dialog({ resizable: false });
+ TestHelpers.dialog.shouldResize(element, 0, 0, "disabled in init options");
+ element.dialog("option", "resizable", true);
+ TestHelpers.dialog.shouldResize(element, 50, 50, "enabled after init");
+ element.remove();
+});
+
+test( "title", function() {
+ expect( 11 );
+
+ function titleText() {
+ return element.dialog("widget").find( ".ui-dialog-title" ).html();
+ }
+
+ var element = $( "<div></div>" ).dialog();
+ // some browsers return a non-breaking space and some return "&nbsp;"
+ // so we generate a non-breaking space for comparison
+ equal( titleText(), $( "<span>&#160;</span>" ).html(), "[default]" );
+ equal( element.dialog( "option", "title" ), null, "option not changed" );
+ element.remove();
+
+ element = $( "<div title='foo'>" ).dialog();
+ equal( titleText(), "foo", "title in element attribute" );
+ equal( element.dialog( "option", "title"), "foo", "option updated from attribute" );
+ element.remove();
+
+ element = $( "<div></div>" ).dialog({ title: "foo" });
+ equal( titleText(), "foo", "title in init options" );
+ equal( element.dialog("option", "title"), "foo", "opiton set from options hash" );
+ element.remove();
+
+ element = $( "<div title='foo'>" ).dialog({ title: "bar" });
+ equal( titleText(), "bar", "title in init options should override title in element attribute" );
+ equal( element.dialog("option", "title"), "bar", "opiton set from options hash" );
+ element.remove();
+
+ element = $( "<div></div>" ).dialog().dialog( "option", "title", "foo" );
+ equal( titleText(), "foo", "title after init" );
+ element.remove();
+
+ // make sure attroperties are properly ignored - #5742 - .attr() might return a DOMElement
+ element = $( "<form><input name='title'></form>" ).dialog();
+ // some browsers return a non-breaking space and some return "&nbsp;"
+ // so we get the text to normalize to the actual non-breaking space
+ equal( titleText(), $( "<span>&#160;</span>" ).html(), "[default]" );
+ equal( element.dialog( "option", "title" ), null, "option not changed" );
+ element.remove();
+});
+
+test("width", function() {
+ expect(3);
+
+ var element = $("<div></div>").dialog();
+ closeEnough(element.dialog("widget").width(), 300, 1, "default width");
+ element.remove();
+
+ element = $("<div></div>").dialog({width: 437 });
+ closeEnough(element.dialog("widget").width(), 437, 1, "explicit width");
+ element.dialog("option", "width", 438);
+ closeEnough(element.dialog("widget").width(), 438, 1, "explicit width after init");
+ element.remove();
+});
+
+test("#4826: setting resizable false toggles resizable on dialog", function() {
+ expect(6);
+ var i,
+ element = $("<div></div>").dialog({ resizable: false });
+
+ TestHelpers.dialog.shouldResize(element, 0, 0, "[default]");
+ for (i=0; i<2; i++) {
+ element.dialog("close").dialog("open");
+ TestHelpers.dialog.shouldResize(element, 0, 0, "initialized with resizable false toggle ("+ (i+1) +")");
+ }
+ element.remove();
+
+ element = $("<div></div>").dialog({ resizable: true });
+ TestHelpers.dialog.shouldResize(element, 50, 50, "[default]");
+ for (i=0; i<2; i++) {
+ element.dialog("close").dialog("option", "resizable", false).dialog("open");
+ TestHelpers.dialog.shouldResize(element, 0, 0, "set option resizable false toggle ("+ (i+1) +")");
+ }
+ element.remove();
+
+});
+
+asyncTest( "#8051 - 'Explode' dialog animation causes crash in IE 6, 7 and 8", function() {
+ expect( 1 );
+ var element = $( "<div></div>" ).dialog({
+ show: "explode",
+ focus: function() {
+ ok( true, "dialog opened with animation" );
+ element.remove();
+ start();
+ }
+ });
+});
+
+asyncTest( "#4421 - Focus lost from dialog which uses show-effect", function() {
+ expect( 1 );
+ var element = $( "<div></div>" ).dialog({
+ show: "blind",
+ focus: function() {
+ equal( element.dialog( "widget" ).find( ":focus" ).length, 1, "dialog maintains focus" );
+ element.remove();
+ start();
+ }
+ });
+});
+
+asyncTest( "Open followed by close during show effect", function() {
+ expect( 1 );
+ var element = $( "<div></div>" ).dialog({
+ show: "blind",
+ close: function() {
+ ok( true, "dialog closed properly during animation" );
+ element.remove();
+ start();
+ }
+ });
+
+ setTimeout( function() {
+ element.dialog("close");
+ }, 100 );
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/dialog/dialog_test_helpers.js b/apps/it/static/js/ui/tests/unit/dialog/dialog_test_helpers.js
new file mode 100644
index 0000000..64e8dbf
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/dialog/dialog_test_helpers.js
@@ -0,0 +1,44 @@
+TestHelpers.dialog = {
+ drag: function(element, handle, dx, dy) {
+ var d = element.dialog("widget");
+ //this mouseover is to work around a limitation in resizable
+ //TODO: fix resizable so handle doesn't require mouseover in order to be used
+ $( handle, d ).simulate("mouseover").simulate( "drag", {
+ dx: dx,
+ dy: dy
+ });
+ },
+ testDrag: function(element, dx, dy, expectedDX, expectedDY, msg) {
+ var actualDX, actualDY, offsetAfter,
+ d = element.dialog("widget"),
+ handle = $(".ui-dialog-titlebar", d),
+ offsetBefore = d.offset();
+
+ TestHelpers.dialog.drag(element, handle, dx, dy);
+
+ offsetAfter = d.offset();
+
+ msg = msg ? msg + "." : "";
+
+ actualDX = offsetAfter.left - offsetBefore.left;
+ actualDY = offsetAfter.top - offsetBefore.top;
+ ok( expectedDX - actualDX <= 1 && expectedDY - actualDY <= 1, "dragged[" + expectedDX + ", " + expectedDY + "] " + msg);
+ },
+ shouldResize: function(element, dw, dh, msg) {
+ var heightAfter, widthAfter, actual, expected,
+ d = element.dialog("widget"),
+ handle = $(".ui-resizable-se", d),
+ heightBefore = d.height(),
+ widthBefore = d.width();
+
+ TestHelpers.dialog.drag(element, handle, 50, 50);
+
+ heightAfter = d.height();
+ widthAfter = d.width();
+
+ msg = msg ? msg + "." : "";
+ actual = { width: widthAfter, height: heightAfter },
+ expected = { width: widthBefore + dw, height: heightBefore + dh };
+ deepEqual(actual, expected, "resized[" + 50 + ", " + 50 + "] " + msg);
+ }
+};
diff --git a/apps/it/static/js/ui/tests/unit/draggable/all.html b/apps/it/static/js/ui/tests/unit/draggable/all.html
new file mode 100644
index 0000000..7c43866
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Draggable Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "draggable" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Draggable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/draggable/draggable.html b/apps/it/static/js/ui/tests/unit/draggable/draggable.html
new file mode 100644
index 0000000..3d1d332
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/draggable.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Draggable Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+
+ <style>
+ /* See #9077 */
+ #draggable3, #draggable4 { z-index: 100; }
+ </style>
+
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.resizable.js",
+ "ui/jquery.ui.draggable.js",
+ "ui/jquery.ui.droppable.js"
+ ]
+ });
+ </script>
+
+ <script src="draggable_common.js"></script>
+ <script src="draggable_core.js"></script>
+ <script src="draggable_events.js"></script>
+ <script src="draggable_methods.js"></script>
+ <script src="draggable_options.js"></script>
+ <script src="draggable_test_helpers.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Draggable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+ <div id="main"></div>
+ <div id="draggable1" style="background: green; width: 200px; height: 100px;">Relative</div>
+ <div id="draggable2" style="background: green; width: 200px; height: 100px; position: absolute; top: 10px; left: 10px;"><span><em>Absolute</em></span></div>
+ <div id="droppable" style="background: green; width: 200px; height: 100px; position: absolute; top: 110px; left: 110px;"><span>Absolute</span></div>
+ <div style="width: 1px; height: 1000px;"></div>
+ <div style="position: absolute; width: 1px; height: 2000px;"></div>
+</div>
+
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/draggable/draggable_common.js b/apps/it/static/js/ui/tests/unit/draggable/draggable_common.js
new file mode 100644
index 0000000..5abd09e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/draggable_common.js
@@ -0,0 +1,40 @@
+TestHelpers.commonWidgetTests( "draggable", {
+ defaults: {
+ appendTo: "parent",
+ axis: false,
+ cancel: "input,textarea,button,select,option",
+ connectToSortable: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ disabled: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ opacity: false,
+ refreshPositions: false,
+ revert: false,
+ revertDuration: 500,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ snap: false,
+ snapMode: "both",
+ snapTolerance: 20,
+ stack: false,
+ zIndex: false,
+
+ //todo: remove the following option checks when interactions are rewritten:
+ addClasses: true,
+ delay: 0,
+ distance: 1,
+ iframeFix: false,
+
+ // callbacks
+ create: null,
+ drag: null,
+ start: null,
+ stop: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/draggable/draggable_core.js b/apps/it/static/js/ui/tests/unit/draggable/draggable_core.js
new file mode 100644
index 0000000..7b1588a
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/draggable_core.js
@@ -0,0 +1,168 @@
+/*
+ * draggable_core.js
+ */
+
+(function( $ ) {
+
+module( "draggable: core" );
+
+test( "element types", function() {
+ var typeNames = (
+ "p,h1,h2,h3,h4,h5,h6,blockquote,ol,ul,dl,div,form" +
+ ",table,fieldset,address,ins,del,em,strong,q,cite,dfn,abbr" +
+ ",acronym,code,samp,kbd,var,img,hr" +
+ ",input,button,label,select,iframe"
+ ).split(",");
+
+ expect( typeNames.length * 2 );
+
+ $.each( typeNames, function( i ) {
+ var offsetBefore, offsetAfter,
+ typeName = typeNames[ i ],
+ el = $( document.createElement( typeName ) ).appendTo("#qunit-fixture");
+
+ if ( typeName === "table" ) {
+ el.append("<tr><td>content</td></tr>");
+ }
+
+ el.draggable({ cancel: "" });
+ offsetBefore = el.offset();
+ el.simulate( "drag", {
+ dx: 50,
+ dy: 50
+ });
+ offsetAfter = el.offset();
+
+ // Support: FF, Chrome, and IE9,
+ // there are some rounding errors in so we can't say equal, we have to settle for close enough
+ closeEnough( offsetBefore.left, offsetAfter.left - 50, 1, "dragged[50, 50] " + "<" + typeName + ">" );
+ closeEnough( offsetBefore.top, offsetAfter.top - 50, 1, "dragged[50, 50] " + "<" + typeName + ">" );
+ el.draggable("destroy");
+ el.remove();
+ });
+});
+
+test( "No options, relative", function() {
+ expect( 1 );
+ TestHelpers.draggable.shouldMove( $( "#draggable1" ).draggable() );
+});
+
+test( "No options, absolute", function() {
+ expect( 1 );
+ TestHelpers.draggable.shouldMove( $( "#draggable2" ).draggable() );
+});
+
+test( "resizable handle with complex markup (#8756 / #8757)", function() {
+ expect( 2 );
+
+ $( "#draggable1" )
+ .append(
+ $("<div>")
+ .addClass("ui-resizable-handle ui-resizable-w")
+ .append( $("<div>") )
+ );
+
+ var handle = $(".ui-resizable-w div"),
+ target = $( "#draggable1" ).draggable().resizable({ handles: "all" });
+
+ // todo: fix resizable so it doesn't require a mouseover
+ handle.simulate("mouseover").simulate( "drag", { dx: -50 } );
+ equal( target.width(), 250, "compare width" );
+
+ // todo: fix resizable so it doesn't require a mouseover
+ handle.simulate("mouseover").simulate( "drag", { dx: 50 } );
+ equal( target.width(), 200, "compare width" );
+});
+
+test( "#8269: Removing draggable element on drop", function() {
+ expect( 1 );
+
+ var element = $( "#draggable1" ).wrap( "<div id='wrapper' />" ).draggable(),
+ dropOffset = $( "#droppable" ).offset();
+
+ $( "#droppable" ).droppable({
+ drop: function() {
+ $( "#wrapper" ).remove();
+ ok( true, "element removed from DOM on drop" );
+ }
+ });
+
+ // Support: Opera 12.10, Safari 5.1, jQuery <1.8
+ if ( TestHelpers.draggable.unreliableContains ) {
+ ok( true, "Opera <12.14 and Safari <6.0 report wrong values for $.contains in jQuery < 1.8" );
+ ok( true, "Opera <12.14 and Safari <6.0 report wrong values for $.contains in jQuery < 1.8" );
+ } else {
+ element.simulate( "drag", {
+ handle: "corner",
+ x: dropOffset.left,
+ y: dropOffset.top
+ });
+ }
+});
+
+test( "#6258: not following mouse when scrolled and using overflow-y: scroll", function() {
+ expect( 2 );
+
+ var element = $( "#draggable1" ).draggable({
+ stop: function( event, ui ) {
+ equal( ui.position.left, 1, "left position is correct despite overflow on HTML" );
+ equal( ui.position.top, 1, "top position is correct despite overflow on HTML" );
+ $( "html" )
+ .css( "overflow-y", oldOverflowY )
+ .css( "overflow-x", oldOverflowX )
+ .scrollTop( 0 )
+ .scrollLeft( 0 );
+ }
+ }),
+ contentToForceScroll = $( "<div>" ).css({
+ height: "10000px",
+ width: "10000px"
+ }),
+ oldOverflowY = $( "html" ).css( "overflow-y" ),
+ oldOverflowX = $( "html" ).css( "overflow-x" );
+
+ contentToForceScroll.appendTo( "#qunit-fixture" );
+ $( "html" )
+ .css( "overflow-y", "scroll" )
+ .css( "overflow-x", "scroll" )
+ .scrollTop( 300 )
+ .scrollLeft( 300 );
+
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1,
+ moves: 1
+ });
+});
+
+test( "#5009: scroll not working with parent's position fixed", function() {
+ expect( 2 );
+
+ var startValue = 300,
+ element = $( "#draggable1" ).wrap( "<div id='wrapper' />" ).draggable({
+ drag: function() {
+ startValue += 100;
+ $( document ).scrollTop( startValue ).scrollLeft( startValue );
+ },
+ stop: function( event, ui ) {
+ equal( ui.position.left, 10, "left position is correct when parent position is fixed" );
+ equal( ui.position.top, 10, "top position is correct when parent position is fixed" );
+ $( document ).scrollTop( 0 ).scrollLeft( 0 );
+ }
+ }),
+ contentToForceScroll = $( "<div>" ).css({
+ height: "20000px",
+ width: "20000px"
+ });
+
+ $( "#qunit-fixture" ).append( contentToForceScroll );
+ $( "#wrapper" ).css( "position", "fixed" );
+
+ element.simulate( "drag", {
+ dx: 10,
+ dy: 10,
+ moves: 3
+ });
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/draggable/draggable_events.js b/apps/it/static/js/ui/tests/unit/draggable/draggable_events.js
new file mode 100644
index 0000000..199561b
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/draggable_events.js
@@ -0,0 +1,125 @@
+/*
+ * draggable_events.js
+ */
+(function( $ ) {
+
+var element;
+
+module( "draggable: events", {
+ setup: function() {
+ element = $("<div>").appendTo("#qunit-fixture");
+ },
+ teardown: function() {
+ element.draggable("destroy");
+ }
+});
+
+test( "callbacks occurrence count", function() {
+ expect( 3 );
+
+ var start = 0,
+ stop = 0,
+ dragc = 0;
+
+ element.draggable({
+ start: function() {
+ start++;
+ },
+ drag: function() {
+ dragc++;
+ },
+ stop: function() {
+ stop++;
+ }
+ });
+
+ element.simulate( "drag", {
+ dx: 10,
+ dy: 10
+ });
+
+ equal( start, 1, "start callback should happen exactly once" );
+ equal( dragc, 3, "drag callback should happen exactly once per mousemove" );
+ equal( stop, 1, "stop callback should happen exactly once" );
+});
+
+test( "stopping the start callback", function() {
+ expect( 3 );
+
+ var start = 0,
+ stop = 0,
+ dragc = 0;
+
+ element.draggable({
+ start: function() {
+ start++;
+ return false;
+ },
+ drag: function() {
+ dragc++;
+ },
+ stop: function() {
+ stop++;
+ }
+ });
+
+ element.simulate( "drag", {
+ dx: 10,
+ dy: 10
+ });
+
+ equal( start, 1, "start callback should happen exactly once" );
+ equal( dragc, 0, "drag callback should not happen at all" );
+ equal( stop, 0, "stop callback should not happen if there wasnt even a start" );
+});
+
+test( "stopping the drag callback", function() {
+ expect( 2 );
+
+ var start = 0,
+ stop = 0,
+ dragc = 0;
+
+ element.draggable({
+ start: function() {
+ start++;
+ },
+ drag: function() {
+ dragc++;
+ return false;
+ },
+ stop: function() {
+ stop++;
+ }
+ });
+
+ element.simulate( "drag", {
+ dx: 10,
+ dy: 10
+ });
+
+ equal( start, 1, "start callback should happen exactly once" );
+ equal( stop, 1, "stop callback should happen, as we need to actively stop the drag" );
+});
+
+test( "stopping the stop callback", function() {
+ expect( 1 );
+
+ element.draggable({
+ helper: "clone",
+ stop: function() {
+ return false;
+ }
+ });
+
+ element.simulate( "drag", {
+ dx: 10,
+ dy: 10
+ });
+
+ ok( element.data("ui-draggable").helper, "the clone should not be deleted if the stop callback is stopped" );
+
+
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/draggable/draggable_methods.js b/apps/it/static/js/ui/tests/unit/draggable/draggable_methods.js
new file mode 100644
index 0000000..901c261
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/draggable_methods.js
@@ -0,0 +1,99 @@
+/*
+ * draggable_methods.js
+ */
+(function( $ ) {
+
+var element;
+
+module( "draggable: methods", {
+ setup: function() {
+ element = $("<div style='background: green; width: 200px; height: 100px; position: absolute; top: 10px; left: 10px;'><span>Absolute</span></div>").appendTo("#qunit-fixture");
+ },
+ teardown: function() {
+ element.remove();
+ }
+});
+
+test( "init", function() {
+ expect( 5 );
+
+ element.draggable();
+ ok( true, ".draggable() called on element" );
+
+ $([]).draggable();
+ ok( true, ".draggable() called on empty collection" );
+
+ $("<div></div>").draggable();
+ ok( true, ".draggable() called on disconnected DOMElement" );
+
+ element.draggable( "option", "foo" );
+ ok( true, "arbitrary option getter after init" );
+
+ element.draggable( "option", "foo", "bar" );
+ ok( true, "arbitrary option setter after init" );
+});
+
+test( "destroy", function() {
+ expect( 4 );
+
+ element.draggable().draggable("destroy");
+ ok( true, ".draggable('destroy') called on element" );
+
+ $([]).draggable().draggable("destroy");
+ ok( true, ".draggable('destroy') called on empty collection" );
+
+ element.draggable().draggable("destroy");
+ ok( true, ".draggable('destroy') called on disconnected DOMElement" );
+
+ var expected = element.draggable(),
+ actual = expected.draggable("destroy");
+ equal( actual, expected, "destroy is chainable" );
+});
+
+test( "enable", function() {
+ expect( 7 );
+
+ element.draggable({ disabled: true });
+ TestHelpers.draggable.shouldNotMove( element, ".draggable({ disabled: true })" );
+
+ element.draggable("enable");
+ TestHelpers.draggable.shouldMove( element, ".draggable('enable')" );
+ equal( element.draggable( "option", "disabled" ), false, "disabled option getter" );
+
+ element.draggable("destroy");
+ element.draggable({ disabled: true });
+ TestHelpers.draggable.shouldNotMove( element, ".draggable({ disabled: true })" );
+
+ element.draggable( "option", "disabled", false );
+ equal(element.draggable( "option", "disabled" ), false, "disabled option setter" );
+ TestHelpers.draggable.shouldMove( element, ".draggable('option', 'disabled', false)" );
+
+ var expected = element.draggable(),
+ actual = expected.draggable("enable");
+ equal( actual, expected, "enable is chainable" );
+});
+
+test( "disable", function() {
+ expect( 7 );
+
+ element = $("#draggable2").draggable({ disabled: false });
+ TestHelpers.draggable.shouldMove( element, ".draggable({ disabled: false })" );
+
+ element.draggable("disable");
+ TestHelpers.draggable.shouldNotMove( element, ".draggable('disable')" );
+ equal( element.draggable( "option", "disabled" ), true, "disabled option getter" );
+
+ element.draggable("destroy");
+ element.draggable({ disabled: false });
+ TestHelpers.draggable.shouldMove( element, ".draggable({ disabled: false })" );
+
+ element.draggable( "option", "disabled", true );
+ equal( element.draggable( "option", "disabled" ), true, "disabled option setter" );
+ TestHelpers.draggable.shouldNotMove( element, ".draggable('option', 'disabled', true)" );
+
+ var expected = element.draggable(),
+ actual = expected.draggable("disable");
+ equal( actual, expected, "disable is chainable" );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/draggable/draggable_options.js b/apps/it/static/js/ui/tests/unit/draggable/draggable_options.js
new file mode 100644
index 0000000..635d318
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/draggable_options.js
@@ -0,0 +1,1404 @@
+(function( $ ) {
+
+module( "draggable: options" );
+
+// TODO: This doesn't actually test whether append happened, possibly remove
+test( "{ appendTo: 'parent' }, default, no clone", function() {
+ expect( 2 );
+ var element = $( "#draggable2" ).draggable({ appendTo: "parent" });
+ TestHelpers.draggable.shouldMove( element );
+
+ element = $( "#draggable1" ).draggable({ appendTo: "parent" });
+ TestHelpers.draggable.shouldMove( element );
+});
+
+// TODO: This doesn't actually test whether append happened, possibly remove
+test( "{ appendTo: Element }, no clone", function() {
+ expect( 2 );
+ var element = $( "#draggable2" ).draggable({ appendTo: $( "#draggable2" ).parent()[ 0 ] });
+
+ TestHelpers.draggable.shouldMove( element );
+
+ element = $( "#draggable1" ).draggable({ appendTo: $( "#draggable2" ).parent()[ 0 ] });
+ TestHelpers.draggable.shouldMove( element );
+});
+
+// TODO: This doesn't actually test whether append happened, possibly remove
+test( "{ appendTo: Selector }, no clone", function() {
+ expect( 2 );
+ var element = $( "#draggable2" ).draggable({ appendTo: "#main" });
+ TestHelpers.draggable.shouldMove( element );
+
+ element = $( "#draggable1" ).draggable({ appendTo: "#main" });
+ TestHelpers.draggable.shouldMove( element );
+});
+
+test( "{ appendTo: 'parent' }, default", function() {
+ expect( 2 );
+
+ var element = $( "#draggable1" ).draggable();
+
+ TestHelpers.draggable.trackAppendedParent( element );
+
+ equal( element.draggable( "option", "appendTo" ), "parent" );
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_parent" ), $( "#qunit-fixture" )[ 0 ] );
+});
+
+test( "{ appendTo: Element }", function() {
+ expect( 1 );
+
+ var appendTo = $( "#draggable2" ).parent()[ 0 ],
+ element = $( "#draggable1" ).draggable({ appendTo: appendTo });
+
+ TestHelpers.draggable.trackAppendedParent( element );
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_parent" ), appendTo );
+});
+
+test( "{ appendTo: jQuery }", function() {
+ expect( 1 );
+
+ var appendTo = $( "#draggable2" ).parent(),
+ element = $( "#draggable1" ).draggable({ appendTo: appendTo });
+
+ TestHelpers.draggable.trackAppendedParent( element );
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_parent" ), appendTo[ 0 ] );
+});
+
+test( "{ appendTo: Selector }", function() {
+ expect( 1 );
+
+ var appendTo = "#main",
+ element = $( "#draggable1" ).draggable({ appendTo: appendTo });
+
+ TestHelpers.draggable.trackAppendedParent( element );
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_parent" ), $(appendTo)[ 0 ] );
+});
+
+test( "appendTo, default, switching after initialization", function() {
+ expect( 2 );
+
+ var element = $( "#draggable1" ).draggable({ helper : "clone" });
+
+ TestHelpers.draggable.trackAppendedParent( element );
+
+ // Move and make sure element was appended to fixture
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_parent" ), $( "#qunit-fixture" )[ 0 ] );
+
+ // Move and make sure element was appended to main
+ element.draggable( "option", "appendTo", $( "#main" ) );
+ TestHelpers.draggable.move( element, 2, 2 );
+ equal( element.data( "last_dragged_parent" ), $( "#main" )[ 0 ] );
+});
+
+test( "{ axis: false }, default", function() {
+ expect( 1 );
+ var element = $( "#draggable2" ).draggable({ axis: false });
+ TestHelpers.draggable.shouldMove( element );
+});
+
+test( "{ axis: 'x' }", function() {
+ expect( 1 );
+ var element = $( "#draggable2" ).draggable({ axis: "x" });
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 50, 0 );
+});
+
+test( "{ axis: 'y' }", function() {
+ expect( 1 );
+ var element = $( "#draggable2" ).draggable({ axis: "y" });
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 0, 50 );
+});
+
+test( "{ axis: ? }, unexpected", function() {
+ var element,
+ unexpected = {
+ "true": true,
+ "{}": {},
+ "[]": [],
+ "null": null,
+ "undefined": undefined,
+ "function() {}": function() {}
+ };
+
+ expect( 6 );
+
+ $.each(unexpected, function(key, val) {
+ element = $( "#draggable2" ).draggable({ axis: val });
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 50, 50, "axis: " + key );
+ element.draggable( "destroy" );
+ });
+});
+
+test( "axis, default, switching after initialization", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable({ axis : false });
+
+ // Any Direction
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 50, 50 );
+
+ // Only horizontal
+ element.draggable( "option", "axis", "x" );
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 50, 0 );
+
+ // Vertical only
+ element.draggable( "option", "axis", "y" );
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 0, 50 );
+
+});
+
+test( "{ cancel: 'input,textarea,button,select,option' }, default", function() {
+ expect( 2 );
+
+ $( "<div id='draggable-option-cancel-default'><input type='text'></div>" ).appendTo( "#main" );
+
+ var element = $( "#draggable-option-cancel-default" ).draggable({ cancel: "input,textarea,button,select,option" });
+ TestHelpers.draggable.shouldMove( element );
+
+ element.draggable( "destroy" );
+
+ element = $( "#draggable-option-cancel-default" ).draggable({ cancel: "input,textarea,button,select,option" });
+ TestHelpers.draggable.testDrag( element, "#draggable-option-cancel-default input", 50, 50, 0, 0 );
+ element.draggable( "destroy" );
+});
+
+test( "{ cancel: 'span' }", function() {
+ expect( 2 );
+
+ var element = $( "#draggable2" ).draggable();
+ TestHelpers.draggable.testDrag( element, "#draggable2 span", 50, 50, 50, 50 );
+
+ element.draggable( "destroy" );
+
+ element = $( "#draggable2" ).draggable({ cancel: "span" });
+ TestHelpers.draggable.testDrag( element, "#draggable2 span", 50, 50, 0, 0 );
+});
+
+test( "{ cancel: ? }, unexpected", function() {
+ expect( 6 );
+
+ var element,
+ unexpected = {
+ "true": true,
+ "false": false,
+ "{}": {},
+ "[]": [],
+ "null": null,
+ "undefined": undefined
+ };
+
+ $.each( unexpected, function( key, val ) {
+ element = $( "#draggable2" ).draggable({ cancel: val });
+ TestHelpers.draggable.shouldMove( element, "cancel: " + key );
+ element.draggable( "destroy" );
+ });
+});
+
+/**
+test( "{ cancel: Selectors }, matching parent selector", function() {
+
+ expect( 5 );
+
+ var element = $( "#draggable2" ).draggable({ cancel: "span a" });
+
+ $( "#qunit-fixture" ).append( "<span id='wrapping'><a></a></span>" );
+
+ element.find( "span" ).append( "<a>" );
+
+ $( "#wrapping a" ).append( element );
+
+ TestHelpers.draggable.testDrag( element, "#draggable2 span", 50, 50, 50, 50, "drag span child" );
+ TestHelpers.draggable.shouldNotMove( $( "#draggable2 span a" ) );
+ TestHelpers.draggable.shouldNotMove( $( "#wrapping a" ) );
+
+ $( "#draggable2" ).draggable( "option", "cancel", "span > a" );
+ $( "#draggable2" ).find( "a" ).append( "<a>" );
+
+
+ TestHelpers.draggable.testDrag( element, $( "#draggable2 span a" ).last(), 50, 50, 50, 50, "drag span child" );
+ TestHelpers.draggable.shouldNotMove( $( "#draggable2 span a" ).first() );
+
+});
+*/
+
+test( "cancelement, default, switching after initialization", function() {
+ expect( 3 );
+
+ $( "<div id='draggable-option-cancel-default'><input type='text'></div>" ).appendTo( "#main" );
+
+ var input = $( "#draggable-option-cancel-default input" ),
+ element = $( "#draggable-option-cancel-default" ).draggable();
+
+ TestHelpers.draggable.testDrag( element, input, 50, 50, 0, 0 );
+
+ element.draggable( "option", "cancel", "textarea" );
+ TestHelpers.draggable.testDrag( element, input, 50, 50, 50, 50 );
+
+ element.draggable( "option", "cancel", "input" );
+ TestHelpers.draggable.testDrag( element, input, 50, 50, 0, 0 );
+});
+
+/*
+
+test( "{ connectToSortable: selector }, default", function() {
+ expect( 1 );
+
+ ok(false, "missing test - untested code is broken code" );
+});
+*/
+
+test( "{ containment: Element }", function() {
+ expect( 1 );
+
+ var offsetAfter,
+ element = $( "#draggable1" ).draggable({ containment: $( "#draggable1" ).parent()[ 0 ] }),
+ p = element.parent(),
+ po = p.offset(),
+ expected = {
+ left: po.left + TestHelpers.draggable.border( p, "left" ) + TestHelpers.draggable.margin( element, "left" ),
+ top: po.top + TestHelpers.draggable.border( p, "top" ) + TestHelpers.draggable.margin( element, "top" )
+ };
+
+ element.simulate( "drag", {
+ dx: -100,
+ dy: -100
+ });
+ offsetAfter = element.offset();
+ deepEqual( offsetAfter, expected, "compare offset to parent" );
+});
+
+test( "{ containment: Selector }", function() {
+ expect( 1 );
+
+ var offsetAfter,
+ element = $( "#draggable1" ).draggable({ containment: $( "#qunit-fixture" ) }),
+ p = element.parent(),
+ po = p.offset(),
+ expected = {
+ left: po.left + TestHelpers.draggable.border( p, "left" ) + TestHelpers.draggable.margin( element, "left" ),
+ top: po.top + TestHelpers.draggable.border( p, "top" ) + TestHelpers.draggable.margin( element, "top" )
+ };
+
+ element.simulate( "drag", {
+ dx: -100,
+ dy: -100
+ });
+ offsetAfter = element.offset();
+ deepEqual( offsetAfter, expected, "compare offset to parent" );
+});
+
+test( "{ containment: [x1, y1, x2, y2] }", function() {
+ expect( 1 );
+
+ var element = $( "#draggable1" ).draggable(),
+ eo = element.offset();
+
+ element.draggable( "option", "containment", [ eo.left, eo.top, eo.left + element.width() + 5, eo.top + element.height() + 5 ] );
+
+ TestHelpers.draggable.testDrag( element, element, -100, -100, 0, 0 );
+});
+
+test( "{ containment: 'parent' }, relative", function() {
+ expect( 1 );
+
+ var offsetAfter,
+ element = $( "#draggable1" ).draggable({ containment: "parent" }),
+ p = element.parent(),
+ po = p.offset(),
+ expected = {
+ left: po.left + TestHelpers.draggable.border( p, "left" ) + TestHelpers.draggable.margin( element, "left" ),
+ top: po.top + TestHelpers.draggable.border( p, "top" ) + TestHelpers.draggable.margin( element, "top" )
+ };
+
+ element.simulate( "drag", {
+ dx: -100,
+ dy: -100
+ });
+ offsetAfter = element.offset();
+ deepEqual( offsetAfter, expected, "compare offset to parent" );
+});
+
+test( "{ containment: 'parent' }, absolute", function() {
+ expect( 1 );
+
+ var offsetAfter,
+ element = $( "#draggable2" ).draggable({ containment: "parent" }),
+ p = element.parent(),
+ po = p.offset(),
+ expected = {
+ left: po.left + TestHelpers.draggable.border( p, "left" ) + TestHelpers.draggable.margin( element, "left" ),
+ top: po.top + TestHelpers.draggable.border( p, "top" ) + TestHelpers.draggable.margin( element, "top" )
+ };
+
+ element.simulate( "drag", {
+ dx: -100,
+ dy: -100
+ });
+ offsetAfter = element.offset();
+ deepEqual( offsetAfter, expected, "compare offset to parent" );
+});
+
+test( "containment, account for border", function() {
+ expect( 2 );
+
+ var el = $("#draggable1").appendTo("#main"),
+ parent = el.parent().css({
+ height: "100px",
+ width: "100px",
+ borderStyle: "solid",
+ borderWidth: "5px 10px 15px 20px"
+ }),
+ parentBottom = parent.offset().top + parent.outerHeight(),
+ parentRight = parent.offset().left + parent.outerWidth(),
+ parentBorderBottom = TestHelpers.draggable.border( parent, "bottom" ),
+ parentBorderRight = TestHelpers.draggable.border( parent, "right" );
+
+ el.css({
+ height: "5px",
+ width: "5px"
+ }).draggable({ containment: "parent" });
+
+ el.simulate( "drag", {
+ dx: 100,
+ dy: 100
+ });
+
+ equal( el.offset().top, parentBottom - parentBorderBottom - el.height(),
+ "The draggable should be on top of its parent's bottom border" );
+ equal( el.offset().left, parentRight - parentBorderRight - el.width(),
+ "The draggable should be to the right of its parent's right border" );
+});
+
+test( "containment, default, switching after initialization", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable({ containment: false });
+
+ TestHelpers.draggable.testDrag( element, element, -100, -100, -100, -100 );
+
+ element.draggable( "option", "containment", "parent" )
+ .css({
+ top: 0,
+ left: 0
+ })
+ .appendTo( $( "#main" ) );
+
+ TestHelpers.draggable.testDrag( element, element, -100, -100, 0, 0 );
+
+ element.draggable( "option", "containment", false );
+ TestHelpers.draggable.testDrag( element, element, -100, -100, -100, -100 );
+});
+
+test( "{ cursor: 'auto' }, default", function() {
+ function getCursor() {
+ return $( "#draggable2" ).css( "cursor" );
+ }
+
+ expect( 2 );
+
+ var actual, after,
+ expected = "auto",
+ element = $( "#draggable2" ).draggable({
+ cursor: expected,
+ start: function() {
+ actual = getCursor();
+ }
+ }),
+ before = getCursor();
+
+ element.simulate( "drag", {
+ dx: -1,
+ dy: -1
+ });
+ after = getCursor();
+
+ equal( actual, expected, "start callback: cursor '" + expected + "'" );
+ equal( after, before, "after drag: cursor restored" );
+});
+
+test( "{ cursor: 'move' }", function() {
+ function getCursor() {
+ return $( "body" ).css( "cursor" );
+ }
+
+ expect( 2 );
+
+ var actual, after,
+ expected = "move",
+ element = $( "#draggable2" ).draggable({
+ cursor: expected,
+ start: function() {
+ actual = getCursor();
+ }
+ }),
+ before = getCursor();
+
+ element.simulate( "drag", {
+ dx: -1,
+ dy: -1
+ });
+ after = getCursor();
+
+ equal( actual, expected, "start callback: cursor '" + expected + "'" );
+ equal( after, before, "after drag: cursor restored" );
+});
+
+test( "cursor, default, switching after initialization", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable();
+
+ TestHelpers.draggable.trackMouseCss( element );
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_cursor" ), "auto" );
+
+ element.draggable( "option", "cursor", "move" );
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_cursor" ), "move" );
+
+ element.draggable( "option", "cursor", "ns-resize" );
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.data( "last_dragged_cursor" ), "ns-resize" );
+});
+
+test( "cursorAt", function() {
+ expect( 24 );
+
+ var deltaX = -3,
+ deltaY = -3,
+ tests = {
+ "false": { cursorAt : false },
+ "{ left: -5, top: -5 }": { x: -5, y: -5, cursorAt : { left: -5, top: -5 } },
+ "[ 10, 20 ]": { x: 10, y: 20, cursorAt : [ 10, 20 ] },
+ "'10 20'": { x: 10, y: 20, cursorAt : "10 20" },
+ "{ left: 20, top: 40 }": { x: 20, y: 40, cursorAt : { left: 20, top: 40 } },
+ "{ right: 10, bottom: 20 }": { x: 10, y: 20, cursorAt : { right: 10, bottom: 20 } }
+ };
+
+ $.each( tests, function( testName, testData ) {
+ $.each( [ "relative", "absolute" ], function( i, position ) {
+ var element = $( "#draggable" + ( i + 1 ) ).draggable({
+ cursorAt: testData.cursorAt,
+ drag: function( event, ui ) {
+ if( !testData.cursorAt ) {
+ equal( ui.position.left - ui.originalPosition.left, deltaX, testName + " " + position + " left" );
+ equal( ui.position.top - ui.originalPosition.top, deltaY, testName + " " + position + " top" );
+ } else if( testData.cursorAt.right ) {
+ equal( ui.helper.width() - ( event.clientX - ui.offset.left ), testData.x - TestHelpers.draggable.unreliableOffset, testName + " " + position + " left" );
+ equal( ui.helper.height() - ( event.clientY - ui.offset.top ), testData.y - TestHelpers.draggable.unreliableOffset, testName + " " +position + " top" );
+ } else {
+ equal( event.clientX - ui.offset.left, testData.x + TestHelpers.draggable.unreliableOffset, testName + " " + position + " left" );
+ equal( event.clientY - ui.offset.top, testData.y + TestHelpers.draggable.unreliableOffset, testName + " " + position + " top" );
+ }
+ }
+ });
+
+ element.simulate( "drag", {
+ moves: 1,
+ dx: deltaX,
+ dy: deltaY
+ });
+ });
+ });
+});
+
+test( "cursorAt, switching after initialization", function() {
+ expect( 24 );
+
+ var deltaX = -3,
+ deltaY = -3,
+ tests = {
+ "false": { cursorAt : false },
+ "{ left: -5, top: -5 }": { x: -5, y: -5, cursorAt : { left: -5, top: -5 } },
+ "[ 10, 20 ]": { x: 10, y: 20, cursorAt : [ 10, 20 ] },
+ "'10 20'": { x: 10, y: 20, cursorAt : "10 20" },
+ "{ left: 20, top: 40 }": { x: 20, y: 40, cursorAt : { left: 20, top: 40 } },
+ "{ right: 10, bottom: 20 }": { x: 10, y: 20, cursorAt : { right: 10, bottom: 20 } }
+ };
+
+ $.each( tests, function( testName, testData ) {
+ $.each( [ "relative", "absolute" ], function( i, position ) {
+ var element = $( "#draggable" + ( i + 1 ) );
+
+ element.draggable({
+ drag: function( event, ui ) {
+ if( !testData.cursorAt ) {
+ equal( ui.position.left - ui.originalPosition.left, deltaX, testName + " " + position + " left" );
+ equal( ui.position.top - ui.originalPosition.top, deltaY, testName + " " + position + " top" );
+ } else if( testData.cursorAt.right ) {
+ equal( ui.helper.width() - ( event.clientX - ui.offset.left ), testData.x - TestHelpers.draggable.unreliableOffset, testName + " " + position + " left" );
+ equal( ui.helper.height() - ( event.clientY - ui.offset.top ), testData.y - TestHelpers.draggable.unreliableOffset, testName + " " +position + " top" );
+ } else {
+ equal( event.clientX - ui.offset.left, testData.x + TestHelpers.draggable.unreliableOffset, testName + " " + position + " left" );
+ equal( event.clientY - ui.offset.top, testData.y + TestHelpers.draggable.unreliableOffset, testName + " " + position + " top" );
+ }
+ }
+ });
+
+ element.draggable( "option", "cursorAt", false );
+ element.draggable( "option", "cursorAt", testData.cursorAt );
+
+ element.simulate( "drag", {
+ moves: 1,
+ dx: deltaX,
+ dy: deltaY
+ });
+ });
+ });
+});
+
+test( "disabled", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable();
+
+ TestHelpers.draggable.shouldMove( element );
+
+ element.draggable( "option", "disabled", true );
+ TestHelpers.draggable.shouldNotMove( element );
+
+ element.draggable( "option", "disabled", false );
+ TestHelpers.draggable.shouldMove( element );
+});
+
+test( "{ grid: [50, 50] }, relative", function() {
+ expect( 2 );
+
+ var element = $( "#draggable1" ).draggable({ grid: [ 50, 50 ] });
+ TestHelpers.draggable.testDrag( element, element, 24, 24, 0, 0 );
+ TestHelpers.draggable.testDrag( element, element, 26, 25, 50, 50 );
+});
+
+test( "{ grid: [50, 50] }, absolute", function() {
+ expect( 2 );
+
+ var element = $( "#draggable2" ).draggable({ grid: [ 50, 50 ] });
+ TestHelpers.draggable.testDrag( element, element, 24, 24, 0, 0 );
+ TestHelpers.draggable.testDrag( element, element, 26, 25, 50, 50 );
+});
+
+test( "grid, switching after initialization", function() {
+ expect( 4 );
+
+ var element = $( "#draggable1" ).draggable();
+
+ // Forward
+ TestHelpers.draggable.testDrag( element, element, 24, 24, 24, 24 );
+ TestHelpers.draggable.testDrag( element, element, 0, 0, 0, 0 );
+
+ element.draggable( "option", "grid", [ 50,50 ] );
+
+ TestHelpers.draggable.testDrag( element, element, 24, 24, 0, 0 );
+ TestHelpers.draggable.testDrag( element, element, 26, 25, 50, 50 );
+});
+
+test( "{ handle: 'span' }", function() {
+ expect( 3 );
+
+ var element = $( "#draggable2" ).draggable({ handle: "span" });
+
+ TestHelpers.draggable.testDrag( element, "#draggable2 span", 50, 50, 50, 50, "drag span" );
+ TestHelpers.draggable.testDrag( element, "#draggable2 span em", 50, 50, 50, 50, "drag span child" );
+ TestHelpers.draggable.shouldNotMove( element, "drag element" );
+});
+
+test( "handle, default, switching after initialization", function() {
+ expect( 6 );
+
+ var element = $( "#draggable2" ).draggable();
+
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 50, 50 );
+ TestHelpers.draggable.testDrag( element, "#draggable2 span", 100, 100, 100, 100 );
+
+ // Switch
+ element.draggable( "option", "handle", "span" );
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 0, 0 );
+ TestHelpers.draggable.testDrag( element, "#draggable2 span", 100, 100, 100, 100 );
+
+ // And back
+ element.draggable( "option", "handle", false );
+ TestHelpers.draggable.testDrag( element, element, 50, 50, 50, 50 );
+ TestHelpers.draggable.testDrag( element, "#draggable2 span", 100, 100, 100, 100 );
+});
+
+test( "helper, default, switching after initialization", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable();
+ TestHelpers.draggable.shouldMove( element );
+
+ element.draggable( "option", "helper", "clone" );
+ TestHelpers.draggable.shouldNotMove( element );
+
+ element.draggable( "option", "helper", "original" );
+ TestHelpers.draggable.shouldMove( element );
+});
+
+test( "{ helper: 'clone' }, relative", function() {
+ expect( 1 );
+
+ var element = $( "#draggable1" ).draggable({ helper: "clone" });
+ TestHelpers.draggable.shouldNotMove( element );
+});
+
+test( "{ helper: 'clone' }, absolute", function() {
+ expect( 1 );
+
+ var element = $( "#draggable2" ).draggable({ helper: "clone" });
+ TestHelpers.draggable.shouldNotMove( element );
+});
+
+test( "{ helper: 'original' }, relative, with scroll offset on parent", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll();
+});
+
+test( "{ helper: 'original' }, relative, with scroll offset on root", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll( "root" );
+});
+
+test( "{ helper: 'original' }, relative, with scroll offset on root and parent", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll();
+ TestHelpers.draggable.restoreScroll( "root" );
+});
+
+test( "{ helper: 'original' }, absolute, with scroll offset on parent", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).css({ position: "absolute", top: 0, left: 0 }).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll();
+});
+
+test( "{ helper: 'original' }, absolute, with scroll offset on root", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).css({ position: "absolute", top: 0, left: 0 }).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll( "root" );
+});
+
+test( "{ helper: 'original' }, absolute, with scroll offset on root and parent", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).css({ position: "absolute", top: 0, left: 0 }).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll();
+ TestHelpers.draggable.restoreScroll( "root" );
+});
+
+test( "{ helper: 'original' }, fixed, with scroll offset on parent", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).css({ position: "fixed", top: 0, left: 0 }).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll();
+});
+
+test( "{ helper: 'original' }, fixed, with scroll offset on root", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).css({ position: "fixed", top: 0, left: 0 }).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll( "root" );
+});
+
+test( "{ helper: 'original' }, fixed, with scroll offset on root and parent", function() {
+ expect( 3 );
+
+ var element = $( "#draggable1" ).css({ position: "fixed", top: 0, left: 0 }).draggable({ helper: "original" });
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "relative" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "static" );
+
+ TestHelpers.draggable.setScroll();
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.testScroll( element, "absolute" );
+
+ TestHelpers.draggable.restoreScroll();
+ TestHelpers.draggable.restoreScroll( "root" );
+});
+
+test( "{ helper: 'clone' }, absolute", function() {
+ expect( 1 );
+
+ var helperOffset = null,
+ origOffset = $( "#draggable1" ).offset(),
+ element = $( "#draggable1" ).draggable({ helper: "clone", drag: function( event, ui) {
+ helperOffset = ui.helper.offset();
+ } });
+
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+});
+
+test( "{ helper: 'clone' }, absolute with scroll offset on parent", function() {
+ expect( 3 );
+
+ TestHelpers.draggable.setScroll();
+ var helperOffset = null,
+ origOffset = null,
+ element = $( "#draggable1" ).draggable({
+ helper: "clone",
+ drag: function( event, ui) {
+ helperOffset = ui.helper.offset();
+ }
+ });
+
+ $( "#main" ).css( "position", "relative" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ $( "#main" ).css( "position", "static" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ $( "#main" ).css( "position", "absolute" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ TestHelpers.draggable.restoreScroll();
+});
+
+test( "{ helper: 'clone' }, absolute with scroll offset on root", function() {
+ expect( 3 );
+
+ TestHelpers.draggable.setScroll( "root" );
+ var helperOffset = null,
+ origOffset = null,
+ element = $( "#draggable1" ).draggable({
+ helper: "clone",
+ drag: function( event, ui) {
+ helperOffset = ui.helper.offset();
+ }
+ });
+
+ $( "#main" ).css( "position", "relative" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ $( "#main" ).css( "position", "static" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ $( "#main" ).css( "position", "absolute" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ TestHelpers.draggable.restoreScroll( "root" );
+});
+
+test( "{ helper: 'clone' }, absolute with scroll offset on root and parent", function() {
+ expect( 3 );
+
+ TestHelpers.draggable.setScroll( "root" );
+ TestHelpers.draggable.setScroll();
+
+ var helperOffset = null,
+ origOffset = null,
+ element = $( "#draggable1" ).draggable({
+ helper: "clone",
+ drag: function( event, ui) {
+ helperOffset = ui.helper.offset();
+ }
+ });
+
+ $( "#main" ).css( "position", "relative" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ $( "#main" ).css( "position", "static" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ $( "#main" ).css( "position", "absolute" );
+ origOffset = $( "#draggable1" ).offset();
+ element.simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+ deepEqual({ top: helperOffset.top - 1, left: helperOffset.left - 1 }, origOffset, "dragged[1, 1]" );
+
+ TestHelpers.draggable.restoreScroll( "root" );
+ TestHelpers.draggable.restoreScroll();
+});
+
+test( "{ opacity: 0.5 }", function() {
+ expect( 1 );
+
+ var opacity = null,
+ element = $( "#draggable2" ).draggable({
+ opacity: 0.5,
+ start: function() {
+ opacity = $(this).css( "opacity" );
+ }
+ });
+
+ element.simulate( "drag", {
+ dx: -1,
+ dy: -1
+ });
+
+ equal( opacity, 0.5, "start callback: opacity is" );
+});
+
+test( "opacity, default, switching after initialization", function() {
+ expect( 3 );
+
+ var opacity = null,
+ element = $( "#draggable2" ).draggable({
+ start: function() {
+ opacity = $(this).css( "opacity" );
+ }
+ });
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( opacity, 1 );
+
+ element.draggable( "option", "opacity", 0.5 );
+ TestHelpers.draggable.move( element, 2, 1 );
+ equal( opacity, 0.5 );
+
+ element.draggable( "option", "opacity", false );
+ TestHelpers.draggable.move( element, 3, 1 );
+ equal( opacity, 1 );
+});
+
+asyncTest( "revert and revertDuration", function() {
+ expect( 4 );
+
+ var element = $( "#draggable2" ).draggable({
+ revert: true,
+ revertDuration: 0
+ });
+ TestHelpers.draggable.shouldNotMove( element, "revert: true, revertDuration: 0 should revert immediately" );
+
+ $( "#draggable2" ).draggable( "option", "revert", "invalid" );
+ TestHelpers.draggable.shouldNotMove( element, "revert: invalid, revertDuration: 0 should revert immediately" );
+
+ $( "#draggable2" ).draggable( "option", "revert", false );
+ TestHelpers.draggable.shouldMove( element, "revert: false should allow movement" );
+
+ $( "#draggable2" ).draggable( "option", {
+ revert: true,
+ revertDuration: 200,
+ stop: function() {
+ start();
+ }
+ });
+
+ // animation are async, so test for it asynchronously
+ TestHelpers.draggable.move( element, 50, 50 );
+ setTimeout( function() {
+ ok( $( "#draggable2" ).is( ":animated" ), "revert: true with revertDuration should animate" );
+ });
+});
+
+test( "revert: valid", function() {
+ expect( 1 );
+
+ var element = $( "#draggable2" ).draggable({
+ revert: "valid",
+ revertDuration: 0
+ });
+
+ $( "#droppable" ).droppable();
+
+ TestHelpers.draggable.testDrag( element, element, 100, 100, 0, 0, "revert: valid reverts when dropped on a droppable" );
+});
+
+test( "scope", function() {
+ expect( 2 );
+
+ var element = $( "#draggable2" ).draggable({
+ scope: "tasks",
+ revert: "valid",
+ revertDuration: 0
+ });
+
+ $( "#droppable" ).droppable({ scope: "tasks" });
+
+ TestHelpers.draggable.testDrag( element, element, 100, 100, 0, 0, "revert: valid reverts when dropped on a droppable in scope" );
+
+ $( "#droppable" ).droppable( "destroy" ).droppable({ scope: "nottasks" });
+
+ TestHelpers.draggable.testDrag( element, element, 100, 100, 100, 100, "revert: valid reverts when dropped on a droppable out of scope" );
+});
+
+test( "scroll, scrollSensitivity, and scrollSpeed", function() {
+ expect( 2 );
+
+ var viewportHeight = $( window ).height(),
+ element = $( "#draggable1" ).draggable({ scroll: true }),
+ scrollSensitivity = element.draggable( "option", "scrollSensitivity" ),
+ scrollSpeed = element.draggable( "option", "scrollSpeed" );
+
+ element.offset({
+ top: viewportHeight - scrollSensitivity - 1,
+ left: 1
+ });
+
+ element.simulate( "drag", {
+ dx: 1,
+ y: viewportHeight - scrollSensitivity - 1,
+ moves: 1
+ });
+
+ ok( $( window ).scrollTop() === 0, "scroll: true doesn't scroll when the element is dragged outside of scrollSensitivity" );
+
+ element.draggable( "option", "scrollSensitivity", scrollSensitivity + 10 );
+
+ element.offset({
+ top: viewportHeight - scrollSensitivity - 1,
+ left: 1
+ });
+
+ element.simulate( "drag", {
+ dx: 1,
+ y: viewportHeight - scrollSensitivity - 1,
+ moves: 1
+ });
+
+ ok( $( window ).scrollTop() === scrollSpeed, "scroll: true scrolls when the element is dragged within scrollSensitivity" );
+
+ TestHelpers.draggable.restoreScroll( document );
+});
+
+test( "#6817: auto scroll goes double distance when dragging", function() {
+ expect( 2 );
+
+ var offsetBefore,
+ distance = 10,
+ viewportHeight = $( window ).height(),
+ element = $( "#draggable1" ).draggable({
+ scroll: true,
+ stop: function( e, ui ) {
+ equal( ui.offset.top, newY, "offset of item matches pointer position after scroll" );
+ // TODO: fix IE8 testswarm IFRAME positioning bug so closeEnough can be turned back to equal
+ closeEnough( ui.offset.top - offsetBefore.top, distance, 1, "offset of item only moves expected distance after scroll" );
+ }
+ }),
+ scrollSensitivity = element.draggable( "option", "scrollSensitivity" ),
+ oldY = viewportHeight - scrollSensitivity,
+ newY = oldY + distance;
+
+ element.offset({
+ top: oldY,
+ left: 1
+ });
+
+ offsetBefore = element.offset();
+
+ element.simulate( "drag", {
+ handle: "corner",
+ dx: 1,
+ y: newY,
+ moves: 1
+ });
+
+ TestHelpers.draggable.restoreScroll( document );
+});
+
+test( "snap, snapMode, and snapTolerance", function() {
+ expect( 10 );
+
+ var newX, newY,
+ snapTolerance = 15,
+ element = $( "#draggable1" ).draggable({
+ snap: true,
+ snapMode: "both",
+ snapTolerance: snapTolerance
+ }),
+ element2 = $( "#draggable2" ).draggable();
+
+ element.offset({
+ top: 1,
+ left: 1
+ });
+
+ newX = element2.offset().left - element.outerWidth() - snapTolerance - 2;
+ newY = element2.offset().top;
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ // TODO: fix IE8 testswarm IFRAME positioning bug so closeEnough can be turned back to equal
+ closeEnough( element.offset().left, newX, 1, "doesn't snap outside the snapTolerance" );
+ closeEnough( element.offset().top, newY, 1, "doesn't snap outside the snapTolerance" );
+
+ newX += 3;
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ notDeepEqual( element.offset(), { top: newY, left: newX }, "snaps inside the snapTolerance" );
+
+ element.draggable( "option", "snap", "#draggable2" );
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ notDeepEqual( element.offset(), { top: newY, left: newX }, "snaps based on selector" );
+
+ element.draggable( "option", "snap", "#draggable3" );
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ deepEqual( element.offset(), { top: newY, left: newX }, "doesn't snap based on invalid selector" );
+
+ element.draggable( "option", "snap", true );
+ element.draggable( "option", "snapTolerance", snapTolerance - 2 );
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ deepEqual( element.offset(), { top: newY, left: newX }, "doesn't snap outside the modified snapTolerance" );
+
+ element.draggable( "option", "snapTolerance", snapTolerance );
+ element.draggable( "option", "snapMode", "inner" );
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ deepEqual( element.offset(), { top: newY, left: newX }, "doesn't snap inside the outer snapTolerance area when snapMode is inner" );
+
+ newX = element2.offset().left - snapTolerance - 1;
+ newY = element2.offset().top;
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ deepEqual( element.offset(), { top: newY, left: newX }, "doesn't snap inside the outer snapTolerance area when snapMode is inner" );
+
+ newX++;
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ notDeepEqual( element.offset(), { top: newY, left: newX }, "snaps inside the inner snapTolerance area when snapMode is inner" );
+
+ element.draggable( "option", "snapMode", "outer" );
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ deepEqual( element.offset(), { top: newY, left: newX }, "doesn't snap on the inner snapTolerance area when snapMode is outer" );
+});
+
+test( "#8459: element can snap to an element that was removed during drag", function() {
+ expect( 2 );
+
+ var newX, newY,
+ snapTolerance = 15,
+ element = $( "#draggable1" ).draggable({
+ snap: true,
+ snapMode: "both",
+ snapTolerance: snapTolerance,
+ start: function() {
+ element2.remove();
+ }
+ }),
+ element2 = $( "#draggable2" ).draggable();
+
+ element.offset({
+ top: 1,
+ left: 1
+ });
+
+ newX = element2.offset().left - element.outerWidth() - snapTolerance + 1;
+ newY = element2.offset().top;
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ y: newY,
+ moves: 1
+ });
+
+ // Support: Opera 12.10, Safari 5.1, jQuery <1.8
+ if ( TestHelpers.draggable.unreliableContains ) {
+ ok( true, "Opera <12.14 and Safari <6.0 report wrong values for $.contains in jQuery < 1.8" );
+ ok( true, "Opera <12.14 and Safari <6.0 report wrong values for $.contains in jQuery < 1.8" );
+ } else {
+ // TODO: fix IE8 testswarm IFRAME positioning bug so closeEnough can be turned back to equal
+ closeEnough( element.offset().left, newX, 1, "doesn't snap to a removed element" );
+ closeEnough( element.offset().top, newY, 1, "doesn't snap to a removed element" );
+ }
+});
+
+test( "#8165: Snapping large rectangles to small rectangles doesn't snap properly", function() {
+ expect( 1 );
+
+ var snapTolerance = 20,
+ y = 1,
+ element = $( "#draggable1" )
+ .css({
+ width: "50px",
+ height: "200px"
+ }).offset({
+ top: y,
+ left: 1
+ }),
+ element2 = $( "#draggable2" )
+ .css({
+ width: "50px",
+ height: "50px"
+ }).offset({
+ top: y + snapTolerance + 1,
+ left: 200
+ }),
+ newX = element2.offset().left - element.outerWidth() - snapTolerance + 1;
+
+ $( "#draggable1, #draggable2" ).draggable({
+ snap: true,
+ snapTolerance: snapTolerance
+ });
+
+ element.simulate( "drag", {
+ handle: "corner",
+ x: newX,
+ moves: 1
+ });
+
+ notDeepEqual( element.offset(), { top: y, left: newX }, "snaps even if only a side (not a corner) is inside the snapTolerance" );
+});
+
+test( "stack", function() {
+ expect( 2 );
+
+ var element = $( "#draggable1" ).draggable({
+ stack: "#draggable1, #draggable2"
+ }),
+ element2 = $( "#draggable2" ).draggable({
+ stack: "#draggable1, #draggable2"
+ });
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( element.css( "zIndex" ), "2", "stack increments zIndex correctly" );
+
+ TestHelpers.draggable.move( element2, 1, 1 );
+ equal( element2.css( "zIndex" ), "3", "stack increments zIndex correctly" );
+});
+
+test( "{ zIndex: 10 }", function() {
+ expect( 1 );
+
+ var actual,
+ expected = 10,
+ element = $( "#draggable2" ).draggable({
+ zIndex: expected,
+ start: function() {
+ actual = $(this).css( "zIndex" );
+ }
+ });
+
+ element.simulate( "drag", {
+ dx: -1,
+ dy: -1
+ });
+
+ equal( actual, expected, "start callback: zIndex is" );
+
+});
+
+test( "zIndex, default, switching after initialization", function() {
+
+ expect( 3 );
+
+ var zindex = null,
+ element = $( "#draggable2" ).draggable({
+ start: function() {
+ zindex = $(this).css( "z-index" );
+ }
+ });
+
+ element.css( "z-index", 1 );
+
+ TestHelpers.draggable.move( element, 1, 1 );
+ equal( zindex, 1 );
+
+ element.draggable( "option", "zIndex", 5 );
+ TestHelpers.draggable.move( element, 2, 1 );
+ equal( zindex, 5 );
+
+ element.draggable( "option", "zIndex", false );
+ TestHelpers.draggable.move( element, 3, 1 );
+ equal( zindex, 1 );
+
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/draggable/draggable_test_helpers.js b/apps/it/static/js/ui/tests/unit/draggable/draggable_test_helpers.js
new file mode 100644
index 0000000..b365055
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/draggable/draggable_test_helpers.js
@@ -0,0 +1,79 @@
+TestHelpers.draggable = {
+ // TODO: remove the unreliable offset hacks
+ unreliableOffset: $.ui.ie && ( !document.documentMode || document.documentMode < 8 ) ? 2 : 0,
+ // Support: Opera 12.10, Safari 5.1, jQuery <1.8
+ unreliableContains: (function(){
+ var element = $( "<div>" );
+ return $.contains( element[ 0 ].ownerDocument, element[ 0 ] );
+ })(),
+ testDrag: function( el, handle, dx, dy, expectedDX, expectedDY, msg ) {
+ var offsetAfter, actual, expected,
+ offsetBefore = el.offset();
+
+ $( handle ).simulate( "drag", {
+ dx: dx,
+ dy: dy
+ });
+ offsetAfter = el.offset();
+
+ actual = { left: offsetAfter.left, top: offsetAfter.top };
+ expected = { left: offsetBefore.left + expectedDX, top: offsetBefore.top + expectedDY };
+
+ msg = msg ? msg + "." : "";
+ deepEqual( actual, expected, "dragged[" + dx + ", " + dy + "] " + msg );
+ },
+ shouldMove: function( el, why ) {
+ TestHelpers.draggable.testDrag( el, el, 50, 50, 50, 50, why );
+ },
+ shouldNotMove: function( el, why ) {
+ TestHelpers.draggable.testDrag( el, el, 50, 50, 0, 0, why );
+ },
+ testScroll: function( el, position ) {
+ var oldPosition = $( "#main" ).css( "position" );
+ $( "#main" ).css( "position", position);
+ TestHelpers.draggable.shouldMove( el, position + " parent" );
+ $( "#main" ).css( "position", oldPosition );
+ },
+ restoreScroll: function( what ) {
+ if( what ) {
+ $( document ).scrollTop( 0 ).scrollLeft( 0 );
+ } else {
+ $( "#main" ).scrollTop( 0 ).scrollLeft( 0 );
+ }
+ },
+ setScroll: function( what ) {
+ if( what ) {
+ // TODO: currently, the draggable interaction doesn't properly account for scrolled pages,
+ // uncomment the line below to make the tests fail that should when the page is scrolled
+ // $( document ).scrollTop( 100 ).scrollLeft( 100 );
+ } else {
+ $( "#main" ).scrollTop( 100 ).scrollLeft( 100 );
+ }
+ },
+ border: function( el, side ) {
+ return parseInt( el.css( "border-" + side + "-width" ), 10 ) || 0;
+ },
+ margin: function( el, side ) {
+ return parseInt( el.css( "margin-" + side ), 10 ) || 0;
+ },
+ move: function( el, x, y ) {
+ $( el ).simulate( "drag", {
+ dx: x,
+ dy: y
+ });
+ },
+ trackMouseCss : function( el ) {
+ el.bind( "drag", function() {
+ el.data( "last_dragged_cursor", $( "body" ).css( "cursor" ) );
+ });
+ },
+ trackAppendedParent : function( el ) {
+ // TODO: appendTo is currently ignored if helper is original (see #7044)
+ el.draggable( "option", "helper", "clone" );
+
+ // Get what parent is at time of drag
+ el.bind( "drag", function(e,ui) {
+ el.data( "last_dragged_parent", ui.helper.parent()[ 0 ] );
+ });
+ }
+}; \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/droppable/all.html b/apps/it/static/js/ui/tests/unit/droppable/all.html
new file mode 100644
index 0000000..9a50050
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Droppable Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "droppable" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Droppable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/droppable/droppable.html b/apps/it/static/js/ui/tests/unit/droppable/droppable.html
new file mode 100644
index 0000000..d084464
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/droppable.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Droppable Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.draggable.js",
+ "ui/jquery.ui.droppable.js"
+ ]
+ });
+ </script>
+
+ <script src="droppable_common.js"></script>
+ <script src="droppable_core.js"></script>
+ <script src="droppable_events.js"></script>
+ <script src="droppable_methods.js"></script>
+ <script src="droppable_options.js"></script>
+ <script src="droppable_test_helpers.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Droppable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="draggable1" style="width: 25px; height: 25px;">Draggable</div>
+<div id="droppable1" style="width: 100px; height: 100px;">Droppable</div>
+<div id="droppable2" style="width: 100px; height: 100px;">Droppable</div>
+<div style='width:1000px;height:1000px;'>&nbsp;</div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/droppable/droppable_common.js b/apps/it/static/js/ui/tests/unit/droppable/droppable_common.js
new file mode 100644
index 0000000..c112def
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/droppable_common.js
@@ -0,0 +1,20 @@
+TestHelpers.commonWidgetTests( "droppable", {
+ defaults: {
+ accept: "*",
+ activeClass: false,
+ addClasses: true,
+ disabled: false,
+ greedy: false,
+ hoverClass: false,
+ scope: "default",
+ tolerance: "intersect",
+
+ // callbacks
+ activate: null,
+ create: null,
+ deactivate: null,
+ drop: null,
+ out: null,
+ over: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/droppable/droppable_core.js b/apps/it/static/js/ui/tests/unit/droppable/droppable_core.js
new file mode 100644
index 0000000..53b08fd
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/droppable_core.js
@@ -0,0 +1,29 @@
+/*
+ * droppable_core.js
+ */
+
+(function($) {
+
+module("droppable: core");
+
+test("element types", function() {
+ var typeNames = ("p,h1,h2,h3,h4,h5,h6,blockquote,ol,ul,dl,div,form" +
+ ",table,fieldset,address,ins,del,em,strong,q,cite,dfn,abbr" +
+ ",acronym,code,samp,kbd,var,img,hr" +
+ ",input,button,label,select,iframe").split(",");
+
+ expect( typeNames.length );
+
+ $.each(typeNames, function(i) {
+ var typeName = typeNames[i],
+ el = $(document.createElement(typeName)).appendTo("body");
+
+ (typeName === "table" && el.append("<tr><td>content</td></tr>"));
+ el.droppable();
+ TestHelpers.droppable.shouldDrop();
+ el.droppable("destroy");
+ el.remove();
+ });
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/droppable/droppable_events.js b/apps/it/static/js/ui/tests/unit/droppable/droppable_events.js
new file mode 100644
index 0000000..4b8fe5a
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/droppable_events.js
@@ -0,0 +1,63 @@
+(function( $ ) {
+
+module( "droppable: events" );
+
+test( "droppable destruction/recreation on drop event", function() {
+ expect( 1 );
+
+ var config = {
+ activeClass: "active",
+ drop: function() {
+ var element = $( this ),
+ newDroppable = $( "<div>" )
+ .css({ width: 100, height: 100 })
+ .text( "Droppable" );
+ element.after( newDroppable );
+ element.remove();
+ newDroppable.droppable( config );
+ }
+ },
+
+ draggable = $( "#draggable1" ).draggable(),
+ droppable1 = $( "#droppable1" ).droppable( config ),
+ droppable2 = $( "#droppable2" ).droppable( config ),
+
+ droppableOffset = droppable1.offset(),
+ draggableOffset = draggable.offset(),
+ dx = droppableOffset.left - draggableOffset.left,
+ dy = droppableOffset.top - draggableOffset.top;
+
+ draggable.simulate( "drag", {
+ dx: dx,
+ dy: dy
+ });
+
+ ok( !droppable2.hasClass( "active" ), "subsequent droppable no longer active" );
+});
+
+
+
+// todo: comment the following in when ready to actually test
+/*
+test("activate", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("deactivate", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("over", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("out", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("drop", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+*/
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/droppable/droppable_methods.js b/apps/it/static/js/ui/tests/unit/droppable/droppable_methods.js
new file mode 100644
index 0000000..2b452a6
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/droppable_methods.js
@@ -0,0 +1,88 @@
+/*
+ * droppable_methods.js
+ */
+(function($) {
+
+module("droppable: methods");
+
+test("init", function() {
+ expect( 5 );
+
+ $("<div></div>").appendTo("body").droppable().remove();
+ ok(true, ".droppable() called on element");
+
+ $([]).droppable();
+ ok(true, ".droppable() called on empty collection");
+
+ $("<div></div>").droppable();
+ ok(true, ".droppable() called on disconnected DOMElement");
+
+ $("<div></div>").droppable().droppable("option", "foo");
+ ok(true, "arbitrary option getter after init");
+
+ $("<div></div>").droppable().droppable("option", "foo", "bar");
+ ok(true, "arbitrary option setter after init");
+});
+
+test("destroy", function() {
+ expect( 4 );
+
+ $("<div></div>").appendTo("body").droppable().droppable("destroy").remove();
+ ok(true, ".droppable('destroy') called on element");
+
+ $([]).droppable().droppable("destroy");
+ ok(true, ".droppable('destroy') called on empty collection");
+
+ $("<div></div>").droppable().droppable("destroy");
+ ok(true, ".droppable('destroy') called on disconnected DOMElement");
+
+ var expected = $("<div></div>").droppable(),
+ actual = expected.droppable("destroy");
+ equal(actual, expected, "destroy is chainable");
+});
+
+test("enable", function() {
+ expect(7);
+
+ var el, expected, actual;
+
+ el = $("#droppable1").droppable({ disabled: true });
+ TestHelpers.droppable.shouldNotDrop();
+ el.droppable("enable");
+ TestHelpers.droppable.shouldDrop();
+ equal(el.droppable("option", "disabled"), false, "disabled option getter");
+ el.droppable("destroy");
+ el.droppable({ disabled: true });
+ TestHelpers.droppable.shouldNotDrop();
+ el.droppable("option", "disabled", false);
+ equal(el.droppable("option", "disabled"), false, "disabled option setter");
+ TestHelpers.droppable.shouldDrop();
+
+ expected = $("<div></div>").droppable(),
+ actual = expected.droppable("enable");
+ equal(actual, expected, "enable is chainable");
+});
+
+test("disable", function() {
+ expect(7);
+
+ var el, actual, expected;
+
+ el = $("#droppable1").droppable({ disabled: false });
+ TestHelpers.droppable.shouldDrop();
+ el.droppable("disable");
+ TestHelpers.droppable.shouldNotDrop();
+ equal(el.droppable("option", "disabled"), true, "disabled option getter");
+ el.droppable("destroy");
+ el.droppable({ disabled: false });
+ TestHelpers.droppable.shouldDrop();
+ el.droppable("option", "disabled", true);
+ equal(el.droppable("option", "disabled"), true, "disabled option setter");
+ TestHelpers.droppable.shouldNotDrop();
+
+ expected = $("<div></div>").droppable(),
+ actual = expected.droppable("disable");
+ equal(actual, expected, "disable is chainable");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/droppable/droppable_options.js b/apps/it/static/js/ui/tests/unit/droppable/droppable_options.js
new file mode 100644
index 0000000..c2ecdcf
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/droppable_options.js
@@ -0,0 +1,67 @@
+/*
+ * droppable_options.js
+ */
+(function($) {
+
+module("droppable: options");
+
+/*
+test("{ accept '*' }, default ", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("{ accept: Selector }", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("{ accept: function(draggable) }", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("activeClass", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+*/
+test("{ addClasses: true }, default", function() {
+ expect( 1 );
+ var el = $("<div></div>").droppable({ addClasses: true });
+ ok(el.is(".ui-droppable"), "'ui-droppable' class added");
+ el.droppable("destroy");
+});
+
+test("{ addClasses: false }", function() {
+ expect( 1 );
+ var el = $("<div></div>").droppable({ addClasses: false });
+ ok(!el.is(".ui-droppable"), "'ui-droppable' class not added");
+ el.droppable("destroy");
+});
+/*
+test("greedy", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("hoverClass", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("scope", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("tolerance, fit", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("tolerance, intersect", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("tolerance, pointer", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+
+test("tolerance, touch", function() {
+ ok(false, 'missing test - untested code is broken code');
+});
+*/
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/droppable/droppable_test_helpers.js b/apps/it/static/js/ui/tests/unit/droppable/droppable_test_helpers.js
new file mode 100644
index 0000000..ffd3745
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/droppable/droppable_test_helpers.js
@@ -0,0 +1,10 @@
+TestHelpers.droppable = {
+ shouldDrop: function() {
+ // todo: actually implement this
+ ok(true, "missing test - untested code is broken code");
+ },
+ shouldNotDrop: function() {
+ // todo: actually implement this
+ ok(true, "missing test - untested code is broken code");
+ }
+}; \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/effects/all.html b/apps/it/static/js/ui/tests/unit/effects/all.html
new file mode 100644
index 0000000..7448586
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/effects/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Effects Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "effects" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Effects Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/effects/effects.html b/apps/it/static/js/ui/tests/unit/effects/effects.html
new file mode 100644
index 0000000..4538ecb
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/effects/effects.html
@@ -0,0 +1,117 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Effects Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ js: [
+ "ui/jquery.ui.effect.js",
+ "ui/jquery.ui.effect-blind.js",
+ "ui/jquery.ui.effect-bounce.js",
+ "ui/jquery.ui.effect-clip.js",
+ "ui/jquery.ui.effect-drop.js",
+ "ui/jquery.ui.effect-explode.js",
+ "ui/jquery.ui.effect-fade.js",
+ "ui/jquery.ui.effect-fold.js",
+ "ui/jquery.ui.effect-highlight.js",
+ "ui/jquery.ui.effect-pulsate.js",
+ "ui/jquery.ui.effect-scale.js",
+ "ui/jquery.ui.effect-shake.js",
+ "ui/jquery.ui.effect-slide.js",
+ "ui/jquery.ui.effect-transfer.js"
+ ]
+ });
+ </script>
+
+ <script src="effects_core.js"></script>
+ <script src="effects_scale.js"></script>
+
+ <script src="../swarminject.js"></script>
+ <style>
+ #qunit-fixture {
+ width: 1000px;
+ height: 1000px;
+ }
+ .hidden {
+ display: none;
+ }
+ .test {
+ background: #000;
+ border: 0;
+ width: 100px;
+ height: 100px;
+ }
+ .testAddBorder {
+ border: 10px solid #000;
+ }
+ .testChildren,
+ .testChangeBackground {
+ background: #fff;
+ }
+ .test h2 {
+ font-size: 10px;
+ }
+ .testChildren h2 {
+ font-size: 20px;
+ }
+
+ .relWidth {
+ width: 50%;
+ }
+
+ .relHeight {
+ height: 50%;
+ }
+
+ .testScale {
+ border: 5px solid #000;
+ padding: 5px;
+ margin: 5px;
+ width: 50px;
+ height: 50px;
+ }
+
+ .ticket7106 {
+ width: 50px;
+ height: 50px;
+ }
+ .ticket7106.animate {
+ width: 100px;
+ }
+
+ </style>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Effects Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+<div id="elem" class="test">
+</div>
+<div class="hidden test">
+ <div>.</div>
+</div>
+<div class="animateClass test">
+ <h2>Child Element Test</h2>
+</div>
+<div class="relWidth relHeight testAddBorder">
+ <h2>Slide with relative width</h2>
+</div>
+<div class="testScale">
+</div>
+<div class="ticket7106">
+</div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/effects/effects_core.js b/apps/it/static/js/ui/tests/unit/effects/effects_core.js
new file mode 100644
index 0000000..11e9d0b
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/effects/effects_core.js
@@ -0,0 +1,274 @@
+(function($) {
+
+function present( value, array, message ) {
+ QUnit.push( jQuery.inArray( value, array ) !== -1 , value, array, message );
+}
+
+function notPresent( value, array, message ) {
+ QUnit.push( jQuery.inArray( value, array ) === -1 , value, array, message );
+}
+
+// minDuration is used for "short" animate tests where we are only concerned about the final
+var minDuration = 15,
+
+ // duration is used for "long" animates where we plan on testing properties during animation
+ duration = 200;
+
+module( "effects.core" );
+
+// TODO: test all signatures of .show(), .hide(), .toggle().
+// Look at core's signatures and UI's signatures.
+asyncTest( ".hide() with step", function() {
+ expect( 1 );
+ var element = $( "#elem" ),
+ step = function() {
+ ok( true, "step callback invoked" );
+ step = $.noop;
+ };
+
+ element.hide({
+ step: function() {
+ step();
+ },
+ complete: start
+ });
+});
+
+test( "Immediate Return Conditions", function() {
+ var hidden = $( "div.hidden" ),
+ count = 0;
+ expect( 3 );
+ hidden.hide( "blind", function() {
+ equal( ++count, 1, "Hide on hidden returned immediately" );
+ }).show().show( "blind", function() {
+ equal( ++count, 2, "Show on shown returned immediately" );
+ });
+ equal( ++count, 3, "Both Functions worked properly" );
+});
+
+test( ".hide() with hidden parent", function() {
+ expect( 1 );
+ var element = $( "div.hidden" ).children();
+ element.hide( "blind", function() {
+ equal( element.css( "display" ), "none", "display: none" );
+ });
+});
+
+asyncTest( "Parse of null for options", function() {
+ var hidden = $( "div.hidden" ),
+ count = 0;
+ expect( 1 );
+ hidden.show( "blind", null, 1, function() {
+ equal( ++count, 1, "null for options still works" );
+ start();
+ });
+});
+
+test( "removeClass", function() {
+ expect( 3 );
+
+ var element = $( "<div>" );
+ equal( "", element[ 0 ].className );
+ element.addClass( "destroyed" );
+ equal( "destroyed", element[ 0 ].className );
+ element.removeClass();
+ equal( "", element[ 0 ].className );
+});
+
+
+/* TODO: Disabled - Can't figure out why this is failing in IE 6/7
+test( "createWrapper and removeWrapper retain focused elements (#7595)", function() {
+ expect( 2 );
+ var test = $( "div.hidden" ).show(),
+ input = $( "<input type='text'>" ).appendTo( test ).focus();
+
+ $.effects.createWrapper( test );
+ equal( document.activeElement, input[ 0 ], "Active element is still input after createWrapper" );
+ $.effects.removeWrapper( test );
+ equal( document.activeElement, input[ 0 ], "Active element is still input after removeWrapper" );
+});
+*/
+
+module( "effects.core: animateClass" );
+
+asyncTest( "animateClass works with borderStyle", function() {
+ var test = $("div.animateClass");
+ expect(3);
+ test.toggleClass("testAddBorder", minDuration, function() {
+ test.toggleClass("testAddBorder", minDuration, function() {
+ equal( test.css("borderLeftStyle"), "none", "None border set" );
+ start();
+ });
+ equal( test.css("borderLeftStyle"), "solid", "None border not immedately set" );
+ });
+ equal( test.css("borderLeftStyle"), "solid", "Solid border immedately set" );
+});
+
+asyncTest( "animateClass works with colors", function() {
+ var test = $("div.animateClass"),
+ oldStep = jQuery.fx.step.backgroundColor;
+
+ expect(2);
+
+ // we want to catch the first frame of animation
+ jQuery.fx.step.backgroundColor = function( fx ) {
+ oldStep.apply( this, arguments );
+
+ // make sure it has animated somewhere we can detect
+ if ( fx.pos > 255 / 2000 ) {
+ jQuery.fx.step.backgroundColor = oldStep;
+ notPresent( test.css("backgroundColor"),
+ [ "#000000", "#ffffff", "#000", "#fff", "rgb(0, 0, 0)", "rgb(255,255,255)" ],
+ "Color is not endpoints in middle." );
+ test.stop( true, true );
+ }
+ };
+
+ test.toggleClass("testChangeBackground", {
+ duration: 2000,
+ complete: function() {
+ present( test.css("backgroundColor"), [ "#ffffff", "#fff", "rgb(255, 255, 255)" ], "Color is final" );
+ start();
+ }
+ });
+});
+
+asyncTest( "animateClass calls step option", 1, function() {
+ var test = jQuery( "div.animateClass" ),
+ step = function() {
+ ok( true, "Step Function Called" );
+ test.stop();
+ start();
+ step = $.noop;
+ };
+ test.toggleClass( "testChangeBackground", {
+ step: function() {
+ step();
+ }
+ });
+});
+
+asyncTest( "animateClass works with children", 3, function() {
+ var animatedChild,
+ test = $("div.animateClass"),
+ h2 = test.find("h2");
+
+ test.toggleClass("testChildren", {
+ children: true,
+ duration: duration,
+ complete: function() {
+ equal( h2.css("fontSize"), "20px", "Text size is final during complete");
+ test.toggleClass("testChildren", {
+ duration: duration,
+ complete: function() {
+ equal( h2.css("fontSize"), "10px", "Text size revertted after class removed");
+
+ start();
+ },
+ step: function( val, fx ) {
+ if ( fx.elem === h2[ 0 ] ) {
+ ok( false, "Error - Animating property on h2" );
+ }
+ }
+ });
+ },
+ step: function( val, fx ) {
+ if ( fx.prop === "fontSize" && fx.elem === h2[ 0 ] && !animatedChild ) {
+ equal( fx.end, 20, "animating font size on child" );
+ animatedChild = true;
+ }
+ }
+ });
+});
+
+asyncTest( "animateClass clears style properties when stopped", function() {
+ var test = $("div.animateClass"),
+ style = test[0].style,
+ orig = style.cssText;
+
+ expect( 2 );
+
+ test.addClass( "testChangeBackground", duration );
+ notEqual( orig, style.cssText, "cssText is not the same after starting animation" );
+
+ test.stop( true, true );
+ equal( orig, $.trim( style.cssText ), "cssText is the same after stopping animation midway" );
+ start();
+});
+
+asyncTest( "animateClass: css and class changes during animation are not lost (#7106)", function() {
+ expect( 2 );
+ var test = $( "div.ticket7106" );
+
+ // ensure the class stays and that the css property stays
+ function animationComplete() {
+ ok( test.hasClass( "testClass" ), "class change during animateClass was not lost" );
+ equal( test.height(), 100, "css change during animateClass was not lost" );
+ start();
+ }
+
+ // add a class and change a style property after starting an animated class
+ test.addClass( "animate", minDuration, animationComplete )
+ .addClass( "testClass" )
+ .height( 100 );
+});
+
+
+$.each( $.effects.effect, function( effect ) {
+ module( "effects." + effect );
+
+ // puff and size are defined inside scale
+ if ( effect !== "puff" && effect !== "size" ) {
+ TestHelpers.testJshint( "effect-" + effect );
+ }
+
+ if ( effect === "transfer" ) {
+ return;
+ }
+ asyncTest( "show/hide", function() {
+ expect( 8 );
+ var hidden = $( "div.hidden" ),
+ count = 0,
+ test = 0;
+
+ function queueTest( fn ) {
+ count++;
+ var point = count;
+ return function( next ) {
+ test++;
+ equal( point, test, "Queue function fired in order" );
+ if ( fn ) {
+ fn();
+ } else {
+ setTimeout( next, minDuration );
+ }
+ };
+ }
+
+ hidden.queue( queueTest() ).show( effect, minDuration, queueTest(function() {
+ equal( hidden.css("display"), "block", "Hidden is shown after .show(\"" +effect+ "\", time)" );
+ })).queue( queueTest() ).hide( effect, minDuration, queueTest(function() {
+ equal( hidden.css("display"), "none", "Back to hidden after .hide(\"" +effect+ "\", time)" );
+ })).queue( queueTest(function() {
+ deepEqual( hidden.queue(), ["inprogress"], "Only the inprogress sentinel remains");
+ start();
+ }));
+ });
+
+ asyncTest( "relative width & height - properties are preserved", function() {
+ var test = $("div.relWidth.relHeight"),
+ width = test.width(), height = test.height(),
+ cssWidth = test[0].style.width, cssHeight = test[0].style.height;
+
+ expect( 4 );
+ test.toggle( effect, minDuration, function() {
+ equal( test[0].style.width, cssWidth, "Inline CSS Width has been reset after animation ended" );
+ equal( test[0].style.height, cssHeight, "Inline CSS Height has been rest after animation ended" );
+ start();
+ });
+ equal( test.width(), width, "Width is the same px after animation started" );
+ equal( test.height(), height, "Height is the same px after animation started" );
+ });
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/effects/effects_scale.js b/apps/it/static/js/ui/tests/unit/effects/effects_scale.js
new file mode 100644
index 0000000..6abbcb5
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/effects/effects_scale.js
@@ -0,0 +1,68 @@
+(function( $ ) {
+module( "effect.scale: Scale" );
+
+function run( position, v, h, vo, ho ) {
+ var desc = "End Position Correct: " + position + " (" + v + "," + h + ") - origin: (" + vo + "," + ho + ")";
+ asyncTest( desc, function() {
+ expect( 2 );
+ function complete() {
+ equal( parseInt( test.css( h ), 10 ), target[ h ], "Horizontal Position Correct " + desc );
+ equal( parseInt( test.css( v ), 10 ), target[ v ], "Vertical Position Correct " + desc );
+ start();
+ }
+ var test = $( ".testScale" ),
+ css = {
+ position: position
+ },
+ effect = {
+ effect: "scale",
+ mode: "effect",
+ percent: 200,
+ origin: [ vo, ho ],
+ complete: complete,
+ duration: 1
+ },
+ target = {},
+ relative = position === "relative";
+
+ css[ h ] = 33;
+ css[ v ] = 33;
+ target[ h ] = h === ho ? css[ h ] : ho === "center" ? css[ h ] - 35 : css[ h ] - 70;
+ target[ v ] = v === vo ? css[ v ] : vo === "middle" ? css[ v ] - 35 : css[ v ] - 70;
+ if ( relative && h === "right" ) {
+ target[ h ] += 70;
+ }
+ if ( relative && v === "bottom" ) {
+ target[ v ] += 70;
+ }
+ test.css( css );
+ test.effect( effect );
+ });
+}
+
+function suite( position ) {
+ run( position, "top", "left", "top", "left" );
+ run( position, "top", "left", "middle", "center" );
+ run( position, "top", "left", "bottom", "right" );
+ /* Firefox is currently not capable of supporting detection of bottom and right....
+ run( position, "bottom", "right", "top", "left" );
+ run( position, "bottom", "right", "middle", "center" );
+ run( position, "bottom", "right", "bottom", "right" );
+ */
+}
+
+$(function() {
+ suite( "absolute" );
+ suite( "relative" );
+ var fixedElem = $( "<div>" )
+ .css({
+ position: "fixed",
+ top: 10
+ })
+ .appendTo( "body" );
+ if ( fixedElem.offset().top === 10 ) {
+ suite( "fixed" );
+ }
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/images/jqueryui_32x32.png b/apps/it/static/js/ui/tests/unit/images/jqueryui_32x32.png
new file mode 100644
index 0000000..e003d16
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/images/jqueryui_32x32.png
Binary files differ
diff --git a/apps/it/static/js/ui/tests/unit/index.html b/apps/it/static/js/ui/tests/unit/index.html
new file mode 100644
index 0000000..68784d1
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/index.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Unit Tests</title>
+
+ <link rel="stylesheet" href="../../themes/base/jquery.ui.core.css">
+ <link rel="stylesheet" href="../../themes/base/jquery.ui.theme.css">
+ <link rel="stylesheet" href="../index.css">
+ <script src="../jquery-1.10.2.js"></script>
+ <script src="../index.js"></script>
+</head>
+<body>
+
+<div id="main">
+ <h1>jQuery UI Unit Tests</h1>
+ <div>
+ <h2>Full Test Suite</h2>
+ <ul>
+ <li><a href="all.html">All</a></li>
+ </ul>
+
+ <h2>Core</h2>
+ <ul>
+ <li><a href="core/core.html">Core</a></li>
+ <li><a href="widget/widget.html">Widget</a></li>
+ </ul>
+
+ <h2>Interactions</h2>
+ <ul>
+ <li><a href="draggable/draggable.html">Draggable</a></li>
+ <li><a href="droppable/droppable.html">Droppable</a></li>
+ <li><a href="resizable/resizable.html">Resizable</a></li>
+ <li><a href="selectable/selectable.html">Selectable</a></li>
+ <li><a href="sortable/sortable.html">Sortable</a></li>
+ </ul>
+
+ <h2>Widgets</h2>
+ <ul>
+ <li><a href="accordion/accordion.html">Accordion</a></li>
+ <li><a href="autocomplete/autocomplete.html">Autocomplete</a></li>
+ <li><a href="button/button.html">Button</a></li>
+ <li><a href="datepicker/datepicker.html">Datepicker</a></li>
+ <li><a href="dialog/dialog.html">Dialog</a></li>
+ <li><a href="menu/menu.html">Menu</a></li>
+ <li><a href="progressbar/progressbar.html">Progressbar</a></li>
+ <li><a href="slider/slider.html">Slider</a></li>
+ <li><a href="spinner/spinner.html">Spinner</a></li>
+ <li><a href="tabs/tabs.html">Tabs</a></li>
+ <li><a href="tooltip/tooltip.html">Tooltip</a></li>
+ </ul>
+
+ <h2>Utilities</h2>
+ <ul>
+ <li><a href="position/position.html">Position</a></li>
+ </ul>
+
+ <h2>Effects</h2>
+ <ul>
+ <li><a href="effects/effects.html">Effects</a></li>
+ </ul>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/menu/all.html b/apps/it/static/js/ui/tests/unit/menu/all.html
new file mode 100644
index 0000000..fb41cd8
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Menu Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "menu" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Menu Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/menu/menu.html b/apps/it/static/js/ui/tests/unit/menu/menu.html
new file mode 100644
index 0000000..ed37623
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/menu.html
@@ -0,0 +1,269 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Menu Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.menu" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.menu.js"
+ ]
+ });
+ </script>
+
+ <script src="menu_test_helpers.js"></script>
+ <script src="menu_common.js"></script>
+ <script src="menu_core.js"></script>
+ <script src="menu_events.js"></script>
+ <script src="menu_methods.js"></script>
+ <script src="menu_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+ <style>
+ .ui-menu {
+ font-size: 15px;
+ }
+ #menu3 {
+ height: 250px;
+ overflow: auto;
+ }
+ #menu4, #menu4 ul {
+ height: 250px;
+ overflow: auto;
+ }
+ </style>
+</head>
+<body>
+
+<div id="qunit">jQuery UI Menu Test Suite</div>
+<div id="qunit-fixture">
+
+<ul class="foo" id="menu1">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a id="testID1" class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+</ul>
+
+<ul id="menu2">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#"><span class="ui-icon ui-icon-print"></span>Addyston</a></li>
+ <li>
+ <a href="#">Delphi</a>
+ <ul>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li class="foo"><a class="foo" href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li>
+ <a href="#">Salzburg</a>
+ <ul>
+ <li>
+ <a href="#">Delphi</a>
+ <ul>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li class="foo"><a class="foo" href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">Delphi</a>
+ <ul>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li> - </li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li></li>
+ <li class="foo"><a class="foo" href="#">Salzburg</a></li>
+ <li>&ndash;</li>
+ </ul>
+ </li>
+ <li class="foo"><a class="foo" href="#">Perch</a></li>
+ </ul>
+ </li>
+</ul>
+
+<ul class="foo" id="menu3">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+</ul>
+
+<ul class="foo" id="menu4">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo">
+ <a class="foo" href="#">Ada</a>
+ <ul class="foo">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ </ul>
+ </li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+</ul>
+
+<div id="menu5">
+ <blockquote><a href="#">Aberdeen</a></blockquote>
+ <blockquote><a href="#">Ada</a></blockquote>
+ <blockquote><a href="#">Adamsville</a></blockquote>
+ <blockquote><a href="#">Addyston</a></blockquote>
+ <blockquote>
+ <a href="#">Delphi</a>
+ <div>
+ <blockquote><a href="#">Ada</a></blockquote>
+ <blockquote><a href="#">Saarland</a></blockquote>
+ <blockquote><a href="#">Salzburg</a></blockquote>
+ </div>
+ </blockquote>
+ <blockquote><a href="#">Saarland</a></blockquote>
+ <blockquote>
+ <a href="#">Salzburg</a>
+ <div>
+ <blockquote>
+ <a href="#">Delphi</a>
+ <div>
+ <blockquote><a href="#">Ada</a></blockquote>
+ <blockquote><a id="testID2" href="#">Saarland</a></blockquote>
+ <blockquote><a href="#">Salzburg</a></blockquote>
+ </div>
+ </blockquote>
+ <blockquote>
+ <a href="#">Delphi</a>
+ <div>
+ <blockquote><a href="#">Ada</a></blockquote>
+ <blockquote><a href="#">Saarland</a></blockquote>
+ <blockquote><a href="#">Salzburg</a></blockquote>
+ </div>
+ </blockquote>
+ <blockquote><a href="#">Perch</a></blockquote>
+ </div>
+ </blockquote>
+</div>
+
+<ul id="menu6">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo ui-state-disabled"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="ui-state-disabled">
+ <a id="testID3" href="#">Delphi</a>
+ <ul>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li class="foo"><a class="foo" href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+</ul>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/menu/menu_common.js b/apps/it/static/js/ui/tests/unit/menu/menu_common.js
new file mode 100644
index 0000000..4a89a94
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/menu_common.js
@@ -0,0 +1,20 @@
+TestHelpers.commonWidgetTests( "menu", {
+ defaults: {
+ disabled: false,
+ icons: {
+ submenu: "ui-icon-carat-1-e"
+ },
+ menus: "ul",
+ position: {
+ my: "left top",
+ at: "right top"
+ },
+ role: "menu",
+
+ // callbacks
+ blur: null,
+ create: null,
+ focus: null,
+ select: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/menu/menu_core.js b/apps/it/static/js/ui/tests/unit/menu/menu_core.js
new file mode 100644
index 0000000..923d296
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/menu_core.js
@@ -0,0 +1,48 @@
+(function( $ ) {
+
+module( "menu: core" );
+
+test( "markup structure", function() {
+ expect( 6 );
+ var element = $( "#menu1" ).menu();
+ ok( element.hasClass( "ui-menu" ), "main element is .ui-menu" );
+ element.children().each(function( index ) {
+ ok( $( this ).hasClass( "ui-menu-item" ), "child " + index + " is .ui-menu-item" );
+ });
+});
+
+test( "accessibility", function () {
+ expect( 4 );
+ var element = $( "#menu1" ).menu();
+
+ equal( element.attr( "role" ), "menu", "main role" );
+ ok( !element.attr( "aria-activedescendant" ), "aria-activedescendant not set" );
+
+ element.menu( "focus", $.Event(), element.children().eq( -2 ) );
+ equal( element.attr( "aria-activedescendant" ), "testID1", "aria-activedescendant from existing id" );
+
+ element.menu( "focus", $.Event(), element.children().eq( 0 ) );
+ ok( /^ui-id-\d+$/.test( element.attr( "aria-activedescendant" ) ), "aria-activedescendant from generated id" );
+
+ // Item roles are tested in the role option tests
+});
+
+asyncTest( "#9044: Autofocus issue with dialog opened from menu widget", function() {
+ expect( 1 );
+ var element = $( "#menu1" ).menu();
+
+ $( "<input>", { id: "test9044" } ).appendTo( "body" );
+
+ $( "#testID1" ).bind( "click", function() {
+ $( "#test9044" ).focus();
+ });
+
+ TestHelpers.menu.click( element, "3" );
+ setTimeout( function() {
+ equal( document.activeElement.id, "test9044", "Focus was swallowed by menu" );
+ $( "#test9044" ).remove();
+ start();
+ });
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/menu/menu_events.js b/apps/it/static/js/ui/tests/unit/menu/menu_events.js
new file mode 100644
index 0000000..405300c
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/menu_events.js
@@ -0,0 +1,637 @@
+(function( $ ) {
+
+var log = TestHelpers.menu.log,
+ logOutput = TestHelpers.menu.logOutput,
+ click = TestHelpers.menu.click;
+
+module( "menu: events", {
+ setup: function() {
+ TestHelpers.menu.clearLog();
+ }
+});
+
+test( "handle click on menu", function() {
+ expect( 1 );
+ var element = $( "#menu1" ).menu({
+ select: function() {
+ log();
+ }
+ });
+ log( "click", true );
+ click( element, "1" );
+ log( "afterclick" );
+ click( element, "2" );
+ click( element, "3" );
+ click( element, "1" );
+ equal( logOutput(), "click,1,afterclick,2,3,1", "Click order not valid." );
+});
+
+test( "handle click on custom item menu", function() {
+ expect( 1 );
+ var element = $( "#menu5" ).menu({
+ select: function() {
+ log();
+ },
+ menus: "div"
+ });
+ log( "click", true );
+ click( element, "1" );
+ log( "afterclick" );
+ click( element, "2" );
+ click( element, "3" );
+ click( element, "1" );
+ equal( logOutput(), "click,1,afterclick,2,3,1", "Click order not valid." );
+});
+
+asyncTest( "handle blur", function() {
+ expect( 1 );
+ var blurHandled = false,
+ element = $( "#menu1" ).menu({
+ blur: function( event ) {
+ // Ignore duplicate blur event fired by IE
+ if ( !blurHandled ) {
+ blurHandled = true;
+ equal( event.type, "menublur", "blur event.type is 'menublur'" );
+ }
+ }
+ });
+
+ click( element, "1" );
+ setTimeout(function() {
+ element.blur();
+ setTimeout(function() {
+ start();
+ }, 350 );
+ });
+});
+
+asyncTest( "handle blur via click outside", function() {
+ expect( 1 );
+ var blurHandled = false,
+ element = $( "#menu1" ).menu({
+ blur: function( event ) {
+ // Ignore duplicate blur event fired by IE
+ if ( !blurHandled ) {
+ blurHandled = true;
+ equal( event.type, "menublur", "blur event.type is 'menublur'" );
+ }
+ }
+ });
+
+ click( element, "1" );
+ setTimeout(function() {
+ $( "<a>", { id: "remove"} ).appendTo( "body" ).trigger( "click" );
+ setTimeout(function() {
+ start();
+ }, 350 );
+ });
+});
+
+asyncTest( "handle focus of menu with active item", function() {
+ expect( 1 );
+ var element = $( "#menu1" ).menu({
+ focus: function( event ) {
+ log( $( event.target ).find( ".ui-state-focus" ).parent().index() );
+ }
+ });
+
+ log( "focus", true );
+ element[ 0 ].focus();
+ setTimeout(function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element[ 0 ].blur();
+ setTimeout(function() {
+ element[ 0 ].focus();
+ setTimeout(function() {
+ equal( logOutput(), "focus,0,1,2,2", "current active item remains active" );
+ start();
+ });
+ });
+ });
+});
+
+asyncTest( "handle submenu auto collapse: mouseleave", function() {
+ expect( 4 );
+ var element = $( "#menu2" ).menu(),
+ event = $.Event( "mouseenter" );
+
+ function menumouseleave1() {
+ equal( element.find( "ul[aria-expanded='true']" ).length, 1, "first submenu expanded" );
+ element.menu( "focus", event, element.find( "li:nth-child(7) li:first" ) );
+ setTimeout( menumouseleave2, 350 );
+ }
+ function menumouseleave2() {
+ equal( element.find( "ul[aria-expanded='true']" ).length, 2, "second submenu expanded" );
+ element.find( "ul[aria-expanded='true']:first" ).trigger( "mouseleave" );
+ setTimeout( menumouseleave3, 350 );
+ }
+ function menumouseleave3() {
+ equal( element.find( "ul[aria-expanded='true']" ).length, 1, "second submenu collapsed" );
+ element.trigger( "mouseleave" );
+ setTimeout( menumouseleave4, 350 );
+ }
+ function menumouseleave4() {
+ equal( element.find( "ul[aria-expanded='true']" ).length, 0, "first submenu collapsed" );
+ start();
+ }
+
+ element.find( "li:nth-child(7)" ).trigger( "mouseenter" );
+ setTimeout( menumouseleave1, 350 );
+});
+
+asyncTest( "handle submenu auto collapse: mouseleave", function() {
+ expect( 4 );
+ var element = $( "#menu5" ).menu({ menus: "div" }),
+ event = $.Event( "mouseenter" );
+
+ function menumouseleave1() {
+ equal( element.find( "div[aria-expanded='true']" ).length, 1, "first submenu expanded" );
+ element.menu( "focus", event, element.find( ":nth-child(7)" ).find( "div" ).eq( 0 ).children().eq( 0 ) );
+ setTimeout( menumouseleave2, 350 );
+ }
+ function menumouseleave2() {
+ equal( element.find( "div[aria-expanded='true']" ).length, 2, "second submenu expanded" );
+ element.find( "div[aria-expanded='true']:first" ).trigger( "mouseleave" );
+ setTimeout( menumouseleave3, 350 );
+ }
+ function menumouseleave3() {
+ equal( element.find( "div[aria-expanded='true']" ).length, 1, "second submenu collapsed" );
+ element.trigger( "mouseleave" );
+ setTimeout( menumouseleave4, 350 );
+ }
+ function menumouseleave4() {
+ equal( element.find( "div[aria-expanded='true']" ).length, 0, "first submenu collapsed" );
+ start();
+ }
+
+ element.find( ":nth-child(7)" ).trigger( "mouseenter" );
+ setTimeout( menumouseleave1, 350 );
+});
+
+
+asyncTest( "handle keyboard navigation on menu without scroll and without submenus", function() {
+ expect( 12 );
+ var element = $( "#menu1" ).menu({
+ select: function( event, ui ) {
+ log( $( ui.item[ 0 ] ).text() );
+ },
+ focus: function( event ) {
+ log( $( event.target ).find( ".ui-state-focus" ).parent().index() );
+ }
+ });
+
+ log( "keydown", true );
+ element[ 0 ].focus();
+ setTimeout(function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( logOutput(), "keydown,0,1,2", "Keydown DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal( logOutput(), "keydown,1", "Keydown UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal( logOutput(), "keydown", "Keydown LEFT (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal( logOutput(), "keydown", "Keydown RIGHT (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown,4", "Keydown PAGE_DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown", "Keydown PAGE_DOWN (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown,0", "Keydown PAGE_UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown", "Keydown PAGE_UP (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equal( logOutput(), "keydown,4", "Keydown END" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equal( logOutput(), "keydown,0", "Keydown HOME" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equal( logOutput(), "keydown", "Keydown ESCAPE (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equal( logOutput(), "keydown,Aberdeen", "Keydown ENTER" );
+
+ start();
+ });
+});
+
+asyncTest( "handle keyboard navigation on menu without scroll and with submenus", function() {
+ expect( 16 );
+ var element = $( "#menu2" ).menu({
+ select: function( event, ui ) {
+ log( $( ui.item[0] ).text() );
+ },
+ focus: function( event ) {
+ log( $( event.target ).find( ".ui-state-focus" ).parent().index() );
+ }
+ });
+
+ log( "keydown", true );
+ element.one( "menufocus", function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( logOutput(), "keydown,1,2", "Keydown DOWN" );
+ setTimeout( menukeyboard1, 50 );
+ });
+ element.focus();
+
+ function menukeyboard1() {
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal( logOutput(), "keydown,1,0", "Keydown UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal( logOutput(), "keydown", "Keydown LEFT (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+
+ setTimeout(function() {
+ equal( logOutput(), "keydown,1,2,3,4,0", "Keydown RIGHT (open submenu)" );
+ setTimeout( menukeyboard2, 50 );
+ }, 50 );
+ }
+
+ function menukeyboard2() {
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal( logOutput(), "keydown,4", "Keydown LEFT (close submenu)" );
+
+ // re-open submenu
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ setTimeout( menukeyboard3, 50 );
+ }
+
+ function menukeyboard3() {
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown,2", "Keydown PAGE_DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown", "Keydown PAGE_DOWN (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown,0", "Keydown PAGE_UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown", "Keydown PAGE_UP (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equal( logOutput(), "keydown,2", "Keydown END" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equal( logOutput(), "keydown,0", "Keydown HOME" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equal( logOutput(), "keydown,4", "Keydown ESCAPE (close submenu)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.SPACE } );
+ setTimeout( menukeyboard4, 50 );
+ }
+
+ function menukeyboard4() {
+ equal( logOutput(), "keydown,0", "Keydown SPACE (open submenu)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equal( logOutput(), "keydown,4", "Keydown ESCAPE (close submenu)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ setTimeout( function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ setTimeout( function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( logOutput(), "keydown,5,6,0,1,0,2,4,0", "Keydown skip dividers and items without anchors" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ setTimeout( menukeyboard6, 50 );
+ }, 50 );
+ }, 50 );
+ }
+
+ function menukeyboard6() {
+ equal( logOutput(), "keydown,Ada", "Keydown ENTER (open submenu)" );
+ start();
+ }
+});
+
+asyncTest( "handle keyboard navigation on menu with scroll and without submenus", function() {
+ expect( 14 );
+ var element = $( "#menu3" ).menu({
+ select: function( event, ui ) {
+ log( $( ui.item[ 0 ] ).text() );
+ },
+ focus: function( event ) {
+ log( $( event.target ).find( ".ui-state-focus" ).parent().index());
+ }
+ });
+
+ log( "keydown", true );
+ element[ 0 ].focus();
+ setTimeout(function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( logOutput(), "keydown,0,1,2", "Keydown DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal( logOutput(), "keydown,1,0", "Keydown UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal( logOutput(), "keydown", "Keydown LEFT (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal( logOutput(), "keydown", "Keydown RIGHT (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown,10", "Keydown PAGE_DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown,20", "Keydown PAGE_DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown,10", "Keydown PAGE_UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown,0", "Keydown PAGE_UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown", "Keydown PAGE_UP (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equal( logOutput(), "keydown,37", "Keydown END" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown", "Keydown PAGE_DOWN (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equal( logOutput(), "keydown,0", "Keydown HOME" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equal( logOutput(), "keydown", "Keydown ESCAPE (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equal( logOutput(), "keydown,Aberdeen", "Keydown ENTER" );
+
+ start();
+ });
+});
+
+asyncTest( "handle keyboard navigation on menu with scroll and with submenus", function() {
+ expect( 14 );
+ var element = $( "#menu4" ).menu({
+ select: function( event, ui ) {
+ log( $( ui.item[ 0 ] ).text() );
+ },
+ focus: function( event ) {
+ log( $( event.target ).find( ".ui-state-focus" ).parent().index());
+ }
+ });
+
+ log( "keydown", true );
+ element.one( "menufocus", function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( logOutput(), "keydown,1,2", "Keydown DOWN" );
+ setTimeout( menukeyboard1, 50 );
+ });
+ element.focus();
+
+ function menukeyboard1() {
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal( logOutput(), "keydown,1,0", "Keydown UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal( logOutput(), "keydown", "Keydown LEFT (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+
+ setTimeout( function() {
+ equal( logOutput(), "keydown,1,0", "Keydown RIGHT (open submenu)" );
+ }, 50 );
+ setTimeout( menukeyboard2, 50 );
+ }
+
+ function menukeyboard2() {
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal( logOutput(), "keydown,1", "Keydown LEFT (close submenu)" );
+
+ // re-open submenu
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ setTimeout( menukeyboard3, 50 );
+ }
+
+ function menukeyboard3() {
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown,10", "Keydown PAGE_DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal( logOutput(), "keydown,20", "Keydown PAGE_DOWN" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown,10", "Keydown PAGE_UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal( logOutput(), "keydown,0", "Keydown PAGE_UP" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equal( logOutput(), "keydown,27", "Keydown END" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equal( logOutput(), "keydown,0", "Keydown HOME" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equal( logOutput(), "keydown,1", "Keydown ESCAPE (close submenu)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ setTimeout( menukeyboard4, 50 );
+ }
+
+ function menukeyboard4() {
+ equal( logOutput(), "keydown,0", "Keydown ENTER (open submenu)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equal( logOutput(), "keydown,Aberdeen", "Keydown ENTER (select item)" );
+
+ start();
+ }
+});
+
+asyncTest( "handle keyboard navigation and mouse click on menu with disabled items", function() {
+ expect( 6 );
+ var element = $( "#menu6" ).menu({
+ select: function( event, ui ) {
+ log( $( ui.item[0] ).text() );
+ },
+ focus: function( event ) {
+ log( $( event.target ).find( ".ui-state-focus" ).parent().index());
+ }
+ });
+
+ log( "keydown", true );
+ element.one( "menufocus", function() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equal( logOutput(), "keydown,1", "Keydown focus but not select disabled item" );
+ setTimeout( menukeyboard1, 50 );
+ });
+ element.focus();
+
+ function menukeyboard1() {
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( logOutput(), "keydown,2,3,4", "Keydown focus disabled item with submenu" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal( logOutput(), "keydown", "Keydown LEFT (no effect)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+
+ setTimeout( function() {
+ equal( logOutput(), "keydown", "Keydown RIGHT (no effect on disabled sub-menu)" );
+
+ log( "keydown", true );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+
+ setTimeout( function() {
+ equal( logOutput(), "keydown", "Keydown ENTER (no effect on disabled sub-menu)" );
+ log( "click", true );
+ click( element, "1" );
+ equal( logOutput(), "click", "Click disabled item (no effect)" );
+ start();
+ }, 50 );
+ }, 50 );
+ }
+});
+
+asyncTest( "handle keyboard navigation with spelling of menu items", function() {
+ expect( 2 );
+ var element = $( "#menu2" ).menu({
+ focus: function( event ) {
+ log( $( event.target ).find( ".ui-state-focus" ).parent().index() );
+ }
+ });
+
+ log( "keydown", true );
+ element.one( "menufocus", function() {
+ element.simulate( "keydown", { keyCode: 65 } );
+ element.simulate( "keydown", { keyCode: 68 } );
+ element.simulate( "keydown", { keyCode: 68 } );
+ equal( logOutput(), "keydown,0,1,3", "Keydown focus Addyston by spelling the first 3 letters" );
+ element.simulate( "keydown", { keyCode: 68 } );
+ equal( logOutput(), "keydown,0,1,3,4", "Keydown focus Delphi by repeating the 'd' again" );
+ start();
+ });
+ element[ 0 ].focus();
+});
+
+test( "ensure default is prevented when clicking on anchors in disabled menus ", function() {
+ expect( 1 );
+ var element = $( "#menu1" ).menu();
+ element.bind( "click.menu", function(event) {
+ if ( !event.isDefaultPrevented() ) {
+ log();
+ }
+ });
+ log( "click", true );
+ click( element, "1" );
+ log( "afterclick,disable" );
+ element.menu( "option", "disabled", true );
+ click( element, "2" );
+ click( element, "3" );
+ click( element, "1" );
+ log( "enable" );
+ element.menu( "option", "disabled", false );
+ click( element, "3" );
+ equal( logOutput(), "click,1,afterclick,disable,enable,3", "Click order not valid." );
+});
+
+test( "#9469: Stopping propagation in a select event should not suppress subsequent select events.", function() {
+ expect( 1 );
+ var element = $( "#menu1" ).menu({
+ select: function( event ) {
+ log();
+ event.stopPropagation();
+ }
+ });
+
+ click( element, "1" );
+ click( element, "2" );
+
+ equal( logOutput(), "1,2", "Both select events were not triggered." );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/menu/menu_methods.js b/apps/it/static/js/ui/tests/unit/menu/menu_methods.js
new file mode 100644
index 0000000..51d7729
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/menu_methods.js
@@ -0,0 +1,117 @@
+(function( $ ) {
+
+var log = TestHelpers.menu.log,
+ logOutput = TestHelpers.menu.logOutput,
+ click = TestHelpers.menu.click;
+
+module( "menu: methods", {
+ setup: function() {
+ TestHelpers.menu.clearLog();
+ }
+});
+
+test( "destroy", function() {
+ expect( 4 );
+ domEqual( "#menu1", function() {
+ $( "#menu1" ).menu().menu( "destroy" );
+ });
+ domEqual( "#menu2", function() {
+ $( "#menu2" ).menu().menu( "destroy" );
+ });
+ domEqual( "#menu5", function() {
+ $( "#menu5").menu().menu( "destroy" );
+ });
+ domEqual( "#menu6", function() {
+ $( "#menu6" ).menu().menu( "destroy" );
+ });
+});
+
+test( "enable/disable", function() {
+ expect( 3 );
+ var element = $( "#menu1" ).menu({
+ select: function() {
+ log();
+ }
+ });
+ element.menu( "disable" );
+ ok( element.is( ".ui-state-disabled" ), "Missing ui-state-disabled class" );
+ log( "click", true );
+ click( element, "1" );
+ log( "afterclick" );
+ element.menu( "enable" );
+ ok( element.not( ".ui-state-disabled" ), "Has ui-state-disabled class" );
+ log( "click" );
+ click( element, "1" );
+ log( "afterclick" );
+ equal( logOutput(), "click,afterclick,click,1,afterclick", "Click order not valid." );
+});
+
+test( "refresh", function() {
+ expect( 5 );
+ var element = $( "#menu1" ).menu();
+ equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" );
+ element.append( "<li><a href='#'>test item</a></li>" ).menu( "refresh" );
+ equal( element.find( ".ui-menu-item" ).length, 6, "Incorrect number of menu items" );
+ element.find( ".ui-menu-item:last" ).remove().end().menu( "refresh" );
+ equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" );
+ element.append( "<li>---</li>" ).menu( "refresh" );
+ equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" );
+ element.children( ":last" ).remove().end().menu( "refresh" );
+ equal( element.find( ".ui-menu-item" ).length, 5, "Incorrect number of menu items" );
+});
+
+test( "refresh submenu", function() {
+ expect( 2 );
+ var element = $( "#menu2" ).menu();
+ equal( element.find( "ul:first .ui-menu-item" ).length, 3 );
+ element.find( "ul" ).addBack().append( "<li><a href=\"#\">New Item</a></li>" );
+ element.menu( "refresh" );
+ equal( element.find( "ul:first .ui-menu-item" ).length, 4 );
+});
+
+test( "refresh icons (see #9377)", function() {
+ expect( 3 );
+ var element = $( "#menu1" ).menu();
+ ok( !element.hasClass( "ui-menu-icons") );
+ element.find( "li:first a" ).html( "<span class='ui-icon ui-icon-disk'></span>Save</a>" );
+ element.menu( "refresh" );
+
+ ok( element.hasClass( "ui-menu-icons" ) );
+ element.find( "li:first a" ).html( "Save" );
+ element.menu( "refresh" );
+ ok( !element.hasClass( "ui-menu-icons" ) );
+});
+
+test( "widget", function() {
+ expect( 2 );
+ var element = $( "#menu1" ).menu(),
+ widgetElement = element.menu( "widget" );
+ equal( widgetElement.length, 1, "one element" );
+ strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" );
+});
+
+// TODO: test focus method
+
+// TODO: test blur method
+
+// TODO: test collapseAll method
+
+// TODO: test collapse method
+
+// TODO: test expand method
+
+// TODO: test next method
+
+// TODO: test prev method
+
+// TODO: test isFirstItem method
+
+// TODO: test isLastItem method
+
+// TODO: test nextPage method
+
+// TODO: test prevPage method
+
+// TODO: test select method
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/menu/menu_options.js b/apps/it/static/js/ui/tests/unit/menu/menu_options.js
new file mode 100644
index 0000000..27cea67
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/menu_options.js
@@ -0,0 +1,115 @@
+(function( $ ) {
+
+var log = TestHelpers.menu.log,
+ logOutput = TestHelpers.menu.logOutput,
+ click = TestHelpers.menu.click;
+
+module( "menu: options", {
+ setup: function() {
+ TestHelpers.menu.clearLog();
+ }
+});
+
+test( "{ disabled: true }", function() {
+ expect( 2 );
+ var element = $( "#menu1" ).menu({
+ disabled: true,
+ select: function() {
+ log();
+ }
+ });
+ ok( element.hasClass( "ui-state-disabled" ), "Missing ui-state-disabled class" );
+ log( "click", true );
+ click( element, "1" );
+ log( "afterclick" );
+ equal( logOutput(), "click,afterclick", "Click order not valid." );
+});
+
+test( "{ disabled: false }", function() {
+ expect( 2 );
+ var element = $( "#menu1" ).menu({
+ disabled: false,
+ select: function() {
+ log();
+ }
+ });
+ ok( !element.hasClass( "ui-state-disabled" ), "Has ui-state-disabled class" );
+ log( "click", true );
+ click( element, "1" );
+ log( "afterclick" );
+ equal( logOutput(), "click,1,afterclick", "Click order not valid." );
+});
+
+test( "{ icons: default }", function() {
+ expect( 2 );
+ var element = $( "#menu2" ).menu();
+ equal( element.find( ".ui-menu-icon" ).attr( "class" ), "ui-menu-icon ui-icon ui-icon-carat-1-e" );
+
+ element.menu( "option", "icons.submenu", "ui-icon-triangle-1-e" );
+ equal( element.find( ".ui-menu-icon" ).attr( "class" ), "ui-menu-icon ui-icon ui-icon-triangle-1-e" );
+});
+
+test( "{ icons: { submenu: 'custom' } }", function() {
+ expect( 1 );
+ var element = $( "#menu2" ).menu({
+ icons: {
+ submenu: "custom-class"
+ }
+ });
+ equal( element.find( ".ui-menu-icon" ).attr( "class" ), "ui-menu-icon ui-icon custom-class" );
+});
+
+// TODO: test menus option
+
+// TODO: test position option
+
+test( "{ role: 'menu' } ", function() {
+ var element = $( "#menu1" ).menu(),
+ items = element.find( "li" );
+ expect( 2 + 5 * items.length );
+ equal( element.attr( "role" ), "menu" );
+ ok( items.length > 0, "number of menu items" );
+ items.each(function( item ) {
+ ok( $( this ).hasClass( "ui-menu-item" ), "menu item ("+ item + ") class for item" );
+ equal( $( this ).attr( "role" ), "presentation", "menu item ("+ item + ") role" );
+ equal( $( "a", this ).attr( "role" ), "menuitem", "menu item ("+ item + ") role" );
+ ok( $( "a", this ).hasClass( "ui-corner-all" ), "a element class for menu item ("+ item + ")" );
+ equal( $( "a", this ).attr( "tabindex" ), "-1", "a element tabindex for menu item ("+ item + ")" );
+ });
+});
+
+test( "{ role: 'listbox' } ", function() {
+ var element = $( "#menu1" ).menu({
+ role: "listbox"
+ }),
+ items = element.find( "li" );
+ expect( 2 + 5 * items.length );
+ equal( element.attr( "role" ), "listbox" );
+ ok( items.length > 0, "number of menu items" );
+ items.each(function( item ) {
+ ok( $( this ).hasClass( "ui-menu-item" ), "menu item ("+ item + ") class for item" );
+ equal( $( this ).attr( "role" ), "presentation", "menu item ("+ item + ") role" );
+ equal( $( "a", this ).attr( "role" ), "option", "menu item ("+ item + ") role" );
+ ok( $( "a", this ).hasClass( "ui-corner-all" ), "a element class for menu item ("+ item + ")" );
+ equal( $( "a", this ).attr( "tabindex" ), "-1", "a element tabindex for menu item ("+ item + ")" );
+ });
+});
+
+test( "{ role: null }", function() {
+ var element = $( "#menu1" ).menu({
+ role: null
+ }),
+ items = element.find( "li" );
+ expect( 2 + 5 * items.length );
+ strictEqual( element.attr( "role" ), undefined );
+ ok( items.length > 0, "number of menu items" );
+ items.each(function( item ) {
+ ok( $( this ).hasClass( "ui-menu-item" ), "menu item ("+ item + ") class for item" );
+ equal( $( this ).attr( "role" ), "presentation", "menu item ("+ item + ") role" );
+ equal( $( "a", this ).attr( "role" ), undefined, "menu item ("+ item + ") role" );
+ ok( $( "a", this ).hasClass( "ui-corner-all" ), "a element class for menu item ("+ item + ")" );
+ equal( $( "a", this ).attr( "tabindex" ), "-1", "a element tabindex for menu item ("+ item + ")" );
+ });
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/menu/menu_test_helpers.js b/apps/it/static/js/ui/tests/unit/menu/menu_test_helpers.js
new file mode 100644
index 0000000..b6c09ad
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/menu/menu_test_helpers.js
@@ -0,0 +1,31 @@
+(function() {
+
+var lastItem,
+ log = [];
+
+TestHelpers.menu = {
+ log: function( message, clear ) {
+ if ( clear ) {
+ log.length = 0;
+ }
+ if ( message === undefined ) {
+ message = lastItem;
+ }
+ log.push( $.trim( message ) );
+ },
+
+ logOutput: function() {
+ return log.join( "," );
+ },
+
+ clearLog: function() {
+ log.length = 0;
+ },
+
+ click: function( menu, item ) {
+ lastItem = item;
+ menu.children( ":eq(" + item + ")" ).find( "a:first" ).trigger( "click" );
+ }
+};
+
+})();
diff --git a/apps/it/static/js/ui/tests/unit/position/all.html b/apps/it/static/js/ui/tests/unit/position/all.html
new file mode 100644
index 0000000..d866c6a
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/position/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Position Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "position" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Position Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/position/position.html b/apps/it/static/js/ui/tests/unit/position/position.html
new file mode 100644
index 0000000..f3b1ad8
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/position/position.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Position Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ js: [ "ui/jquery.ui.position.js" ]
+ });
+ </script>
+
+ <script src="position_core.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+<div id="qunit" style="position:relative; z-index:2;"></div>
+
+<!--
+elements smaller than 20px have a line-height set on them to avoid a bug in IE6
+.height() returns the greater of the height and line-height
+-->
+
+<div id="qunit-fixture" style="top: 0; left: 0; z-index:1">
+ <div id="el1" style="position: absolute; width: 6px; height: 6px; line-height: 6px;"></div>
+ <div id="el2" style="position: absolute; width: 6px; height: 6px; line-height: 6px;"></div>
+ <div id="parent" style="position: absolute; width: 6px; height: 6px; top: 4px; left: 4px; line-height: 6px;"></div>
+ <div id="within" style="position: absolute; width: 12px; height: 12px; top: 2px; left: 0px; line-height: 12px;"></div>
+
+ <div id="scrollx" style="position: absolute; top: 0px; left: 0px">
+ <div id="elx" style="position: absolute; width: 10px; height: 10px; line-height: 10px;"></div>
+ <div id="parentx" style="position: absolute; width: 20px; height: 20px; top: 40px; left: 40px;"></div>
+ </div>
+
+ <div style="position: absolute; height: 5000px; width: 5000px;"></div>
+
+ <div id="fractions-parent" style="position: absolute; left: 10.7432222px; top: 10.532325px; height: 30px; width: 201px;">
+ <div id="fractions-element"></div>
+ </div>
+
+ <div id="bug-5280" style="height: 30px; width: 201px;">
+ <div style="width: 50px; height: 10px;"></div>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/position/position_core.js b/apps/it/static/js/ui/tests/unit/position/position_core.js
new file mode 100644
index 0000000..5b1872a
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/position/position_core.js
@@ -0,0 +1,729 @@
+(function( $ ) {
+
+var win = $( window ),
+ scrollTopSupport = function() {
+ var support = win.scrollTop( 1 ).scrollTop() === 1;
+ win.scrollTop( 0 );
+ scrollTopSupport = function() {
+ return support;
+ };
+ return support;
+ };
+
+module( "position", {
+ setup: function() {
+ win.scrollTop( 0 ).scrollLeft( 0 );
+ }
+});
+
+TestHelpers.testJshint( "position" );
+
+test( "my, at, of", function() {
+ expect( 4 );
+
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left top",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 40, left: 40 }, "left top, left top" );
+
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left bottom",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 60, left: 40 }, "left top, left bottom" );
+
+ $( "#elx" ).position({
+ my: "left",
+ at: "bottom",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 55, left: 50 }, "left, bottom" );
+
+ $( "#elx" ).position({
+ my: "left foo",
+ at: "bar baz",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 45, left: 50 }, "left foo, bar baz" );
+});
+
+test( "multiple elements", function() {
+ expect( 3 );
+
+ var elements = $( "#el1, #el2" ),
+ result = elements.position({
+ my: "left top",
+ at: "left bottom",
+ of: "#parent",
+ collision: "none"
+ }),
+ expected = { top: 10, left: 4 };
+
+ deepEqual( result, elements );
+ elements.each(function() {
+ deepEqual( $( this ).offset(), expected );
+ });
+});
+
+test( "positions", function() {
+ expect( 18 );
+
+ var offsets = {
+ left: 0,
+ center: 3,
+ right: 6,
+ top: 0,
+ bottom: 6
+ },
+ start = { left: 4, top: 4 },
+ el = $( "#el1" );
+
+ $.each( [ 0, 1 ], function( my ) {
+ $.each( [ "top", "center", "bottom" ], function( vindex, vertical ) {
+ $.each( [ "left", "center", "right" ], function( hindex, horizontal ) {
+ var _my = my ? horizontal + " " + vertical : "left top",
+ _at = !my ? horizontal + " " + vertical : "left top";
+ el.position({
+ my: _my,
+ at: _at,
+ of: "#parent",
+ collision: "none"
+ });
+ deepEqual( el.offset(), {
+ top: start.top + offsets[ vertical ] * (my ? -1 : 1),
+ left: start.left + offsets[ horizontal ] * (my ? -1 : 1)
+ }, "Position via " + QUnit.jsDump.parse({ my: _my, at: _at }) );
+ });
+ });
+ });
+});
+
+test( "of", function() {
+ expect( 9 + (scrollTopSupport() ? 1 : 0) );
+
+ var event;
+
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left top",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 40, left: 40 }, "selector" );
+
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left bottom",
+ of: $( "#parentx"),
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 60, left: 40 }, "jQuery object" );
+
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left top",
+ of: $( "#parentx" )[ 0 ],
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 40, left: 40 }, "DOM element" );
+
+ $( "#elx" ).position({
+ my: "right bottom",
+ at: "right bottom",
+ of: document,
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), {
+ top: $( document ).height() - 10,
+ left: $( document ).width() - 10
+ }, "document" );
+
+ $( "#elx" ).position({
+ my: "right bottom",
+ at: "right bottom",
+ of: $( document ),
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), {
+ top: $( document ).height() - 10,
+ left: $( document ).width() - 10
+ }, "document as jQuery object" );
+
+ win.scrollTop( 0 );
+
+ $( "#elx" ).position({
+ my: "right bottom",
+ at: "right bottom",
+ of: window,
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), {
+ top: win.height() - 10,
+ left: win.width() - 10
+ }, "window" );
+
+ $( "#elx" ).position({
+ my: "right bottom",
+ at: "right bottom",
+ of: win,
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), {
+ top: win.height() - 10,
+ left: win.width() - 10
+ }, "window as jQuery object" );
+
+ if ( scrollTopSupport() ) {
+ win.scrollTop( 500 ).scrollLeft( 200 );
+ $( "#elx" ).position({
+ my: "right bottom",
+ at: "right bottom",
+ of: window,
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), {
+ top: win.height() + 500 - 10,
+ left: win.width() + 200 - 10
+ }, "window, scrolled" );
+ win.scrollTop( 0 ).scrollLeft( 0 );
+ }
+
+ event = $.extend( $.Event( "someEvent" ), { pageX: 200, pageY: 300 } );
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left top",
+ of: event,
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), {
+ top: 300,
+ left: 200
+ }, "event - left top, left top" );
+
+ event = $.extend( $.Event( "someEvent" ), { pageX: 400, pageY: 600 } );
+ $( "#elx" ).position({
+ my: "left top",
+ at: "right bottom",
+ of: event,
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), {
+ top: 600,
+ left: 400
+ }, "event - left top, right bottom" );
+});
+
+test( "offsets", function() {
+ expect( 9 );
+
+ var offset;
+
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left+10 bottom+10",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 70, left: 50 }, "offsets in at" );
+
+ $( "#elx" ).position({
+ my: "left+10 top-10",
+ at: "left bottom",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 50, left: 50 }, "offsets in my" );
+
+ $( "#elx" ).position({
+ my: "left top",
+ at: "left+50% bottom-10%",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 58, left: 50 }, "percentage offsets in at" );
+
+ $( "#elx" ).position({
+ my: "left-30% top+50%",
+ at: "left bottom",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 65, left: 37 }, "percentage offsets in my" );
+
+ $( "#elx" ).position({
+ my: "left-30.001% top+50.0%",
+ at: "left bottom",
+ of: "#parentx",
+ collision: "none"
+ });
+ offset = $( "#elx" ).offset();
+ equal( Math.round( offset.top ), 65, "decimal percentage offsets in my" );
+ equal( Math.round( offset.left ), 37, "decimal percentage offsets in my" );
+
+ $( "#elx" ).position({
+ my: "left+10.4 top-10.6",
+ at: "left bottom",
+ of: "#parentx",
+ collision: "none"
+ });
+ offset = $( "#elx" ).offset();
+ equal( Math.round( offset.top ), 49, "decimal offsets in my" );
+ equal( Math.round( offset.left ), 50, "decimal offsets in my" );
+
+ $( "#elx" ).position({
+ my: "left+right top-left",
+ at: "left-top bottom-bottom",
+ of: "#parentx",
+ collision: "none"
+ });
+ deepEqual( $( "#elx" ).offset(), { top: 60, left: 40 }, "invalid offsets" );
+});
+
+test( "using", function() {
+ expect( 10 );
+
+ var count = 0,
+ elems = $( "#el1, #el2" ),
+ of = $( "#parentx" ),
+ expectedPosition = { top: 60, left: 60 },
+ expectedFeedback = {
+ target: {
+ element: of,
+ width: 20,
+ height: 20,
+ left: 40,
+ top: 40
+ },
+ element: {
+ width: 6,
+ height: 6,
+ left: 60,
+ top: 60
+ },
+ horizontal: "left",
+ vertical: "top",
+ important: "vertical"
+ },
+ originalPosition = elems.position({
+ my: "right bottom",
+ at: "rigt bottom",
+ of: "#parentx",
+ collision: "none"
+ }).offset();
+
+ elems.position({
+ my: "left top",
+ at: "center+10 bottom",
+ of: "#parentx",
+ using: function( position, feedback ) {
+ deepEqual( this, elems[ count ], "correct context for call #" + count );
+ deepEqual( position, expectedPosition, "correct position for call #" + count );
+ deepEqual( feedback.element.element[ 0 ], elems[ count ] );
+ delete feedback.element.element;
+ deepEqual( feedback, expectedFeedback );
+ count++;
+ }
+ });
+
+ elems.each(function() {
+ deepEqual( $( this ).offset(), originalPosition, "elements not moved" );
+ });
+});
+
+function collisionTest( config, result, msg ) {
+ var elem = $( "#elx" ).position( $.extend({
+ my: "left top",
+ at: "right bottom",
+ of: "#parent"
+ }, config ) );
+ deepEqual( elem.offset(), result, msg );
+}
+
+function collisionTest2( config, result, msg ) {
+ collisionTest( $.extend({
+ my: "right bottom",
+ at: "left top"
+ }, config ), result, msg );
+}
+
+test( "collision: fit, no collision", function() {
+ expect( 2 );
+
+ collisionTest({
+ collision: "fit"
+ }, {
+ top: 10,
+ left: 10
+ }, "no offset" );
+
+ collisionTest({
+ collision: "fit",
+ at: "right+2 bottom+3"
+ }, {
+ top: 13,
+ left: 12
+ }, "with offset" );
+});
+
+// Currently failing in IE8 due to the iframe used by TestSwarm
+if ( !/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ) ) {
+test( "collision: fit, collision", function() {
+ expect( 2 + (scrollTopSupport() ? 1 : 0) );
+
+ collisionTest2({
+ collision: "fit"
+ }, {
+ top: 0,
+ left: 0
+ }, "no offset" );
+
+ collisionTest2({
+ collision: "fit",
+ at: "left+2 top+3"
+ }, {
+ top: 0,
+ left: 0
+ }, "with offset" );
+
+ if ( scrollTopSupport() ) {
+ win.scrollTop( 300 ).scrollLeft( 200 );
+ collisionTest({
+ collision: "fit"
+ }, {
+ top: 300,
+ left: 200
+ }, "window scrolled" );
+
+ win.scrollTop( 0 ).scrollLeft( 0 );
+ }
+});
+}
+
+test( "collision: flip, no collision", function() {
+ expect( 2 );
+
+ collisionTest({
+ collision: "flip"
+ }, {
+ top: 10,
+ left: 10
+ }, "no offset" );
+
+ collisionTest({
+ collision: "flip",
+ at: "right+2 bottom+3"
+ }, {
+ top: 13,
+ left: 12
+ }, "with offset" );
+});
+
+test( "collision: flip, collision", function() {
+ expect( 2 );
+
+ collisionTest2({
+ collision: "flip"
+ }, {
+ top: 10,
+ left: 10
+ }, "no offset" );
+
+ collisionTest2({
+ collision: "flip",
+ at: "left+2 top+3"
+ }, {
+ top: 7,
+ left: 8
+ }, "with offset" );
+});
+
+test( "collision: flipfit, no collision", function() {
+ expect( 2 );
+
+ collisionTest({
+ collision: "flipfit"
+ }, {
+ top: 10,
+ left: 10
+ }, "no offset" );
+
+ collisionTest({
+ collision: "flipfit",
+ at: "right+2 bottom+3"
+ }, {
+ top: 13,
+ left: 12
+ }, "with offset" );
+});
+
+test( "collision: flipfit, collision", function() {
+ expect( 2 );
+
+ collisionTest2({
+ collision: "flipfit"
+ }, {
+ top: 10,
+ left: 10
+ }, "no offset" );
+
+ collisionTest2({
+ collision: "flipfit",
+ at: "left+2 top+3"
+ }, {
+ top: 7,
+ left: 8
+ }, "with offset" );
+});
+
+test( "collision: none, no collision", function() {
+ expect( 2 );
+
+ collisionTest({
+ collision: "none"
+ }, {
+ top: 10,
+ left: 10
+ }, "no offset" );
+
+ collisionTest({
+ collision: "none",
+ at: "right+2 bottom+3"
+ }, {
+ top: 13,
+ left: 12
+ }, "with offset" );
+});
+
+test( "collision: none, collision", function() {
+ expect( 2 );
+
+ collisionTest2({
+ collision: "none"
+ }, {
+ top: -6,
+ left: -6
+ }, "no offset" );
+
+ collisionTest2({
+ collision: "none",
+ at: "left+2 top+3"
+ }, {
+ top: -3,
+ left: -4
+ }, "with offset" );
+});
+
+test( "collision: fit, with margin", function() {
+ expect( 2 );
+
+ $( "#elx" ).css({
+ marginTop: 6,
+ marginLeft: 4
+ });
+
+ collisionTest({
+ collision: "fit"
+ }, {
+ top: 10,
+ left: 10
+ }, "right bottom" );
+
+ collisionTest2({
+ collision: "fit"
+ }, {
+ top: 6,
+ left: 4
+ }, "left top" );
+});
+
+test( "collision: flip, with margin", function() {
+ expect( 3 );
+
+ $( "#elx" ).css({
+ marginTop: 6,
+ marginLeft: 4
+ });
+
+ collisionTest({
+ collision: "flip"
+ }, {
+ top: 10,
+ left: 10
+ }, "left top" );
+
+ collisionTest2({
+ collision: "flip"
+ }, {
+ top: 10,
+ left: 10
+ }, "right bottom" );
+
+ collisionTest2({
+ collision: "flip",
+ my: "left top"
+ }, {
+ top: 0,
+ left: 4
+ }, "right bottom" );
+});
+
+test( "within", function() {
+ expect( 7 );
+
+ collisionTest({
+ within: document
+ }, {
+ top: 10,
+ left: 10
+ }, "within document" );
+
+ collisionTest({
+ within: "#within",
+ collision: "fit"
+ }, {
+ top: 4,
+ left: 2
+ }, "fit - right bottom" );
+
+ collisionTest2({
+ within: "#within",
+ collision: "fit"
+ }, {
+ top: 2,
+ left: 0
+ }, "fit - left top" );
+
+ collisionTest({
+ within: "#within",
+ collision: "flip"
+ }, {
+ top: 10,
+ left: -6
+ }, "flip - right bottom" );
+
+ collisionTest2({
+ within: "#within",
+ collision: "flip"
+ }, {
+ top: 10,
+ left: -6
+ }, "flip - left top" );
+
+ collisionTest({
+ within: "#within",
+ collision: "flipfit"
+ }, {
+ top: 4,
+ left: 0
+ }, "flipfit - right bottom" );
+
+ collisionTest2({
+ within: "#within",
+ collision: "flipfit"
+ }, {
+ top: 4,
+ left: 0
+ }, "flipfit - left top" );
+});
+
+test( "with scrollbars", function() {
+ expect( 4 );
+
+ $( "#scrollx" ).css({
+ width: 100,
+ height: 100,
+ left: 0,
+ top: 0
+ });
+
+ collisionTest({
+ of: "#scrollx",
+ collision: "fit",
+ within: "#scrollx"
+ }, {
+ top: 90,
+ left: 90
+ }, "visible" );
+
+ $( "#scrollx" ).css({
+ overflow: "scroll"
+ });
+
+ var scrollbarInfo = $.position.getScrollInfo( $.position.getWithinInfo( $( "#scrollx" ) ) );
+
+ collisionTest({
+ of: "#scrollx",
+ collision: "fit",
+ within: "#scrollx"
+ }, {
+ top: 90 - scrollbarInfo.height,
+ left: 90 - scrollbarInfo.width
+ }, "scroll" );
+
+ $( "#scrollx" ).css({
+ overflow: "auto"
+ });
+
+ collisionTest({
+ of: "#scrollx",
+ collision: "fit",
+ within: "#scrollx"
+ }, {
+ top: 90,
+ left: 90
+ }, "auto, no scroll" );
+
+ $( "#scrollx" ).css({
+ overflow: "auto"
+ }).append( $("<div>").height(300).width(300) );
+
+ collisionTest({
+ of: "#scrollx",
+ collision: "fit",
+ within: "#scrollx"
+ }, {
+ top: 90 - scrollbarInfo.height,
+ left: 90 - scrollbarInfo.width
+ }, "auto, with scroll" );
+});
+
+test( "fractions", function() {
+ expect( 1 );
+
+ $( "#fractions-element" ).position({
+ my: "left top",
+ at: "left top",
+ of: "#fractions-parent",
+ collision: "none"
+ });
+ deepEqual( $( "#fractions-element" ).offset(), $( "#fractions-parent" ).offset(), "left top, left top" );
+});
+
+test( "bug #5280: consistent results (avoid fractional values)", function() {
+ expect( 1 );
+
+ var wrapper = $( "#bug-5280" ),
+ elem = wrapper.children(),
+ offset1 = elem.position({
+ my: "center",
+ at: "center",
+ of: wrapper,
+ collision: "none"
+ }).offset(),
+ offset2 = elem.position({
+ my: "center",
+ at: "center",
+ of: wrapper,
+ collision: "none"
+ }).offset();
+ deepEqual( offset1, offset2 );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/progressbar/all.html b/apps/it/static/js/ui/tests/unit/progressbar/all.html
new file mode 100644
index 0000000..ed17c36
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/progressbar/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Progressbar Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "progressbar" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Progressbar Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/progressbar/progressbar.html b/apps/it/static/js/ui/tests/unit/progressbar/progressbar.html
new file mode 100644
index 0000000..70a4abe
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/progressbar/progressbar.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Progressbar Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.progressbar" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.progressbar.js"
+ ]
+ });
+ </script>
+
+ <script src="progressbar_common.js"></script>
+ <script src="progressbar_core.js"></script>
+ <script src="progressbar_events.js"></script>
+ <script src="progressbar_methods.js"></script>
+ <script src="progressbar_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Progressbar Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="progressbar"></div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/progressbar/progressbar_common.js b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_common.js
new file mode 100644
index 0000000..0768576
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_common.js
@@ -0,0 +1,12 @@
+TestHelpers.commonWidgetTests( "progressbar", {
+ defaults: {
+ disabled: false,
+ max: 100,
+ value: 0,
+
+ //callbacks
+ change: null,
+ complete: null,
+ create: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/progressbar/progressbar_core.js b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_core.js
new file mode 100644
index 0000000..8f4a138
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_core.js
@@ -0,0 +1,53 @@
+module( "progressbar: core" );
+
+test( "markup structure", function() {
+ expect( 5 );
+ var element = $( "#progressbar" ).progressbar();
+ ok( element.hasClass( "ui-progressbar" ), "main element is .ui-progressbar" );
+ ok( !element.hasClass( "ui-progressbar-indeterminate" ),
+ "main element is not .ui-progressbar-indeterminate" );
+ equal( element.children().length, 1, "main element contains one child" );
+ ok( element.children().eq( 0 ).hasClass( "ui-progressbar-value" ),
+ "child is .ui-progressbar-value" );
+ equal( element.children().children().length, 0, "no overlay div" );
+});
+
+test( "markup structure - indeterminate", function() {
+ expect( 5 );
+ var element = $( "#progressbar" ).progressbar({ value: false });
+ ok( element.hasClass( "ui-progressbar" ), "main element is .ui-progressbar" );
+ ok( element.hasClass( "ui-progressbar-indeterminate" ),
+ "main element is .ui-progressbar-indeterminate" );
+ equal( element.children().length, 1, "main element contains one child" );
+ ok( element.children().eq( 0 ).hasClass( "ui-progressbar-value" ),
+ "child is .ui-progressbar-value" );
+ equal( element.children().children( ".ui-progressbar-overlay" ).length, 1,
+ ".ui-progressbar-value has .ui-progressbar-overlay" );
+});
+
+test( "accessibility", function() {
+ expect( 11 );
+ var element = $( "#progressbar" ).progressbar();
+
+ equal( element.attr( "role" ), "progressbar", "aria role" );
+ equal( element.attr( "aria-valuemin" ), 0, "aria-valuemin" );
+ equal( element.attr( "aria-valuemax" ), 100, "aria-valuemax" );
+ equal( element.attr( "aria-valuenow" ), 0, "aria-valuenow initially" );
+
+ element.progressbar( "value", 77 );
+ equal( element.attr( "aria-valuenow" ), 77, "aria-valuenow" );
+
+ element.progressbar( "option", "max", 150 );
+ equal( element.attr( "aria-valuemax" ), 150, "aria-valuemax" );
+
+ element.progressbar( "disable" );
+ equal( element.attr( "aria-disabled" ), "true", "aria-disabled on" );
+
+ element.progressbar( "enable" );
+ equal( element.attr( "aria-disabled" ), "false", "aria-disabled off" );
+
+ element.progressbar( "option", "value", false );
+ equal( element.attr( "aria-valuemin" ), 0, "aria-valuemin" );
+ equal( element.attr( "aria-valuemax" ), 150, "aria-valuemax" );
+ strictEqual( element.attr( "aria-valuenow" ), undefined, "aria-valuenow" );
+});
diff --git a/apps/it/static/js/ui/tests/unit/progressbar/progressbar_events.js b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_events.js
new file mode 100644
index 0000000..95effda
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_events.js
@@ -0,0 +1,51 @@
+module( "progressbar: events" );
+
+test( "create", function() {
+ expect( 1 );
+ $( "#progressbar" ).progressbar({
+ value: 5,
+ create: function() {
+ equal( $( this ).progressbar( "value" ), 5, "Correct value at create" );
+ },
+ change: function() {
+ ok( false, "create has triggered change()" );
+ }
+ });
+});
+
+test( "change", function() {
+ expect( 2 );
+ var element = $( "#progressbar" ).progressbar();
+
+ element.one( "progressbarchange", function() {
+ equal( element.progressbar( "value" ), 5, "change triggered for middle value" );
+ });
+ element.progressbar( "value", 5 );
+ element.one( "progressbarchange", function() {
+ equal( element.progressbar( "value" ), 100, "change triggered for final value" );
+ });
+ element.progressbar( "value", 100 );
+});
+
+test( "complete", function() {
+ expect( 5 );
+ var value,
+ changes = 0,
+ element = $( "#progressbar" ).progressbar({
+ change: function() {
+ changes++;
+ equal( element.progressbar( "value" ), value, "change at " + value );
+ },
+ complete: function() {
+ equal( changes, 3, "complete triggered after change and not on indeterminate" );
+ equal( element.progressbar( "value" ), 100, "value is 100" );
+ }
+ });
+
+ value = 5;
+ element.progressbar( "value", value );
+ value = false;
+ element.progressbar( "value", value );
+ value = 100;
+ element.progressbar( "value", value );
+});
diff --git a/apps/it/static/js/ui/tests/unit/progressbar/progressbar_methods.js b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_methods.js
new file mode 100644
index 0000000..cf7faf6
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_methods.js
@@ -0,0 +1,25 @@
+module( "progressbar: methods" );
+
+test( "destroy", function() {
+ expect( 1 );
+ domEqual( "#progressbar", function() {
+ $( "#progressbar" ).progressbar().progressbar( "destroy" );
+ });
+});
+
+test( "value", function() {
+ expect( 3 );
+
+ var element = $( "<div>" ).progressbar({ value: 20 });
+ equal( element.progressbar( "value" ), 20, "correct value as getter" );
+ strictEqual( element.progressbar( "value", 30 ), element, "chainable as setter" );
+ equal( element.progressbar( "option", "value" ), 30, "correct value after setter" );
+});
+
+test( "widget", function() {
+ expect( 2 );
+ var element = $( "#progressbar" ).progressbar(),
+ widgetElement = element.progressbar( "widget" );
+ equal( widgetElement.length, 1, "one element" );
+ strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" );
+});
diff --git a/apps/it/static/js/ui/tests/unit/progressbar/progressbar_options.js b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_options.js
new file mode 100644
index 0000000..bc0b5d0
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/progressbar/progressbar_options.js
@@ -0,0 +1,72 @@
+module( "progressbar: options" );
+
+test( "{ value: 0 }, default", function() {
+ expect( 1 );
+ $( "#progressbar" ).progressbar();
+ equal( $( "#progressbar" ).progressbar( "value" ), 0 );
+});
+
+// Ticket #7231 - valueDiv should be hidden when value is at 0%
+test( "value: visibility of valueDiv", function() {
+ expect( 4 );
+ var element = $( "#progressbar" ).progressbar({
+ value: 0
+ });
+ ok( element.children( ".ui-progressbar-value" ).is( ":hidden" ),
+ "valueDiv hidden when value is initialized at 0" );
+ element.progressbar( "value", 1 );
+ ok( element.children( ".ui-progressbar-value" ).is( ":visible" ),
+ "valueDiv visible when value is set to 1" );
+ element.progressbar( "value", 100 );
+ ok( element.children( ".ui-progressbar-value" ).is( ":visible" ),
+ "valueDiv visible when value is set to 100" );
+ element.progressbar( "value", 0 );
+ ok( element.children( ".ui-progressbar-value" ).is( ":hidden" ),
+ "valueDiv hidden when value is set to 0" );
+});
+
+test( "{ value: 5 }", function() {
+ expect( 1 );
+ $( "#progressbar" ).progressbar({
+ value: 5
+ });
+ equal( $( "#progressbar" ).progressbar( "value" ), 5 );
+});
+
+test( "{ value: -5 }", function() {
+ expect( 1 );
+ $( "#progressbar" ).progressbar({
+ value: -5
+ });
+ equal( $( "#progressbar" ).progressbar( "value" ), 0,
+ "value constrained at min" );
+});
+
+test( "{ value: 105 }", function() {
+ expect( 1 );
+ $( "#progressbar" ).progressbar({
+ value: 105
+ });
+ equal( $( "#progressbar" ).progressbar( "value" ), 100,
+ "value constrained at max" );
+});
+
+test( "{ value: 10, max: 5 }", function() {
+ expect( 1 );
+ $("#progressbar").progressbar({
+ max: 5,
+ value: 10
+ });
+ equal( $( "#progressbar" ).progressbar( "value" ), 5,
+ "value constrained at max" );
+});
+
+test( "change max below value", function() {
+ expect( 1 );
+ $("#progressbar").progressbar({
+ max: 10,
+ value: 10
+ }).progressbar( "option", "max", 5 );
+ equal( $( "#progressbar" ).progressbar( "value" ), 5,
+ "value constrained at max" );
+});
diff --git a/apps/it/static/js/ui/tests/unit/qunit-composite.css b/apps/it/static/js/ui/tests/unit/qunit-composite.css
new file mode 100644
index 0000000..c530436
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/qunit-composite.css
@@ -0,0 +1,13 @@
+iframe.qunit-subsuite {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+
+ margin: 0;
+ padding: 0;
+ border-width: 1px 0 0;
+ height: 45%;
+ width: 100%;
+
+ background: #fff;
+}
diff --git a/apps/it/static/js/ui/tests/unit/qunit-composite.js b/apps/it/static/js/ui/tests/unit/qunit-composite.js
new file mode 100644
index 0000000..2e54540
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/qunit-composite.js
@@ -0,0 +1,112 @@
+(function( QUnit ) {
+
+QUnit.extend( QUnit, {
+ testSuites: function( suites ) {
+ QUnit.begin(function() {
+ QUnit.initIframe();
+ });
+
+ for ( var i = 0; i < suites.length; i++ ) {
+ QUnit.runSuite( suites[i] );
+ }
+
+ QUnit.done(function() {
+ this.iframe.style.display = "none";
+ });
+ },
+
+ runSuite: function( suite ) {
+ var path = suite;
+
+ if ( QUnit.is( "object", suite ) ) {
+ path = suite.path;
+ suite = suite.name;
+ }
+
+ asyncTest( suite, function() {
+ QUnit.iframe.setAttribute( "src", path );
+ });
+ },
+
+ initIframe: function() {
+ var body = document.body,
+ iframe = this.iframe = document.createElement( "iframe" ),
+ iframeWin;
+
+ iframe.className = "qunit-subsuite";
+ body.appendChild( iframe );
+
+ function onIframeLoad() {
+ var module, test,
+ count = 0;
+
+ if (iframe.src === "") {
+ return;
+ }
+
+ iframeWin.QUnit.moduleStart(function( data ) {
+ // capture module name for messages
+ module = data.name;
+ });
+
+ iframeWin.QUnit.testStart(function( data ) {
+ // capture test name for messages
+ test = data.name;
+ });
+ iframeWin.QUnit.testDone(function() {
+ test = null;
+ });
+
+ iframeWin.QUnit.log(function( data ) {
+ if (test === null) {
+ return;
+ }
+ // pass all test details through to the main page
+ var message = module + ": " + test + ": " + data.message;
+ expect( ++count );
+ QUnit.push( data.result, data.actual, data.expected, message );
+ });
+
+ iframeWin.QUnit.done(function() {
+ // start the wrapper test from the main page
+ start();
+ });
+ }
+ QUnit.addEvent( iframe, "load", onIframeLoad );
+
+ iframeWin = iframe.contentWindow;
+ }
+});
+
+QUnit.testStart(function( data ) {
+ // update the test status to show which test suite is running
+ QUnit.id( "qunit-testresult" ).innerHTML = "Running " + data.name + "...<br>&nbsp;";
+});
+
+QUnit.testDone(function() {
+ var i,
+ current = QUnit.id( this.config.current.id ),
+ children = current.children,
+ src = this.iframe.src;
+
+ // undo the auto-expansion of failed tests
+ for ( i = 0; i < children.length; i++ ) {
+ if ( children[i].nodeName === "OL" ) {
+ children[i].style.display = "none";
+ }
+ }
+
+ QUnit.addEvent(current, "dblclick", function( e ) {
+ var target = e && e.target ? e.target : window.event.srcElement;
+ if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
+ target = target.parentNode;
+ }
+ if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
+ window.location = src;
+ }
+ });
+
+ current.getElementsByTagName("a")[0].href = src;
+});
+
+}( QUnit ) );
diff --git a/apps/it/static/js/ui/tests/unit/resizable/all.html b/apps/it/static/js/ui/tests/unit/resizable/all.html
new file mode 100644
index 0000000..63bc458
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Resizable Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "resizable" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Resizable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/resizable/images/test.jpg b/apps/it/static/js/ui/tests/unit/resizable/images/test.jpg
new file mode 100644
index 0000000..0175b13
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/images/test.jpg
Binary files differ
diff --git a/apps/it/static/js/ui/tests/unit/resizable/resizable.html b/apps/it/static/js/ui/tests/unit/resizable/resizable.html
new file mode 100644
index 0000000..255c988
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/resizable.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Resizable Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.resizable" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.resizable.js"
+ ]
+ });
+ </script>
+
+ <script src="resizable_common.js"></script>
+ <script src="resizable_core.js"></script>
+ <script src="resizable_events.js"></script>
+ <script src="resizable_methods.js"></script>
+ <script src="resizable_options.js"></script>
+ <script src="resizable_test_helpers.js"></script>
+
+ <script src="../swarminject.js"></script>
+
+ <style>
+ #container {
+ width: 300px;
+ height: 200px;
+ }
+ #resizable1 {
+ background: green;
+ height: 100px;
+ width: 100px;
+ }
+ #resizable2 {
+ height: 100px;
+ width: 100px;
+ }
+ </style>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Resizable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="container">
+ <div id="resizable1">I'm a resizable.</div>
+</div>
+<img src="images/test.jpg" id="resizable2" alt="solid gray">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/resizable/resizable_common.js b/apps/it/static/js/ui/tests/unit/resizable/resizable_common.js
new file mode 100644
index 0000000..c261ac5
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/resizable_common.js
@@ -0,0 +1,30 @@
+TestHelpers.commonWidgetTests( "resizable", {
+ defaults: {
+ alsoResize: false,
+ animate: false,
+ animateDuration: "slow",
+ animateEasing: "swing",
+ aspectRatio: false,
+ autoHide: false,
+ cancel: "input,textarea,button,select,option",
+ containment: false,
+ delay: 0,
+ disabled: false,
+ distance: 1,
+ ghost: false,
+ grid: false,
+ handles: "e,s,se",
+ helper: false,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 10,
+ minWidth: 10,
+ zIndex: 90,
+
+ // callbacks
+ create: null,
+ resize: null,
+ start: null,
+ stop: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/resizable/resizable_core.js b/apps/it/static/js/ui/tests/unit/resizable/resizable_core.js
new file mode 100644
index 0000000..b02e8b4
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/resizable_core.js
@@ -0,0 +1,209 @@
+/*
+ * resizable_core.js
+ */
+
+(function($) {
+
+module("resizable: core");
+
+/*
+test("element types", function() {
+ var typeNames = ("p,h1,h2,h3,h4,h5,h6,blockquote,ol,ul,dl,div,form"
+ + ",table,fieldset,address,ins,del,em,strong,q,cite,dfn,abbr"
+ + ",acronym,code,samp,kbd,var,img,object,hr"
+ + ",input,button,label,select,iframe").split(",");
+
+ $.each(typeNames, function(i) {
+ var typeName = typeNames[i];
+ el = $(document.createElement(typeName)).appendTo("body");
+ (typeName == "table" && el.append("<tr><td>content</td></tr>"));
+ el.resizable();
+ ok(true, "$('&lt;" + typeName + "/&gt').resizable()");
+ el.resizable("destroy");
+ el.remove();
+ });
+});
+*/
+
+test("n", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-n", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, 0, -50);
+ equal( target.height(), 150, "compare height" );
+
+ TestHelpers.resizable.drag(handle, 0, 50);
+ equal( target.height(), 100, "compare height" );
+
+ equal( target[0].style.left, "", "left should not be modified" );
+ equal( target[0].style.width, "", "width should not be modified" );
+});
+
+test("s", function() {
+ expect(5);
+
+ var handle = ".ui-resizable-s", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, 0, 50);
+ equal( target.height(), 150, "compare height" );
+
+ TestHelpers.resizable.drag(handle, 0, -50);
+ equal( target.height(), 100, "compare height" );
+
+ equal( target[0].style.top, "", "top should not be modified" );
+ equal( target[0].style.left, "", "left should not be modified" );
+ equal( target[0].style.width, "", "width should not be modified" );
+});
+
+test("e", function() {
+ expect(5);
+
+ var handle = ".ui-resizable-e", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, 50);
+ equal( target.width(), 150, "compare width");
+
+ TestHelpers.resizable.drag(handle, -50);
+ equal( target.width(), 100, "compare width" );
+
+ equal( target[0].style.height, "", "height should not be modified" );
+ equal( target[0].style.top, "", "top should not be modified" );
+ equal( target[0].style.left, "", "left should not be modified" );
+});
+
+test("w", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-w", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, -50);
+ equal( target.width(), 150, "compare width" );
+
+ TestHelpers.resizable.drag(handle, 50);
+ equal( target.width(), 100, "compare width" );
+
+ equal( target[0].style.height, "", "height should not be modified" );
+ equal( target[0].style.top, "", "top should not be modified" );
+});
+
+test("ne", function() {
+ expect(5);
+
+ var handle = ".ui-resizable-ne", target = $("#resizable1").css({ overflow: "hidden" }).resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, -50, -50);
+ equal( target.width(), 50, "compare width" );
+ equal( target.height(), 150, "compare height" );
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+ equal( target.width(), 100, "compare width" );
+ equal( target.height(), 100, "compare height" );
+
+ equal( target[0].style.left, "", "left should not be modified" );
+});
+
+test("se", function() {
+ expect(6);
+
+ var handle = ".ui-resizable-se", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+ equal( target.width(), 150, "compare width" );
+ equal( target.height(), 150, "compare height" );
+
+ TestHelpers.resizable.drag(handle, -50, -50);
+ equal( target.width(), 100, "compare width" );
+ equal( target.height(), 100, "compare height" );
+
+ equal( target[0].style.top, "", "top should not be modified" );
+ equal( target[0].style.left, "", "left should not be modified" );
+});
+
+test("sw", function() {
+ expect(5);
+
+ var handle = ".ui-resizable-sw", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, -50, -50);
+ equal( target.width(), 150, "compare width" );
+ equal( target.height(), 50, "compare height" );
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+ equal( target.width(), 100, "compare width" );
+ equal( target.height(), 100, "compare height" );
+
+ equal( target[0].style.top, "", "top should not be modified" );
+});
+
+test("nw", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-nw", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, -50, -50);
+ equal( target.width(), 150, "compare width" );
+ equal( target.height(), 150, "compare height" );
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+ equal( target.width(), 100, "compare width" );
+ equal( target.height(), 100, "compare height" );
+});
+
+test("handle with complex markup (#8756)", function() {
+ expect(2);
+
+ $("#resizable1")
+ .append(
+ $("<div>")
+ .addClass("ui-resizable-handle")
+ .addClass("ui-resizable-w")
+ .append($("<div>"))
+ );
+
+ var handle = ".ui-resizable-w div", target = $("#resizable1").resizable({ handles: "all" });
+
+ TestHelpers.resizable.drag(handle, -50);
+ equal( target.width(), 150, "compare width" );
+
+ TestHelpers.resizable.drag(handle, 50);
+ equal( target.width(), 100, "compare width" );
+});
+
+test("resizable accounts for scroll position correctly (#3815)", function() {
+ expect( 3 );
+
+ var position, top, left,
+ container = $("<div style='overflow:scroll;height:300px;width:300px;position:relative;'></div>").appendTo("#qunit-fixture"),
+ overflowed = $("<div style='width: 1000px; height: 1000px;'></div>").appendTo( container ),
+ el = $("<div style='height:100px;width:100px;position:absolute;top:10px;left:10px;'></div>").appendTo( overflowed ).resizable({ handles: "all" }),
+ handle = ".ui-resizable-e";
+
+ container.scrollLeft( 100 ).scrollTop( 100 );
+
+ position = el.position();
+ left = el.css("left");
+ top = el.css("top");
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+ deepEqual( el.position(), position, "position stays the same when resized" );
+ equal( el.css("left"), left, "css('left') stays the same when resized" );
+ equal( el.css("top"), top, "css('top') stays the same when resized" );
+});
+
+test( "resizable stores correct size when using helper and grid (#9547)", function() {
+ expect( 2 );
+
+ var handle = ".ui-resizable-se",
+ target = $( "#resizable1" ).resizable({
+ handles: "all",
+ helper: "ui-resizable-helper",
+ grid: [ 10, 10 ]
+ });
+
+ TestHelpers.resizable.drag( handle, 1, 1 );
+ equal( target.width(), 100, "compare width" );
+ equal( target.height(), 100, "compare height" );
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/resizable/resizable_events.js b/apps/it/static/js/ui/tests/unit/resizable/resizable_events.js
new file mode 100644
index 0000000..18e25bf
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/resizable_events.js
@@ -0,0 +1,220 @@
+/*
+ * resizable_events.js
+ */
+(function($) {
+
+module("resizable: events");
+
+test("start", function() {
+
+ expect(5);
+
+ var count = 0,
+ handle = ".ui-resizable-se";
+
+ $("#resizable1").resizable({
+ handles: "all",
+ start: function(event, ui) {
+ equal( ui.size.width, 100, "compare width" );
+ equal( ui.size.height, 100, "compare height" );
+ equal( ui.originalSize.width, 100, "compare original width" );
+ equal( ui.originalSize.height, 100, "compare original height" );
+ count++;
+ }
+ });
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+
+ equal(count, 1, "start callback should happen exactly once");
+
+});
+
+test( "resize", function() {
+
+ expect( 9 );
+
+ var count = 0,
+ handle = ".ui-resizable-se";
+
+ $("#resizable1").resizable({
+ handles: "all",
+ resize: function( event, ui ) {
+ if ( count === 0 ) {
+ equal( ui.size.width, 125, "compare width" );
+ equal( ui.size.height, 125, "compare height" );
+ equal( ui.originalSize.width, 100, "compare original width" );
+ equal( ui.originalSize.height, 100, "compare original height" );
+ } else {
+ equal( ui.size.width, 150, "compare width" );
+ equal( ui.size.height, 150, "compare height" );
+ equal( ui.originalSize.width, 100, "compare original width" );
+ equal( ui.originalSize.height, 100, "compare original height" );
+ }
+ count++;
+ }
+ });
+
+ TestHelpers.resizable.drag( handle, 50, 50 );
+
+ equal( count, 2, "resize callback should happen exactly once per size adjustment" );
+
+});
+
+test( "resize (min/max dimensions)", function() {
+
+ expect( 5 );
+
+ var count = 0,
+ handle = ".ui-resizable-se";
+
+ $("#resizable1").resizable({
+ handles: "all",
+ minWidth: 60,
+ minHeight: 60,
+ maxWidth: 100,
+ maxHeight: 100,
+ resize: function( event, ui ) {
+ equal( ui.size.width, 60, "compare width" );
+ equal( ui.size.height, 60, "compare height" );
+ equal( ui.originalSize.width, 100, "compare original width" );
+ equal( ui.originalSize.height, 100, "compare original height" );
+ count++;
+ }
+ });
+
+ TestHelpers.resizable.drag( handle, -200, -200 );
+
+ equal( count, 1, "resize callback should happen exactly once per size adjustment" );
+
+});
+
+test( "resize (containment)", function() {
+
+ expect( 5 );
+
+ var count = 0,
+ handle = ".ui-resizable-se",
+ container = $("#resizable1").wrap("<div>").parent().css({
+ height: "100px",
+ width: "100px"
+ });
+
+ $("#resizable1").resizable({
+ handles: "all",
+ containment: container,
+ resize: function( event, ui ) {
+ equal( ui.size.width, 10, "compare width" );
+ equal( ui.size.height, 10, "compare height" );
+ equal( ui.originalSize.width, 100, "compare original width" );
+ equal( ui.originalSize.height, 100, "compare original height" );
+ count++;
+ }
+ });
+
+ // Prove you can't resize outside containment by dragging southeast corner southeast
+ TestHelpers.resizable.drag( handle, 100, 100 );
+
+ // Prove you can't resize outside containment by dragging southeast corner northwest
+ TestHelpers.resizable.drag( handle, -200, -200 );
+
+ equal( count, 1, "resize callback should happen exactly once per size adjustment" );
+
+});
+
+test("resize (grid)", function() {
+
+ expect(5);
+
+ var count = 0,
+ handle = ".ui-resizable-se";
+
+ $("#resizable1").resizable({
+ handles: "all",
+ grid: 50,
+ resize: function(event, ui) {
+ equal( ui.size.width, 150, "compare width" );
+ equal( ui.size.height, 150, "compare height" );
+ equal( ui.originalSize.width, 100, "compare original width" );
+ equal( ui.originalSize.height, 100, "compare original height" );
+ count++;
+ }
+ });
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+
+ equal(count, 1, "resize callback should happen exactly once per grid-unit size adjustment");
+
+});
+
+test("stop", function() {
+
+ expect(5);
+
+ var count = 0,
+ handle = ".ui-resizable-se";
+
+ $("#resizable1").resizable({
+ handles: "all",
+ stop: function(event, ui) {
+ equal( ui.size.width, 150, "compare width" );
+ equal( ui.size.height, 150, "compare height" );
+ equal( ui.originalSize.width, 100, "compare original width" );
+ equal( ui.originalSize.height, 100, "compare original height" );
+ count++;
+ }
+ });
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+
+ equal(count, 1, "stop callback should happen exactly once");
+
+});
+
+test( "resize (containment) works with parent with negative offset", function() {
+
+ expect( 1 );
+
+ var widthBefore, widthAfter,
+ handle = ".ui-resizable-e",
+ target = $( "#resizable1" ),
+ absoluteContainer = target.wrap( "<div />" ).parent(),
+ fixedContainer = absoluteContainer.wrap( "<div />" ).parent(),
+ increaseWidthBy = 50;
+
+ // position fixed container in window top left
+ fixedContainer.css({
+ width: 400,
+ height: 100,
+ position: "fixed",
+ top: 0,
+ left: 0
+ });
+
+ // position absolute container within fixed on slightly outside window
+ absoluteContainer.css({
+ width: 400,
+ height: 100,
+ position: "absolute",
+ top: 0,
+ left: -50
+ });
+
+ // set up resizable to be contained within absolute container
+ target.resizable({
+ handles: "all",
+ containment: "parent"
+ }).css({
+ width: 300
+ });
+
+ widthBefore = target.width();
+
+ TestHelpers.resizable.drag( handle, increaseWidthBy, 0 );
+
+ widthAfter = target.width();
+
+ equal( widthAfter, ( widthBefore + increaseWidthBy ), "resizable width should be increased by the value dragged" );
+
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/resizable/resizable_methods.js b/apps/it/static/js/ui/tests/unit/resizable/resizable_methods.js
new file mode 100644
index 0000000..b12f303
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/resizable_methods.js
@@ -0,0 +1,12 @@
+/*
+ * resizable_methods.js
+ */
+(function($) {
+
+module("resizable: methods");
+
+// this is here to make JSHint pass "unused", and we don't want to
+// remove the parameter for when we finally implement
+$.noop();
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/resizable/resizable_options.js b/apps/it/static/js/ui/tests/unit/resizable/resizable_options.js
new file mode 100644
index 0000000..e739d61
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/resizable_options.js
@@ -0,0 +1,291 @@
+/*
+ * resizable_options.js
+ */
+(function($) {
+
+module("resizable: options");
+
+test( "alsoResize", function() {
+ expect( 2 );
+
+ var other = $( "<div>" )
+ .css({
+ width: 50,
+ height: 50
+ })
+ .appendTo( "body" ),
+ element = $( "#resizable1" ).resizable({
+ alsoResize: other
+ }),
+ handle = ".ui-resizable-e";
+
+ TestHelpers.resizable.drag( handle, 80 );
+ equal( element.width(), 180, "resizable width" );
+ equal( other.width(), 130, "alsoResize width" );
+});
+
+
+test("aspectRatio: 'preserve' (e)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-e", target = $("#resizable1").resizable({ aspectRatio: "preserve", handles: "all", minWidth: 70, minHeight: 50, maxWidth: 150, maxHeight: 130 });
+
+ TestHelpers.resizable.drag(handle, 80);
+ equal( target.width(), 130, "compare maxWidth");
+ equal( target.height(), 130, "compare maxHeight");
+
+ TestHelpers.resizable.drag(handle, -130);
+ equal( target.width(), 70, "compare minWidth");
+ equal( target.height(), 70, "compare minHeight");
+});
+
+test("aspectRatio: 'preserve' (w)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-w", target = $("#resizable1").resizable({ aspectRatio: "preserve", handles: "all", minWidth: 70, minHeight: 50, maxWidth: 150, maxHeight: 130 });
+
+ TestHelpers.resizable.drag(handle, -80);
+ equal( target.width(), 130, "compare maxWidth");
+ equal( target.height(), 130, "compare maxHeight");
+
+ TestHelpers.resizable.drag(handle, 130);
+ equal( target.width(), 70, "compare minWidth");
+ equal( target.height(), 70, "compare minHeight");
+});
+
+test("aspectRatio: 'preserve' (n)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-n", target = $("#resizable1").resizable({ aspectRatio: "preserve", handles: "all", minWidth: 70, minHeight: 50, maxWidth: 150, maxHeight: 130 });
+
+ TestHelpers.resizable.drag(handle, 0, -80);
+ equal( target.width(), 130, "compare maxWidth");
+ equal( target.height(), 130, "compare maxHeight");
+
+ TestHelpers.resizable.drag(handle, 0, 80);
+ equal( target.width(), 70, "compare minWidth");
+ equal( target.height(), 70, "compare minHeight");
+});
+
+test("aspectRatio: 'preserve' (s)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-s", target = $("#resizable1").resizable({ aspectRatio: "preserve", handles: "all", minWidth: 70, minHeight: 50, maxWidth: 150, maxHeight: 130 });
+
+ TestHelpers.resizable.drag(handle, 0, 80);
+ equal( target.width(), 130, "compare maxWidth");
+ equal( target.height(), 130, "compare maxHeight");
+
+ TestHelpers.resizable.drag(handle, 0, -80);
+ equal( target.width(), 70, "compare minWidth");
+ equal( target.height(), 70, "compare minHeight");
+});
+
+test("aspectRatio: 'preserve' (se)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-se", target = $("#resizable1").resizable({ aspectRatio: "preserve", handles: "all", minWidth: 70, minHeight: 50, maxWidth: 150, maxHeight: 130 });
+
+ TestHelpers.resizable.drag(handle, 80, 80);
+ equal( target.width(), 130, "compare maxWidth");
+ equal( target.height(), 130, "compare maxHeight");
+
+ TestHelpers.resizable.drag(handle, -80, -80);
+ equal( target.width(), 70, "compare minWidth");
+ equal( target.height(), 70, "compare minHeight");
+});
+
+test("aspectRatio: 'preserve' (sw)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-sw", target = $("#resizable1").resizable({ aspectRatio: "preserve", handles: "all", minWidth: 70, minHeight: 50, maxWidth: 150, maxHeight: 130 });
+
+ TestHelpers.resizable.drag(handle, -80, 80);
+ equal( target.width(), 130, "compare maxWidth");
+ equal( target.height(), 130, "compare maxHeight");
+
+ TestHelpers.resizable.drag(handle, 80, -80);
+ equal( target.width(), 70, "compare minWidth");
+ equal( target.height(), 70, "compare minHeight");
+});
+
+test("aspectRatio: 'preserve' (ne)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-ne", target = $("#resizable1").resizable({ aspectRatio: "preserve", handles: "all", minWidth: 70, minHeight: 50, maxWidth: 150, maxHeight: 130 });
+
+ TestHelpers.resizable.drag(handle, 80, -80);
+ equal( target.width(), 130, "compare maxWidth");
+ equal( target.height(), 130, "compare maxHeight");
+
+ TestHelpers.resizable.drag(handle, -80, 80);
+ equal( target.width(), 70, "compare minWidth");
+ equal( target.height(), 70, "compare minHeight");
+});
+
+test( "containment", function() {
+ expect( 4 );
+ var element = $( "#resizable1" ).resizable({
+ containment: "#container"
+ });
+
+ TestHelpers.resizable.drag( ".ui-resizable-se", 20, 30 );
+ equal( element.width(), 120, "unconstrained width within container" );
+ equal( element.height(), 130, "unconstrained height within container" );
+
+ TestHelpers.resizable.drag( ".ui-resizable-se", 400, 400 );
+ equal( element.width(), 300, "constrained width at containment edge" );
+ equal( element.height(), 200, "constrained height at containment edge" );
+});
+
+test("grid", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-se", target = $("#resizable1").resizable({ handles: "all", grid: [0, 20] });
+
+ TestHelpers.resizable.drag(handle, 3, 9);
+ equal( target.width(), 103, "compare width");
+ equal( target.height(), 100, "compare height");
+
+ TestHelpers.resizable.drag(handle, 15, 11);
+ equal( target.width(), 118, "compare width");
+ equal( target.height(), 120, "compare height");
+});
+
+test("grid (min/max dimensions)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-se", target = $("#resizable1").resizable({ handles: "all", grid: 20, minWidth: 65, minHeight: 65, maxWidth: 135, maxHeight: 135 });
+
+ TestHelpers.resizable.drag(handle, 50, 50);
+ equal( target.width(), 120, "grid should respect maxWidth");
+ equal( target.height(), 120, "grid should respect maxHeight");
+
+ TestHelpers.resizable.drag(handle, -100, -100);
+ equal( target.width(), 80, "grid should respect minWidth");
+ equal( target.height(), 80, "grid should respect minHeight");
+});
+
+test("grid (wrapped)", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-se", target = $("#resizable2").resizable({ handles: "all", grid: [0, 20] });
+
+ TestHelpers.resizable.drag(handle, 3, 9);
+ equal( target.width(), 103, "compare width");
+ equal( target.height(), 100, "compare height");
+
+ TestHelpers.resizable.drag(handle, 15, 11);
+ equal( target.width(), 118, "compare width");
+ equal( target.height(), 120, "compare height");
+});
+
+test( "grid - Resizable: can be moved when grid option is set (#9611)", function() {
+ expect( 6 );
+
+ var oldPosition,
+ handle = ".ui-resizable-nw",
+ target = $( "#resizable1" ).resizable({
+ handles: "all",
+ grid: 50
+ });
+
+ TestHelpers.resizable.drag( handle, 50, 50 );
+ equal( target.width(), 50, "compare width" );
+ equal( target.height(), 50, "compare height" );
+
+ oldPosition = target.position();
+
+ TestHelpers.resizable.drag( handle, 50, 50 );
+ equal( target.width(), 50, "compare width" );
+ equal( target.height(), 50, "compare height" );
+ equal( target.position().top, oldPosition.top, "compare top" );
+ equal( target.position().left, oldPosition.left, "compare left" );
+});
+
+test("ui-resizable-se { handles: 'all', minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 }", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-se", target = $("#resizable1").resizable({ handles: "all", minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 });
+
+ TestHelpers.resizable.drag(handle, -50, -50);
+ equal( target.width(), 60, "compare minWidth" );
+ equal( target.height(), 60, "compare minHeight" );
+
+ TestHelpers.resizable.drag(handle, 70, 70);
+ equal( target.width(), 100, "compare maxWidth" );
+ equal( target.height(), 100, "compare maxHeight" );
+});
+
+test("ui-resizable-sw { handles: 'all', minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 }", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-sw", target = $("#resizable1").resizable({ handles: "all", minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 });
+
+ TestHelpers.resizable.drag(handle, 50, -50);
+ equal( target.width(), 60, "compare minWidth" );
+ equal( target.height(), 60, "compare minHeight" );
+
+ TestHelpers.resizable.drag(handle, -70, 70);
+ equal( target.width(), 100, "compare maxWidth" );
+ equal( target.height(), 100, "compare maxHeight" );
+});
+
+test("ui-resizable-ne { handles: 'all', minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 }", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-ne", target = $("#resizable1").resizable({ handles: "all", minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 });
+
+ TestHelpers.resizable.drag(handle, -50, 50);
+ equal( target.width(), 60, "compare minWidth" );
+ equal( target.height(), 60, "compare minHeight" );
+
+ TestHelpers.resizable.drag(handle, 70, -70);
+ equal( target.width(), 100, "compare maxWidth" );
+ equal( target.height(), 100, "compare maxHeight" );
+});
+
+test("ui-resizable-nw { handles: 'all', minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 }", function() {
+ expect(4);
+
+ var handle = ".ui-resizable-nw", target = $("#resizable1").resizable({ handles: "all", minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 });
+
+ TestHelpers.resizable.drag(handle, 70, 70);
+ equal( target.width(), 60, "compare minWidth" );
+ equal( target.height(), 60, "compare minHeight" );
+
+ TestHelpers.resizable.drag(handle, -70, -70);
+ equal( target.width(), 100, "compare maxWidth" );
+ equal( target.height(), 100, "compare maxHeight" );
+});
+
+test("zIndex, applied to all handles", function() {
+ expect(8);
+
+ var target = $("<div></div>").resizable({ handles: "all", zIndex: 100 });
+ target.children( ".ui-resizable-handle" ).each( function( index, handle ) {
+ equal( $( handle ).css( "zIndex" ), 100, "compare zIndex" );
+ });
+});
+
+test( "alsoResize + containment", function() {
+ expect( 4 );
+ var other = $( "<div>" )
+ .css({
+ width: 50,
+ height: 50
+ })
+ .appendTo( "body" ),
+ element = $( "#resizable1" ).resizable({
+ alsoResize: other,
+ containment: "#container"
+ });
+
+ TestHelpers.resizable.drag( ".ui-resizable-se", 400, 400 );
+ equal( element.width(), 300, "resizable constrained width at containment edge" );
+ equal( element.height(), 200, "resizable constrained height at containment edge" );
+ equal( other.width(), 250, "alsoResize constrained width at containment edge" );
+ equal( other.height(), 150, "alsoResize constrained height at containment edge" );
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/resizable/resizable_test_helpers.js b/apps/it/static/js/ui/tests/unit/resizable/resizable_test_helpers.js
new file mode 100644
index 0000000..7ab5aa1
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/resizable/resizable_test_helpers.js
@@ -0,0 +1,11 @@
+TestHelpers.resizable = {
+ drag: function( el, dx, dy ) {
+ // this mouseover is to work around a limitation in resizable
+ // TODO: fix resizable so handle doesn't require mouseover in order to be used
+ $( el ).simulate("mouseover").simulate( "drag", {
+ moves: 2,
+ dx: dx,
+ dy: dy
+ });
+ }
+}; \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/selectable/all.html b/apps/it/static/js/ui/tests/unit/selectable/all.html
new file mode 100644
index 0000000..5ee323f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/selectable/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectable Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "selectable" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Selectable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/selectable/selectable.html b/apps/it/static/js/ui/tests/unit/selectable/selectable.html
new file mode 100644
index 0000000..18ffc6e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/selectable/selectable.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectable Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.selectable" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.selectable.js"
+ ]
+ });
+ </script>
+
+ <script src="selectable_common.js"></script>
+ <script src="selectable_core.js"></script>
+ <script src="selectable_events.js"></script>
+ <script src="selectable_methods.js"></script>
+ <script src="selectable_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Selectable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<ul id="selectable1">
+ <li>Item 1</li>
+ <li>Item 2</li>
+ <li class="special">Item 3</li>
+ <li>Item 4</li>
+ <li>Item 5</li>
+</ul>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/selectable/selectable_common.js b/apps/it/static/js/ui/tests/unit/selectable/selectable_common.js
new file mode 100644
index 0000000..d00a47b
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/selectable/selectable_common.js
@@ -0,0 +1,21 @@
+TestHelpers.commonWidgetTests("selectable", {
+ defaults: {
+ appendTo: "body",
+ autoRefresh: true,
+ cancel: "input,textarea,button,select,option",
+ delay: 0,
+ disabled: false,
+ distance: 0,
+ filter: "*",
+ tolerance: "touch",
+
+ // callbacks
+ create: null,
+ selected: null,
+ selecting: null,
+ start: null,
+ stop: null,
+ unselected: null,
+ unselecting: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/selectable/selectable_core.js b/apps/it/static/js/ui/tests/unit/selectable/selectable_core.js
new file mode 100644
index 0000000..9953b6c
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/selectable/selectable_core.js
@@ -0,0 +1,3 @@
+/*
+ * selectable_core.js
+ */ \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/selectable/selectable_events.js b/apps/it/static/js/ui/tests/unit/selectable/selectable_events.js
new file mode 100644
index 0000000..ae35fa3
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/selectable/selectable_events.js
@@ -0,0 +1,69 @@
+/*
+ * selectable_events.js
+ */
+(function( $ ) {
+
+module("selectable: events");
+
+test( "start", function() {
+ expect( 2 );
+ var el = $("#selectable1");
+ el.selectable({
+ start: function() {
+ ok( true, "drag fired start callback" );
+ equal( this, el[0], "context of callback" );
+ }
+ });
+ el.simulate( "drag", {
+ dx: 20,
+ dy: 20
+ });
+});
+
+test( "stop", function() {
+ expect( 2 );
+ var el = $("#selectable1");
+ el.selectable({
+ start: function() {
+ ok( true, "drag fired stop callback" );
+ equal( this, el[0], "context of callback" );
+ }
+ });
+ el.simulate( "drag", {
+ dx: 20,
+ dy: 20
+ });
+});
+
+test( "mousedown: initial position of helper", function() {
+ expect( 2 );
+
+ var helperOffset,
+ element = $( "#selectable1" ).selectable(),
+ contentToForceScroll = $( "<div>" ).css({
+ height: "10000px",
+ width: "10000px"
+ });
+
+ contentToForceScroll.appendTo( "body" );
+ $( window ).scrollTop( 100 ).scrollLeft( 100 );
+
+ element.simulate( "mousedown", {
+ clientX: 10,
+ clientY: 10
+ });
+
+ // we do a GTE comparison here because IE7 erroneously subtracts
+ // 2 pixels from a simulated mousedown for clientX/Y
+ // Support: IE7
+ helperOffset = $( ".ui-selectable-helper" ).offset();
+ ok( helperOffset.top >= 99, "Scroll top should be accounted for." );
+ ok( helperOffset.left >= 99, "Scroll left should be accounted for." );
+
+ // Cleanup
+ element.simulate( "mouseup" );
+ contentToForceScroll.remove();
+ $( window ).scrollTop( 0 ).scrollLeft( 0 );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/selectable/selectable_methods.js b/apps/it/static/js/ui/tests/unit/selectable/selectable_methods.js
new file mode 100644
index 0000000..72f9bb2
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/selectable/selectable_methods.js
@@ -0,0 +1,104 @@
+/*
+ * selectable_methods.js
+ */
+(function($) {
+
+module("selectable: methods");
+
+test("init", function() {
+ expect( 5 );
+
+ $("<div></div>").appendTo("body").selectable().remove();
+ ok(true, ".selectable() called on element");
+
+ $([]).selectable().remove();
+ ok(true, ".selectable() called on empty collection");
+
+ $("<div></div>").selectable().remove();
+ ok(true, ".selectable() called on disconnected DOMElement");
+
+ var el = $("<div></div>").selectable();
+ el.selectable("option", "foo");
+ el.remove();
+ ok(true, "arbitrary option getter after init");
+
+ $("<div></div>").selectable().selectable("option", "foo", "bar").remove();
+ ok(true, "arbitrary option setter after init");
+});
+
+test("destroy", function() {
+ expect( 4 );
+
+ $("<div></div>").appendTo("body").selectable().selectable("destroy").remove();
+ ok(true, ".selectable('destroy') called on element");
+
+ $([]).selectable().selectable("destroy").remove();
+ ok(true, ".selectable('destroy') called on empty collection");
+
+ $("<div></div>").selectable().selectable("destroy").remove();
+ ok(true, ".selectable('destroy') called on disconnected DOMElement");
+
+ var expected = $("<div></div>").selectable(),
+ actual = expected.selectable("destroy");
+ equal(actual, expected, "destroy is chainable");
+});
+
+test("enable", function() {
+ expect(3);
+ var expected, actual,
+ fired = false,
+ el = $("#selectable1");
+
+ el.selectable({
+ disabled: true,
+ start: function() { fired = true; }
+ });
+ el.simulate( "drag", {
+ dx: 20,
+ dy: 20
+ });
+ equal(fired, false, "start fired");
+ el.selectable("enable");
+ el.simulate( "drag", {
+ dx: 20,
+ dy: 20
+ });
+ equal(fired, true, "start fired");
+ el.selectable("destroy");
+
+ expected = $("<div></div>").selectable();
+ actual = expected.selectable("enable");
+ equal(actual, expected, "enable is chainable");
+});
+
+test("disable", function() {
+ expect(3);
+ var expected, actual,
+ fired = false,
+ el = $("#selectable1");
+
+ el.selectable({
+ disabled: false,
+ start: function() { fired = true; }
+ });
+ el.simulate( "drag", {
+ dx: 20,
+ dy: 20
+ });
+ equal(fired, true, "start fired");
+ el.selectable("disable");
+ fired = false;
+
+ el.simulate( "drag", {
+ dx: 20,
+ dy: 20
+ });
+ equal(fired, false, "start fired");
+ el.selectable("destroy");
+
+ expected = $("<div></div>").selectable();
+ actual = expected.selectable("disable");
+ equal(actual, expected, "disable is chainable");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/selectable/selectable_options.js b/apps/it/static/js/ui/tests/unit/selectable/selectable_options.js
new file mode 100644
index 0000000..973247f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/selectable/selectable_options.js
@@ -0,0 +1,65 @@
+/*
+ * selectable_options.js
+ */
+(function($) {
+
+module("selectable: options");
+
+test("autoRefresh", function() {
+ expect(3);
+
+ var actual = 0,
+ el = $("#selectable1"),
+ sel = $("*", el),
+ selected = function() { actual += 1; };
+
+ el = $("#selectable1").selectable({ autoRefresh: false, selected: selected });
+ sel.hide();
+ el.simulate( "drag", {
+ dx: 1000,
+ dy: 1000
+ });
+ equal(actual, sel.length);
+ el.selectable("destroy");
+
+ actual = 0;
+ sel.show();
+ el = $("#selectable1").selectable({ autoRefresh: true, selected: selected });
+ sel.hide();
+ el.simulate( "drag", {
+ dx: 1000,
+ dy: 1000
+ });
+ equal(actual, 0);
+
+ sel.show();
+ $( sel[ 0 ] ).simulate( "drag", {
+ dx: 1000,
+ dy: 1000
+ });
+ equal(actual, sel.length);
+
+ el.selectable("destroy");
+ sel.show();
+});
+
+test("filter", function() {
+ expect(2);
+
+ var actual =0,
+ el = $("#selectable1"),
+ sel = $("*", el),
+ selected = function() { actual += 1; };
+
+
+ el = $("#selectable1").selectable({ filter: ".special", selected: selected });
+ el.simulate( "drag", {
+ dx: 1000,
+ dy: 1000
+ });
+ ok(sel.length !== 1, "this test assumes more than 1 selectee");
+ equal(actual, 1);
+ el.selectable("destroy");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/slider/all.html b/apps/it/static/js/ui/tests/unit/slider/all.html
new file mode 100644
index 0000000..a447b98
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/slider/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Slider Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "slider" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Slider Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/slider/slider.html b/apps/it/static/js/ui/tests/unit/slider/slider.html
new file mode 100644
index 0000000..98adfa3
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/slider/slider.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Slider Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.slider" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.slider.js"
+ ]
+ });
+ </script>
+
+ <script src="slider_common.js"></script>
+ <script src="slider_core.js"></script>
+ <script src="slider_events.js"></script>
+ <script src="slider_methods.js"></script>
+ <script src="slider_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Slider Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="slider1"></div>
+<div id="slider3" style="position: relative; margin: 40px; width: 217px; height: 28px;">
+ <div class="ui-slider-handle" style="position: absolute; height: 21px; left: 0px; bottom: 0px; width: 17px;"></div>
+</div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/slider/slider_common.js b/apps/it/static/js/ui/tests/unit/slider/slider_common.js
new file mode 100644
index 0000000..6d7278d
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/slider/slider_common.js
@@ -0,0 +1,23 @@
+TestHelpers.commonWidgetTests( "slider", {
+ defaults: {
+ animate: false,
+ cancel: "input,textarea,button,select,option",
+ delay: 0,
+ disabled: false,
+ distance: 0,
+ max: 100,
+ min: 0,
+ orientation: "horizontal",
+ range: false,
+ step: 1,
+ value: 0,
+ values: null,
+
+ // callbacks
+ create: null,
+ change: null,
+ slide: null,
+ start: null,
+ stop: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/slider/slider_core.js b/apps/it/static/js/ui/tests/unit/slider/slider_core.js
new file mode 100644
index 0000000..3649bde
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/slider/slider_core.js
@@ -0,0 +1,297 @@
+(function( $ ) {
+//
+// Slider Test Helper Functions
+//
+
+var element, options;
+
+function handle() {
+ return element.find( ".ui-slider-handle" );
+}
+
+// Slider Tests
+module( "slider: core" );
+
+test( "keydown HOME on handle sets value to min", function() {
+ expect( 2 );
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "horizontal",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", 0 );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equal(element.slider( "value" ), options.min );
+
+ element.slider( "destroy" );
+
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "vertical",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", 0 );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equal(element.slider( "value" ), options.min) ;
+
+ element.slider( "destroy" );
+});
+
+test( "keydown END on handle sets value to max", function() {
+ expect( 2 );
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "horizontal",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", 0 );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equal(element.slider( "value" ), options.max) ;
+
+ element.slider( "destroy" );
+
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "vertical",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", 0 );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equal(element.slider( "value" ), options.max );
+
+ element.slider( "destroy" );
+});
+
+test( "keydown PAGE_UP on handle increases value by 1/5 range, not greater than max", function() {
+ expect( 4 );
+ $.each( [ "horizontal", "vertical" ], function( i, orientation ) {
+ element = $( "<div></div>" );
+ options = {
+ max: 100,
+ min: 0,
+ orientation: orientation,
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", 70);
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal(element.slider( "value" ), 90);
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equal(element.slider( "value" ), 100);
+
+ element.slider( "destroy" );
+ });
+});
+
+test( "keydown PAGE_DOWN on handle decreases value by 1/5 range, not less than min", function() {
+ expect( 4 );
+ $.each( [ "horizontal", "vertical" ], function( i, orientation ) {
+ element = $( "<div></div>" );
+ options = {
+ max: 100,
+ min: 0,
+ orientation: orientation,
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", 30);
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal(element.slider( "value" ), 10);
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equal(element.slider( "value" ), 0 );
+
+ element.slider( "destroy" );
+ });
+});
+
+test( "keydown UP on handle increases value by step, not greater than max", function() {
+ expect( 4 );
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "horizontal",
+ step: 1
+ };
+ element.slider(options);
+
+ element.slider( "value", options.max - options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal(element.slider( "value" ), options.max );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal(element.slider( "value" ), options.max );
+
+ element.slider( "destroy" );
+
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "vertical",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", options.max - options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal(element.slider( "value" ), options.max );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal(element.slider( "value" ), options.max );
+
+ element.slider( "destroy" );
+});
+
+test( "keydown RIGHT on handle increases value by step, not greater than max", function() {
+ expect( 4 );
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "horizontal",
+ step: 1
+ };
+ element.slider(options);
+
+ element.slider( "value", options.max - options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal(element.slider( "value" ), options.max);
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal(element.slider( "value" ), options.max );
+
+ element.slider( "destroy" );
+
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "vertical",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", options.max - options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal(element.slider( "value" ), options.max );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal(element.slider( "value" ), options.max );
+
+ element.slider( "destroy" );
+});
+
+test( "keydown DOWN on handle decreases value by step, not less than min", function() {
+ expect( 4 );
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "horizontal",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", options.min + options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal(element.slider( "value" ), options.min);
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal(element.slider( "value" ), options.min );
+
+ element.slider( "destroy" );
+
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "vertical",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", options.min + options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal(element.slider( "value" ), options.min);
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal(element.slider( "value" ), options.min );
+
+ element.slider( "destroy" );
+});
+
+test( "keydown LEFT on handle decreases value by step, not less than min", function() {
+ expect( 4 );
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "horizontal",
+ step: 1
+ };
+ element.slider(options);
+
+ element.slider( "value", options.min + options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal(element.slider( "value" ), options.min );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal(element.slider( "value" ), options.min );
+
+ element.slider( "destroy" );
+
+ element = $( "<div></div>" );
+ options = {
+ max: 5,
+ min: -5,
+ orientation: "vertical",
+ step: 1
+ };
+ element.slider( options );
+
+ element.slider( "value", options.min + options.step );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal(element.slider( "value" ), options.min );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equal(element.slider( "value" ), options.min );
+
+ element.slider( "destroy" );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/slider/slider_events.js b/apps/it/static/js/ui/tests/unit/slider/slider_events.js
new file mode 100644
index 0000000..ec93a05
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/slider/slider_events.js
@@ -0,0 +1,152 @@
+(function( $ ) {
+
+module( "slider: events" );
+
+//Specs from http://wiki.jqueryui.com/Slider#specs
+//"change callback: triggers when the slider has stopped moving and has a new
+// value (even if same as previous value), via mouse(mouseup) or keyboard(keyup)
+// or value method/option"
+test( "mouse based interaction", function() {
+ expect( 4 );
+
+ var element = $( "#slider1" )
+ .slider({
+ start: function( event ) {
+ equal( event.originalEvent.type, "mousedown", "start triggered by mousedown" );
+ },
+ slide: function( event) {
+ equal( event.originalEvent.type, "mousemove", "slider triggered by mousemove" );
+ },
+ stop: function( event ) {
+ equal( event.originalEvent.type, "mouseup", "stop triggered by mouseup" );
+ },
+ change: function( event ) {
+ equal( event.originalEvent.type, "mouseup", "change triggered by mouseup" );
+ }
+ });
+
+ element.find( ".ui-slider-handle" ).eq( 0 )
+ .simulate( "drag", { dx: 10, dy: 10 } );
+
+});
+test( "keyboard based interaction", function() {
+ expect( 3 );
+
+ // Test keyup at end of handle slide (keyboard)
+ var element = $( "#slider1" )
+ .slider({
+ start: function( event ) {
+ equal( event.originalEvent.type, "keydown", "start triggered by keydown" );
+ },
+ slide: function() {
+ ok( false, "Slider never triggered by keys" );
+ },
+ stop: function( event ) {
+ equal( event.originalEvent.type, "keyup", "stop triggered by keyup" );
+ },
+ change: function( event ) {
+ equal( event.originalEvent.type, "keyup", "change triggered by keyup" );
+ }
+ });
+
+ element.find( ".ui-slider-handle" ).eq( 0 )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } )
+ .simulate( "keypress", { keyCode: $.ui.keyCode.LEFT } )
+ .simulate( "keyup", { keyCode: $.ui.keyCode.LEFT } );
+
+});
+test( "programmatic event triggers", function() {
+ expect( 6 );
+
+ // Test value method
+ var element = $( "<div></div>" )
+ .slider({
+ change: function() {
+ ok( true, "change triggered by value method" );
+ }
+ })
+ .slider( "value", 0 );
+
+ // Test values method
+ element = $( "<div></div>" )
+ .slider({
+ values: [ 10, 20 ],
+ change: function() {
+ ok( true, "change triggered by values method" );
+ }
+ })
+ .slider( "values", [ 80, 90 ] );
+
+ // Test value option
+ element = $( "<div></div>" )
+ .slider({
+ change: function() {
+ ok( true, "change triggered by value option" );
+ }
+ })
+ .slider( "option", "value", 0 );
+
+ // Test values option
+ element = $( "<div></div>" )
+ .slider({
+ values: [ 10, 20 ],
+ change: function() {
+ ok( true, "change triggered by values option" );
+ }
+ })
+ .slider( "option", "values", [ 80, 90 ] );
+
+});
+
+test( "mouse based interaction part two: when handles overlap", function() {
+ expect( 4 );
+
+ var element = $( "#slider1" )
+ .slider({
+ values: [ 0, 0, 0 ],
+ start: function( event, ui ) {
+ equal( handles.index( ui.handle ), 2, "rightmost handle activated when overlapping at minimum (#3736)" );
+ }
+ }),
+ handles = element.find( ".ui-slider-handle" );
+ handles.eq( 0 ).simulate( "drag", { dx: 10 } );
+ element.slider( "destroy" );
+
+ element = $( "#slider1" )
+ .slider({
+ values: [ 10, 10, 10 ],
+ max: 10,
+ start: function( event, ui ) {
+ equal( handles.index( ui.handle ), 0, "leftmost handle activated when overlapping at maximum" );
+ }
+ }),
+ handles = element.find( ".ui-slider-handle" );
+ handles.eq( 0 ).simulate( "drag", { dx: -10 } );
+ element.slider( "destroy" );
+
+ element = $( "#slider1" )
+ .slider({
+ values: [ 19, 20 ]
+ }),
+ handles = element.find( ".ui-slider-handle" );
+ handles.eq( 0 ).simulate( "drag", { dx: 10 } );
+ element.one( "slidestart", function( event, ui ) {
+ equal( handles.index( ui.handle ), 0, "left handle activated if left was moved last" );
+ });
+ handles.eq( 0 ).simulate( "drag", { dx: 10 } );
+ element.slider( "destroy" );
+
+ element = $( "#slider1" )
+ .slider({
+ values: [ 19, 20 ]
+ }),
+ handles = element.find( ".ui-slider-handle" );
+ handles.eq( 1 ).simulate( "drag", { dx: -10 } );
+ element.one( "slidestart", function( event, ui ) {
+ equal( handles.index( ui.handle ), 1, "right handle activated if right was moved last (#3467)" );
+ });
+ handles.eq( 0 ).simulate( "drag", { dx: 10 } );
+
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/slider/slider_methods.js b/apps/it/static/js/ui/tests/unit/slider/slider_methods.js
new file mode 100644
index 0000000..e13fbd5
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/slider/slider_methods.js
@@ -0,0 +1,96 @@
+(function( $ ) {
+
+module( "slider: methods" );
+
+test( "init", function() {
+ expect(5);
+
+ $( "<div></div>" ).appendTo( "body" ).slider().remove();
+ ok( true, ".slider() called on element" );
+
+ $( [] ).slider().remove();
+ ok( true, ".slider() called on empty collection" );
+
+ $( "<div></div>" ).slider().remove();
+ ok( true, ".slider() called on disconnected DOMElement" );
+
+ var element = $( "<div></div>" ).slider();
+ element.slider( "option", "foo" );
+ element.remove();
+ ok( true, "arbitrary option getter after init" );
+
+ $( "<div></div>" ).slider().slider( "option", "foo", "bar" ).remove();
+ ok( true, "arbitrary option setter after init" );
+});
+
+test( "destroy", function() {
+ expect( 1 );
+ domEqual( "#slider1", function() {
+ $( "#slider1" ).slider().slider( "destroy" );
+ });
+});
+
+test( "enable", function() {
+ expect( 5 );
+ var element,
+ expected = $( "<div></div>" ).slider(),
+ actual = expected.slider( "enable" );
+ equal(actual, expected, "enable is chainable" );
+
+ element = $( "<div></div>" ).slider({ disabled: true });
+ ok( element.hasClass( "ui-state-disabled" ), "slider has ui-state-disabled class before enable method call" );
+ ok( element.hasClass( "ui-slider-disabled" ), "slider has ui-slider-disabled class before enable method call" );
+ element.slider( "enable" );
+ ok( !element.hasClass( "ui-state-disabled" ), "slider does not have ui-state-disabled class after enable method call" );
+ ok( !element.hasClass( "ui-slider-disabled" ), "slider does not have ui-slider-disabled class after enable method call" );
+});
+
+test( "disable", function() {
+ expect( 5 );
+ var element,
+ expected = $( "<div></div>" ).slider(),
+ actual = expected.slider( "disable" );
+ equal(actual, expected, "disable is chainable" );
+
+ element = $( "<div></div>" ).slider({ disabled: false });
+ ok( !element.hasClass( "ui-state-disabled" ), "slider does not have ui-state-disabled class before disabled method call" );
+ ok( !element.hasClass( "ui-slider-disabled" ), "slider does not have ui-slider-disabled class before disable method call" );
+ element.slider( "disable" );
+ ok( element.hasClass( "ui-state-disabled" ), "slider has ui-state-disabled class after disable method call" );
+ ok( element.hasClass( "ui-slider-disabled" ), "slider has ui-slider-disabled class after disable method call" );
+});
+
+test( "value", function() {
+ expect( 17 );
+ $( [ false, "min", "max" ] ).each(function() {
+ var element = $( "<div></div>" ).slider({
+ range: this,
+ value: 5
+ });
+ equal( element.slider( "value" ), 5, "range: " + this + " slider method get" );
+ equal( element.slider( "value", 10), element, "value method is chainable" );
+ equal( element.slider( "value" ), 10, "range: " + this + " slider method set" );
+ element.remove();
+ });
+ var element = $( "<div></div>" ).slider({
+ min: -1, value: 0, max: 1
+ });
+ // min with value option vs value method
+ element.slider( "option", "value", -2 );
+ equal( element.slider( "option", "value" ), -2, "value option does not respect min" );
+ equal( element.slider( "value" ), -1, "value method get respects min" );
+ equal( element.slider( "value", -2 ), element, "value method is chainable" );
+ equal( element.slider( "option", "value" ), -1, "value method set respects min" );
+ // max with value option vs value method
+ element.slider( "option", "value", 2);
+ equal( element.slider( "option", "value" ), 2, "value option does not respect max" );
+ equal( element.slider( "value" ), 1, "value method get respects max" );
+ equal( element.slider( "value", 2 ), element, "value method is chainable" );
+ equal( element.slider( "option", "value" ), 1, "value method set respects max" );
+});
+
+//test( "values", function() {
+// ok(false, "missing test - untested code is broken code." );
+//});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/slider/slider_options.js b/apps/it/static/js/ui/tests/unit/slider/slider_options.js
new file mode 100644
index 0000000..bd62f5d
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/slider/slider_options.js
@@ -0,0 +1,317 @@
+(function( $ ) {
+
+var element, options;
+
+function handle() {
+ return element.find( ".ui-slider-handle" );
+}
+
+module( "slider: options" );
+
+test( "disabled", function(){
+ expect( 8 );
+ var count = 0;
+
+ element = $( "#slider1" ).slider();
+ element.bind( "slidestart", function() {
+ count++;
+ });
+
+ // enabled
+ ok( !element.hasClass( "ui-slider-disabled" ), "no disabled class" );
+ equal( element.slider( "option", "disabled" ), false , "is not disabled" );
+
+ handle().simulate( "drag", { dx: 10 } );
+ equal( count, 1, "slider moved" );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal( count, 2, "slider moved" );
+
+ // disabled
+ element.slider( "option", "disabled", true );
+ ok( element.hasClass( "ui-slider-disabled" ), "has disabled class" );
+ equal( element.slider( "option", "disabled" ), true, "is disabled" );
+
+ handle().simulate( "drag", { dx: 10 } );
+ equal( count, 2, "slider did not move" );
+
+ handle().simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equal( count, 2, "slider did not move" );
+});
+
+test( "max", function() {
+ expect( 2 );
+ element = $( "<div></div>" );
+
+ options = {
+ max: 37,
+ min: 6,
+ orientation: "horizontal",
+ step: 1,
+ value: 50
+ };
+
+ element.slider( options );
+ ok(element.slider( "option", "value" ) === options.value, "value option is not contained by max" );
+ ok(element.slider( "value" ) === options.max, "value method is contained by max" );
+ element.slider( "destroy" );
+
+});
+
+test( "min", function() {
+ expect( 2 );
+ element = $( "<div></div>" );
+
+ options = {
+ max: 37,
+ min: 6,
+ orientation: "vertical",
+ step: 1,
+ value: 2
+ };
+
+ element.slider( options );
+ ok( element.slider( "option", "value" ) === options.value, "value option is not contained by min" );
+ ok( element.slider( "value" ) === options.min, "value method is contained by min" );
+ element.slider( "destroy" );
+
+});
+
+test( "orientation", function() {
+ expect( 6 );
+ element = $( "#slider1" );
+
+ options = {
+ max: 2,
+ min: -2,
+ orientation: "vertical",
+ value: 1
+ };
+
+ var percentVal = ( options.value - options.min ) / ( options.max - options.min ) * 100;
+
+ element.slider( options ).slider( "option", "orientation", "horizontal" );
+ ok( element.is( ".ui-slider-horizontal" ), "horizontal slider has class .ui-slider-horizontal" );
+ ok( !element.is( ".ui-slider-vertical" ), "horizontal slider does not have class .ui-slider-vertical" );
+ equal( handle()[0].style.left, percentVal + "%", "horizontal slider handle is positioned with left: %" );
+
+ element.slider( "destroy" ) ;
+
+ options = {
+ max: 2,
+ min: -2,
+ orientation: "horizontal",
+ value: -1
+ };
+
+ percentVal = ( options.value - options.min ) / ( options.max - options.min ) * 100;
+
+ element.slider( options ).slider( "option", "orientation", "vertical" );
+ ok( element.is( ".ui-slider-vertical" ), "vertical slider has class .ui-slider-vertical" );
+ ok( !element.is( ".ui-slider-horizontal" ), "vertical slider does not have class .ui-slider-horizontal" );
+ equal( handle()[0].style.bottom, percentVal + "%", "vertical slider handle is positioned with bottom: %" );
+
+ element.slider( "destroy" );
+
+});
+
+//spec: http://wiki.jqueryui.com/Slider#specs
+// value option/method: the value option is not restricted by min/max/step.
+// What is returned by the value method is restricted by min (>=), max (<=), and step (even multiple)
+test( "step", function() {
+ expect( 9 );
+ element = $( "<div></div>" ).slider({
+ min: 0,
+ value: 0,
+ step: 10,
+ max: 100
+ });
+ equal( element.slider( "value" ), 0 );
+
+ element.slider( "value", 1 );
+ equal( element.slider( "value" ), 0 );
+
+ element.slider( "value", 9 );
+ equal( element.slider( "value" ), 10 );
+
+ element.slider( "value", 11 );
+ equal( element.slider( "value" ), 10 );
+
+ element.slider( "value", 19 );
+ equal( element.slider( "value" ), 20 );
+
+ element = $( "<div></div>" ).slider({
+ min: 0,
+ value: 0,
+ step: 20,
+ max: 100
+ });
+ element.slider( "value", 0 );
+
+ element.slider( "option", "value", 1 );
+ equal( element.slider( "value" ), 0 );
+
+ element.slider( "option", "value", 9 );
+ equal( element.slider( "value" ), 0 );
+
+ element.slider( "option", "value", 11 );
+ equal( element.slider( "value" ), 20 );
+
+ element.slider( "option", "value", 19 );
+ equal( element.slider( "value" ), 20 );
+
+ element.slider( "destroy" );
+});
+
+//test( "value", function() {
+// ok(false, "missing test - untested code is broken code." );
+//});
+
+test( "values", function() {
+ expect( 2 );
+
+ // testing multiple ranges on the same page, the object reference to the values
+ // property is preserved via multiple range elements, so updating options.values
+ // of 1 slider updates options.values of all the others
+ var ranges = $([
+ document.createElement( "div" ),
+ document.createElement( "div" )
+ ]).slider({
+ range: true,
+ values: [ 25, 75 ]
+ });
+
+ notStrictEqual(
+ ranges.eq( 0 ).data( "ui-slider" ).options.values,
+ ranges.eq( 1 ).data( "ui-slider" ).options.values,
+ "multiple range sliders should not have a reference to the same options.values array"
+ );
+
+ ranges.eq( 0 ).slider( "values", 0, 10 );
+
+ notEqual(
+ ranges.eq( 0 ).slider( "values", 0 ),
+ ranges.eq( 1 ).slider( "values", 0 ),
+ "the values for multiple sliders should be different"
+ );
+});
+
+test( "range", function() {
+ expect( 33 );
+ var range;
+
+ // min
+ element = $( "<div></div>" ).slider({
+ range: "min",
+ min: 1,
+ max: 10,
+ step: 1
+ });
+
+ equal( element.find( ".ui-slider-handle" ).length, 1, "range min, one handle" );
+ equal( element.find( ".ui-slider-range-min" ).length, 1, "range min" );
+ element.slider( "destroy" );
+
+ // max
+ element = $( "<div></div>" ).slider({
+ range: "max",
+ min: 1,
+ max: 10,
+ step: 1
+ });
+
+ equal( element.find( ".ui-slider-handle" ).length, 1, "range max, one handle" );
+ equal( element.find( ".ui-slider-range-max" ).length, 1, "range max" );
+ element.slider( "destroy" );
+
+ // true
+ element = $( "<div></div>" ).slider({
+ range: true,
+ min: 1,
+ max: 10,
+ step: 1
+ });
+
+ range = element.find( ".ui-slider-range" );
+ equal( element.find( ".ui-slider-handle" ).length, 2, "range true, two handles" );
+ ok( !range.is( ".ui-slider-range-min" ), "range true" );
+ ok( !range.is( ".ui-slider-range-max" ), "range true" );
+ element.slider( "destroy" );
+
+ // Change range from min to max
+ element = $( "<div></div>" ).slider({
+ range: "min",
+ min: 1,
+ max: 10,
+ step: 1
+ }).slider( "option", "range", "max" );
+
+ equal( element.find( ".ui-slider-handle" ).length, 1, "range switch from min to max, one handle" );
+ equal( element.find( ".ui-slider-range-min" ).length, 0, "range switch from min to max" );
+ equal( element.find( ".ui-slider-range-max" ).length, 1, "range switch from min to max" );
+ element.slider( "destroy" );
+
+ // Change range from max to min
+ element = $( "<div></div>" ).slider({
+ range: "max",
+ min: 1,
+ max: 10,
+ step: 1
+ }).slider( "option", "range", "min" );
+
+ equal( element.find( ".ui-slider-handle" ).length, 1, "range switch from max to min, one handle" );
+ equal( element.find( ".ui-slider-range-max" ).length, 0, "range switch from max to min" );
+ equal( element.find( ".ui-slider-range-min" ).length, 1, "range switch from max to min" );
+ element.slider( "destroy" );
+
+ // Change range from max to true
+ element = $( "<div></div>" ).slider({
+ range: "max",
+ min: 1,
+ max: 10,
+ step: 1
+ }).slider( "option", "range", true );
+
+ equal( element.find( ".ui-slider-handle" ).length, 2, "range switch from max to true, two handles" );
+ equal( element.find( ".ui-slider-range-max" ).length, 0, "range switch from max to true" );
+ equal( element.find( ".ui-slider-range-min" ).length, 0, "range switch from max to true" );
+ equal( element.slider( "option", "value" ), 0 , "option value" );
+ equal( element.slider( "value" ), 1 , "value" );
+ deepEqual( element.slider( "option", "values" ), [1, 1], "option values" );
+ deepEqual( element.slider( "values" ), [1, 1], "values" );
+ element.slider( "destroy" );
+
+ // Change range from true to min
+ element = $( "<div></div>" ).slider({
+ range: true,
+ min: 1,
+ max: 10,
+ step: 1
+ }).slider( "option", "range", "min" );
+
+ equal( element.find( ".ui-slider-handle" ).length, 1, "range switch from true to min, one handle" );
+ equal( element.find( ".ui-slider-range-max" ).length, 0, "range switch from true to min" );
+ equal( element.find( ".ui-slider-range-min" ).length, 1, "range switch from true to min" );
+ equal( element.slider( "option", "value" ), 1, "value" );
+ equal( element.slider( "value" ), 1 , "value" );
+ equal( element.slider( "option", "values" ), null, "values" );
+ deepEqual( element.slider( "values" ), [] , "values" );
+ element.slider( "destroy" );
+
+ // Change range from true to false
+ element = $( "<div></div>" ).slider({
+ range: true,
+ min: 1,
+ max: 10,
+ step: 1
+ }).slider( "option", "range", false );
+ equal( element.find( ".ui-slider-handle" ).length, 2, "range switch from true to false, both handles remain" );
+ equal( element.find( ".ui-slider-range" ).length, 0, "range switch from true to false" );
+ equal( element.slider( "option", "value" ), 0 , "option value" );
+ equal( element.slider( "value" ), 1 , "value" );
+ deepEqual( element.slider( "option", "values" ), [1, 1], "option values" );
+ deepEqual( element.slider( "values" ), [1, 1], "values" );
+ element.slider( "destroy" );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/sortable/all.html b/apps/it/static/js/ui/tests/unit/sortable/all.html
new file mode 100644
index 0000000..03253b9
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Sortable Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "sortable" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Sortable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/sortable/sortable.html b/apps/it/static/js/ui/tests/unit/sortable/sortable.html
new file mode 100644
index 0000000..8e0bac5
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/sortable.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Sortable Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.mouse.js",
+ "ui/jquery.ui.sortable.js"
+ ]
+ });
+ </script>
+
+ <script src="sortable_common.js"></script>
+ <script src="sortable_core.js"></script>
+ <script src="sortable_events.js"></script>
+ <script src="sortable_methods.js"></script>
+ <script src="sortable_options.js"></script>
+ <script src="sortable_test_helpers.js"></script>
+
+ <script src="../swarminject.js"></script>
+ <style>
+ #sortable, #sortable2 {
+ position:relative;
+ top:0;
+ left:0;
+ padding: 0;
+ margin: 1px;
+ border-width: 0;
+ }
+ #sortable li{
+ padding: 0;
+ margin: 0;
+ border-width: 0;
+ height:19px;
+ }
+ #sortable-table {
+ width: 100%;
+ }
+ </style>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Sortable Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<ul id="sortable">
+ <li>Item 1</li>
+ <li>Item 2</li>
+ <li>Item 3</li>
+ <li>Item 4</li>
+ <li>Item 5</li>
+</ul>
+
+<table id="sortable-table">
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ </tr>
+ <tr>
+ <td>3</td>
+ <td>4</td>
+ </tr>
+ <tr>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ <tr>
+ <td>7</td>
+ <td>8</td>
+ </tr>
+ </tbody>
+</table>
+
+<div id="sortable-images">
+ <img src="../images/jqueryui_32x32.png" alt="">
+ <img src="../images/jqueryui_32x32.png" alt="">
+ <img src="../images/jqueryui_32x32.png" alt="">
+ <img src="../images/jqueryui_32x32.png" alt="">
+</div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/sortable/sortable_common.js b/apps/it/static/js/ui/tests/unit/sortable/sortable_common.js
new file mode 100644
index 0000000..86850a6
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/sortable_common.js
@@ -0,0 +1,45 @@
+TestHelpers.commonWidgetTests( "sortable", {
+ defaults: {
+ appendTo: "parent",
+ axis: false,
+ cancel: "input,textarea,button,select,option",
+ connectWith: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ delay: 0,
+ disabled: false,
+ distance: 1,
+ dropOnEmpty: true,
+ forcePlaceholderSize: false,
+ forceHelperSize: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ items: "> *",
+ opacity: false,
+ placeholder: false,
+ revert: false,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ tolerance: "intersect",
+ zIndex: 1000,
+
+ // callbacks
+ activate: null,
+ beforeStop: null,
+ change: null,
+ create: null,
+ deactivate: null,
+ out: null,
+ over: null,
+ receive: null,
+ remove: null,
+ sort: null,
+ start: null,
+ stop: null,
+ update: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/sortable/sortable_core.js b/apps/it/static/js/ui/tests/unit/sortable/sortable_core.js
new file mode 100644
index 0000000..211f8ac
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/sortable_core.js
@@ -0,0 +1,3 @@
+/*
+ * sortable_core.js
+ */ \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/sortable/sortable_events.js b/apps/it/static/js/ui/tests/unit/sortable/sortable_events.js
new file mode 100644
index 0000000..46a493b
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/sortable_events.js
@@ -0,0 +1,275 @@
+/*
+ * sortable_events.js
+ */
+(function($) {
+
+module("sortable: events");
+
+test("start", function() {
+ expect( 7 );
+
+ var hash;
+ $("#sortable").sortable({
+ start: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dy: 10
+ });
+
+ ok(hash, "start event triggered");
+ ok(hash.helper, "UI hash includes: helper");
+ ok(hash.placeholder, "UI hash includes: placeholder");
+ ok(hash.item, "UI hash includes: item");
+ ok(!hash.sender, "UI hash does not include: sender");
+
+ // todo: see if these events should actually have sane values in them
+ ok("position" in hash, "UI hash includes: position");
+ ok("offset" in hash, "UI hash includes: offset");
+
+
+});
+
+test("sort", function() {
+ expect( 7 );
+
+ var hash;
+ $("#sortable").sortable({
+ sort: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dy: 10
+ });
+
+ ok(hash, "sort event triggered");
+ ok(hash.helper, "UI hash includes: helper");
+ ok(hash.placeholder, "UI hash includes: placeholder");
+ ok(hash.position && ("top" in hash.position && "left" in hash.position), "UI hash includes: position");
+ ok(hash.offset && (hash.offset.top && hash.offset.left), "UI hash includes: offset");
+ ok(hash.item, "UI hash includes: item");
+ ok(!hash.sender, "UI hash does not include: sender");
+
+});
+
+test("change", function() {
+ expect( 8 );
+
+ var hash;
+ $("#sortable").sortable({
+ change: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+
+ ok(!hash, "1px drag, change event should not be triggered");
+
+ $("#sortable").sortable({
+ change: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dy: 22
+ });
+
+ ok(hash, "change event triggered");
+ ok(hash.helper, "UI hash includes: helper");
+ ok(hash.placeholder, "UI hash includes: placeholder");
+ ok(hash.position && ("top" in hash.position && "left" in hash.position), "UI hash includes: position");
+ ok(hash.offset && (hash.offset.top && hash.offset.left), "UI hash includes: offset");
+ ok(hash.item, "UI hash includes: item");
+ ok(!hash.sender, "UI hash does not include: sender");
+
+});
+
+test("beforeStop", function() {
+ expect( 7 );
+
+ var hash;
+ $("#sortable").sortable({
+ beforeStop: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dy: 20
+ });
+
+ ok(hash, "beforeStop event triggered");
+ ok(hash.helper, "UI hash includes: helper");
+ ok(hash.placeholder, "UI hash includes: placeholder");
+ ok(hash.position && ("top" in hash.position && "left" in hash.position), "UI hash includes: position");
+ ok(hash.offset && (hash.offset.top && hash.offset.left), "UI hash includes: offset");
+ ok(hash.item, "UI hash includes: item");
+ ok(!hash.sender, "UI hash does not include: sender");
+
+});
+
+test("stop", function() {
+ expect( 7 );
+
+ var hash;
+ $("#sortable").sortable({
+ stop: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dy: 20
+ });
+
+ ok(hash, "stop event triggered");
+ ok(!hash.helper, "UI should not include: helper");
+ ok(hash.placeholder, "UI hash includes: placeholder");
+ ok(hash.position && ("top" in hash.position && "left" in hash.position), "UI hash includes: position");
+ ok(hash.offset && (hash.offset.top && hash.offset.left), "UI hash includes: offset");
+ ok(hash.item, "UI hash includes: item");
+ ok(!hash.sender, "UI hash does not include: sender");
+
+});
+
+test("update", function() {
+ expect( 8 );
+
+ var hash;
+ $("#sortable").sortable({
+ update: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dx: 1,
+ dy: 1
+ });
+
+ ok(!hash, "1px drag, update event should not be triggered");
+
+ $("#sortable").sortable({
+ update: function( e, ui ) {
+ hash = ui;
+ }
+ }).find("li:eq(0)").simulate( "drag", {
+ dy: 22
+ });
+
+ ok(hash, "update event triggered");
+ ok(!hash.helper, "UI hash should not include: helper");
+ ok(hash.placeholder, "UI hash includes: placeholder");
+ ok(hash.position && ("top" in hash.position && "left" in hash.position), "UI hash includes: position");
+ ok(hash.offset && (hash.offset.top && hash.offset.left), "UI hash includes: offset");
+ ok(hash.item, "UI hash includes: item");
+ ok(!hash.sender, "UI hash does not include: sender");
+
+});
+
+test("#3019: Stop fires too early", function() {
+ expect(2);
+
+ var helper = null,
+ el = $("#sortable").sortable({
+ stop: function(event, ui) {
+ helper = ui.helper;
+ }
+ });
+
+ TestHelpers.sortable.sort($("li", el)[0], 0, 44, 2, "Dragging the sortable");
+ equal(helper, null, "helper should be false");
+
+});
+
+test("#4752: link event firing on sortable with connect list", function () {
+ expect( 10 );
+
+ var fired = {},
+ hasFired = function (type) { return (type in fired) && (true === fired[type]); };
+
+ $("#sortable").clone().attr("id", "sortable2").insertAfter("#sortable");
+
+ $("#qunit-fixture ul").sortable({
+ connectWith: "#qunit-fixture ul",
+ change: function () {
+ fired.change = true;
+ },
+ receive: function () {
+ fired.receive = true;
+ },
+ remove: function () {
+ fired.remove = true;
+ }
+ });
+
+ $("#qunit-fixture ul").bind("click.ui-sortable-test", function () {
+ fired.click = true;
+ });
+
+ $("#sortable li:eq(0)").simulate("click");
+ ok(!hasFired("change"), "Click only, change event should not have fired");
+ ok(hasFired("click"), "Click event should have fired");
+
+ // Drag an item within the first list
+ fired = {};
+ $("#sortable li:eq(0)").simulate("drag", { dx: 0, dy: 40 });
+ ok(hasFired("change"), "40px drag, change event should have fired");
+ ok(!hasFired("receive"), "Receive event should not have fired");
+ ok(!hasFired("remove"), "Remove event should not have fired");
+ ok(!hasFired("click"), "Click event should not have fired");
+
+ // Drag an item from the first list to the second, connected list
+ fired = {};
+ $("#sortable li:eq(0)").simulate("drag", { dx: 0, dy: 150 });
+ ok(hasFired("change"), "150px drag, change event should have fired");
+ ok(hasFired("receive"), "Receive event should have fired");
+ ok(hasFired("remove"), "Remove event should have fired");
+ ok(!hasFired("click"), "Click event should not have fired");
+});
+
+/*
+test("receive", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("remove", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+*/
+
+test( "over", function() {
+ expect( 8 );
+
+ var hash,
+ overCount = 0;
+
+ $( "#sortable" ).sortable({
+ over: function( e, ui ) {
+ hash = ui;
+ overCount++;
+ }
+ }).find( "li:eq(0)" ).simulate( "drag", {
+ dy: 20
+ });
+
+ ok( hash, "stop event triggered" );
+ ok( hash.helper, "UI should not include: helper" );
+ ok( hash.placeholder, "UI hash includes: placeholder" );
+ ok( hash.position && ( "top" in hash.position && "left" in hash.position ), "UI hash includes: position" );
+ ok( hash.offset && ( hash.offset.top && hash.offset.left ), "UI hash includes: offset" );
+ ok( hash.item, "UI hash includes: item" );
+ ok( hash.sender, "UI hash does not include: sender" );
+ equal( overCount, 1, "over fires only once" );
+});
+
+/*
+test("out", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("activate", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("deactivate", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+*/
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/sortable/sortable_methods.js b/apps/it/static/js/ui/tests/unit/sortable/sortable_methods.js
new file mode 100644
index 0000000..07a7bc7
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/sortable_methods.js
@@ -0,0 +1,92 @@
+/*
+ * sortable_methods.js
+ */
+(function($) {
+
+module("sortable: methods");
+
+test("init", function() {
+ expect(5);
+
+ $("<div></div>").appendTo("body").sortable().remove();
+ ok(true, ".sortable() called on element");
+
+ $([]).sortable();
+ ok(true, ".sortable() called on empty collection");
+
+ $("<div></div>").sortable();
+ ok(true, ".sortable() called on disconnected DOMElement");
+
+ $("<div></div>").sortable().sortable("option", "foo");
+ ok(true, "arbitrary option getter after init");
+
+ $("<div></div>").sortable().sortable("option", "foo", "bar");
+ ok(true, "arbitrary option setter after init");
+});
+
+test("destroy", function() {
+ expect(4);
+ $("<div></div>").appendTo("body").sortable().sortable("destroy").remove();
+ ok(true, ".sortable('destroy') called on element");
+
+ $([]).sortable().sortable("destroy");
+ ok(true, ".sortable('destroy') called on empty collection");
+
+ $("<div></div>").sortable().sortable("destroy");
+ ok(true, ".sortable('destroy') called on disconnected DOMElement");
+
+ var expected = $("<div></div>").sortable(),
+ actual = expected.sortable("destroy");
+ equal(actual, expected, "destroy is chainable");
+});
+
+test("enable", function() {
+ expect(5);
+
+ var el, actual, expected;
+
+ el = $("#sortable").sortable({ disabled: true });
+
+ TestHelpers.sortable.sort($("li", el)[0], 0, 44, 0, ".sortable({ disabled: true })");
+
+ el.sortable("enable");
+ equal(el.sortable("option", "disabled"), false, "disabled option getter");
+
+ el.sortable("destroy");
+ el.sortable({ disabled: true });
+ el.sortable("option", "disabled", false);
+ equal(el.sortable("option", "disabled"), false, "disabled option setter");
+
+ TestHelpers.sortable.sort($("li", el)[0], 0, 44, 2, ".sortable('option', 'disabled', false)");
+
+ expected = $("<div></div>").sortable(),
+ actual = expected.sortable("enable");
+ equal(actual, expected, "enable is chainable");
+});
+
+test("disable", function() {
+ expect(7);
+
+ var el, actual, expected;
+
+ el = $("#sortable").sortable({ disabled: false });
+ TestHelpers.sortable.sort($("li", el)[0], 0, 44, 2, ".sortable({ disabled: false })");
+
+ el.sortable("disable");
+ TestHelpers.sortable.sort($("li", el)[0], 0, 44, 0, "disabled.sortable getter");
+
+ el.sortable("destroy");
+
+ el.sortable({ disabled: false });
+ TestHelpers.sortable.sort($("li", el)[0], 0, 44, 2, ".sortable({ disabled: false })");
+ el.sortable("option", "disabled", true);
+ equal(el.sortable("option", "disabled"), true, "disabled option setter");
+ ok(el.sortable("widget").is(":not(.ui-state-disabled)"), "sortable element does not get ui-state-disabled since it's an interaction");
+ TestHelpers.sortable.sort($("li", el)[0], 0, 44, 0, ".sortable('option', 'disabled', true)");
+
+ expected = $("<div></div>").sortable(),
+ actual = expected.sortable("disable");
+ equal(actual, expected, "disable is chainable");
+});
+
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/sortable/sortable_options.js b/apps/it/static/js/ui/tests/unit/sortable/sortable_options.js
new file mode 100644
index 0000000..f2beb4d
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/sortable_options.js
@@ -0,0 +1,460 @@
+/*
+ * sortable_options.js
+ */
+(function($) {
+
+module("sortable: options");
+
+/*
+test("{ appendTo: 'parent' }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ appendTo: Selector }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+*/
+
+test( "{ axis: false }, default", function() {
+ expect( 2 );
+
+ var offsetAfter,
+ element = $( "#sortable" ).sortable({
+ axis: false,
+ change: function() {
+ offsetAfter = item.offset();
+ notEqual( offsetAfter.left, offsetBefore.left, "x axis not constrained when axis: false" );
+ notEqual( offsetAfter.top, offsetBefore.top, "y axis not constrained when axis: false" );
+ }
+ }),
+ item = element.find( "li" ).eq( 0 ),
+ offsetBefore = item.offset();
+
+ item.simulate( "drag", {
+ dx: 50,
+ dy: 25,
+ moves: 1
+ });
+});
+
+test( "{ axis: 'x' }", function() {
+ expect( 2 );
+
+ var offsetAfter,
+ element = $( "#sortable" ).sortable({
+ axis: "x",
+ change: function() {
+ offsetAfter = item.offset();
+ notEqual( offsetAfter.left, offsetBefore.left, "x axis not constrained when axis: x" );
+ equal( offsetAfter.top, offsetBefore.top, "y axis constrained when axis: x" );
+ }
+ }),
+ item = element.find( "li" ).eq( 0 ),
+ offsetBefore = item.offset();
+
+ item.simulate( "drag", {
+ dx: 50,
+ dy: 25,
+ moves: 1
+ });
+});
+
+test( "{ axis: 'y' }", function() {
+ expect( 2 );
+
+ var offsetAfter,
+ element = $( "#sortable" ).sortable({
+ axis: "y",
+ change: function() {
+ offsetAfter = item.offset();
+ equal( offsetAfter.left, offsetBefore.left, "x axis constrained when axis: y" );
+ notEqual( offsetAfter.top, offsetBefore.top, "y axis not constrained when axis: y" );
+ }
+ }),
+ item = element.find( "li" ).eq( 0 ),
+ offsetBefore = item.offset();
+
+ item.simulate( "drag", {
+ dx: 50,
+ dy: 25,
+ moves: 1
+ });
+});
+
+asyncTest( "#7415: Incorrect revert animation with axis: 'y'", function() {
+ expect( 2 );
+ var expectedLeft,
+ element = $( "#sortable" ).sortable({
+ axis: "y",
+ revert: true,
+ stop: start,
+ sort: function() {
+ expectedLeft = item.css( "left" );
+ }
+ }),
+ item = element.find( "li" ).eq( 0 );
+
+ item.simulate( "drag", {
+ dy: 300,
+ dx: 50
+ });
+
+ setTimeout(function() {
+ var top = parseFloat( item.css( "top" ) );
+ equal( item.css( "left" ), expectedLeft, "left not animated" );
+ ok( top > 0 && top < 300, "top is animated" );
+ }, 100 );
+});
+
+/*
+test("{ cancel: 'input,textarea,button,select,option' }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ cancel: Selector }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+*/
+
+test( "#8792: issues with floated items in connected lists", function() {
+ expect( 2 );
+
+ var element,
+ changeCount = 0;
+
+ $( "#qunit-fixture" )
+ .html( "<ul class='c'><li>a</li><li>a</li></ul><ul class='c'><li>a</li><li>a</li></ul>" )
+ .find( "ul" ).css({ "float": "left", width: "100px" }).end()
+ .find( "li" ).css({ "float": "left", width: "50px", height: "50px" });
+
+ $( "#qunit-fixture .c" ).sortable({
+ connectWith: "#qunit-fixture .c",
+ change: function() {
+ changeCount++;
+ }
+ });
+
+ element = $( "#qunit-fixture li:eq(0)" );
+
+ // move the first li to the right of the second li in the first ul
+ element.simulate( "drag", {
+ dx: 55,
+ moves: 15
+ });
+
+ equal( changeCount, 1, "change fired only once (no jitters) when dragging a floated sortable in it's own container" );
+
+ // move the first li ( which is now in the second spot )
+ // through the first spot in the second ul to the second spot in the second ul
+ element.simulate( "drag", {
+ dx: 100,
+ moves: 15
+ });
+
+ equal( changeCount, 3, "change fired once for each expected change when dragging a floated sortable to a connected container" );
+});
+
+test( "#8301: single axis with connected list", function() {
+ expect( 1 );
+
+ var element = $( "#sortable" ).sortable({
+ axis: "y",
+ tolerance: "pointer",
+ connectWith: ".connected"
+ });
+
+ $( "<ul class='connected'><li>Item 7</li><li>Item 8</li></ul>" )
+ .sortable({
+ axis: "y",
+ tolerance: "pointer",
+ connectWith: "#sortable",
+ receive: function() {
+ ok( true, "connected list received item" );
+ }
+ })
+ .insertAfter( element );
+
+ element.find( "li" ).eq( 0 ).simulate( "drag", {
+ handle: "corner",
+ dy: 120,
+ moves: 1
+ });
+});
+
+/*
+test("{ connectWith: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ connectWith: Selector }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ containment: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ containment: Element }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ containment: 'document' }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ containment: 'parent' }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ containment: 'window' }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ containment: Selector }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ cursor: 'auto' }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ cursor: 'move' }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ cursorAt: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ cursorAt: true }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ delay: 0 }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ delay: 100 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ distance: 1 }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ distance: 10 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ dropOnEmpty: true }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ dropOnEmpty: false }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ forcePlaceholderSize: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ forcePlaceholderSize: true }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ forceHelperSize: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ forceHelperSize: true }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ grid: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ grid: [17, 3] }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ grid: [3, 7] }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ handle: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ handle: Element }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ handle: Selector }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ helper: 'original' }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ helper: Function }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ items: '> *' }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ items: Selector }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ opacity: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ opacity: .37 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ opacity: 1 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ placeholder: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+*/
+
+test( "{ placeholder: false } img", function() {
+ expect( 3 );
+
+ var element = $( "#sortable-images" ).sortable({
+ start: function( event, ui ) {
+ ok( ui.placeholder.attr( "src" ).indexOf( "images/jqueryui_32x32.png" ) > 0, "placeholder img has correct src" );
+ equal( ui.placeholder.height(), 32, "placeholder has correct height" );
+ equal( ui.placeholder.width(), 32, "placeholder has correct width" );
+ }
+ });
+
+ element.find( "img" ).eq( 0 ).simulate( "drag", {
+ dy: 1
+ });
+});
+
+test( "{ placeholder: String }", function() {
+ expect( 1 );
+
+ var element = $( "#sortable" ).sortable({
+ placeholder: "test",
+ start: function( event, ui ) {
+ ok( ui.placeholder.hasClass( "test" ), "placeholder has class" );
+ }
+ });
+
+ element.find( "li" ).eq( 0 ).simulate( "drag", {
+ dy: 1
+ });
+});
+
+test( "{ placholder: String } tr", function() {
+ expect( 4 );
+
+ var originalWidths,
+ element = $( "#sortable-table tbody" ).sortable({
+ placeholder: "test",
+ start: function( event, ui ) {
+ var currentWidths = otherRow.children().map(function() {
+ return $( this ).width();
+ }).get();
+ ok( ui.placeholder.hasClass( "test" ), "placeholder has class" );
+ deepEqual( currentWidths, originalWidths, "table cells maintian size" );
+ equal( ui.placeholder.children().length, dragRow.children().length,
+ "placeholder has correct number of cells" );
+ equal( ui.placeholder.children().html(), $( "<span>&#160;</span>" ).html(),
+ "placeholder td has content for forced dimensions" );
+ }
+ }),
+ rows = element.children( "tr" ),
+ dragRow = rows.eq( 0 ),
+ otherRow = rows.eq( 1 );
+
+ originalWidths = otherRow.children().map(function() {
+ return $( this ).width();
+ }).get();
+ dragRow.simulate( "drag", {
+ dy: 1
+ });
+});
+
+/*
+test("{ revert: false }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ revert: true }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scroll: true }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scroll: false }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scrollSensitivity: 20 }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scrollSensitivity: 2 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scrollSensitivity: 200 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scrollSpeed: 20 }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scrollSpeed: 2 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scrollSpeed: 200 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scope: 'default' }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ scope: ??? }, unexpected", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ tolerance: 'intersect' }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ tolerance: 'pointer' }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ zIndex: 1000 }, default", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ zIndex: 1 }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+
+test("{ zIndex: false }", function() {
+ ok(false, "missing test - untested code is broken code.");
+});
+*/
+})(jQuery);
diff --git a/apps/it/static/js/ui/tests/unit/sortable/sortable_test_helpers.js b/apps/it/static/js/ui/tests/unit/sortable/sortable_test_helpers.js
new file mode 100644
index 0000000..12e4829
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/sortable/sortable_test_helpers.js
@@ -0,0 +1,9 @@
+TestHelpers.sortable = {
+ sort: function( handle, dx, dy, index, msg ) {
+ $( handle ).simulate( "drag", {
+ dx: dx,
+ dy: dy
+ });
+ equal( $( handle ).parent().children().index( handle ), index, msg );
+ }
+}; \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/spinner/all.html b/apps/it/static/js/ui/tests/unit/spinner/all.html
new file mode 100644
index 0000000..bc180d4
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Spinner Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "spinner" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Spinner Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/spinner/spinner.html b/apps/it/static/js/ui/tests/unit/spinner/spinner.html
new file mode 100644
index 0000000..1d09bbc
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/spinner.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Spinner Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <script src="../../../external/jquery.mousewheel.js"></script>
+ <script src="../../../external/globalize.js"></script>
+ <script src="../../../external/globalize.culture.ja-JP.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.button", "ui.spinner" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.button.js",
+ "ui/jquery.ui.spinner.js"
+ ]
+ });
+ </script>
+
+ <script src="spinner_test_helpers.js"></script>
+ <script src="spinner_common.js"></script>
+ <script src="spinner_core.js"></script>
+ <script src="spinner_events.js"></script>
+ <script src="spinner_methods.js"></script>
+ <script src="spinner_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Spinner Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<input id="spin" class="foo">
+<input id="spin2" value="2">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/spinner/spinner_common.js b/apps/it/static/js/ui/tests/unit/spinner/spinner_common.js
new file mode 100644
index 0000000..b494e3c
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/spinner_common.js
@@ -0,0 +1,23 @@
+TestHelpers.commonWidgetTests( "spinner", {
+ defaults: {
+ culture: null,
+ disabled: false,
+ icons: {
+ down: "ui-icon-triangle-1-s",
+ up: "ui-icon-triangle-1-n"
+ },
+ incremental: true,
+ max: null,
+ min: null,
+ numberFormat: null,
+ page: 10,
+ step: 1,
+
+ // callbacks
+ change: null,
+ create: null,
+ spin: null,
+ start: null,
+ stop: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/spinner/spinner_core.js b/apps/it/static/js/ui/tests/unit/spinner/spinner_core.js
new file mode 100644
index 0000000..03088fe
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/spinner_core.js
@@ -0,0 +1,238 @@
+(function( $ ) {
+
+var simulateKeyDownUp = TestHelpers.spinner.simulateKeyDownUp;
+
+module( "spinner: core" );
+
+test( "keydown UP on input, increases value not greater than max", function() {
+ expect( 5 );
+ var element = $( "#spin" ).val( 70 ).spinner({
+ max: 100,
+ step: 10
+ });
+
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ equal( element.val(), 80 );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ equal( element.val(), 90 );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ equal( element.val(), 100 );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ equal( element.val(), 100 );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ equal( element.val(), 100 );
+});
+
+test( "keydown DOWN on input, decreases value not less than min", function() {
+ expect( 5 );
+ var element = $( "#spin" ).val( 50 ).spinner({
+ min: 20,
+ step: 10
+ });
+
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ equal( element.val(), 40 );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ equal( element.val(), 30 );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ equal( element.val(), 20 );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ equal( element.val(), 20 );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ equal( element.val(), 20 );
+});
+
+test( "keydown PAGE_UP on input, increases value not greater than max", function() {
+ expect( 5 );
+ var element = $( "#spin" ).val( 70 ).spinner({
+ max: 100,
+ page: 10
+ });
+
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ equal( element.val(), 80 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ equal( element.val(), 90 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ equal( element.val(), 100 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ equal( element.val(), 100 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ equal( element.val(), 100 );
+});
+
+test( "keydown PAGE_DOWN on input, decreases value not less than min", function() {
+ expect( 5 );
+ var element = $( "#spin" ).val( 50 ).spinner({
+ min: 20,
+ page: 10
+ });
+
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ equal( element.val(), 40 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ equal( element.val(), 30 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ equal( element.val(), 20 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ equal( element.val(), 20 );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ equal( element.val(), 20 );
+});
+
+asyncTest( "blur input while spinning with UP", function() {
+ expect( 3 );
+ var value,
+ element = $( "#spin" ).val( 10 ).spinner();
+
+ function step1() {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equal( element.val(), 11 );
+ setTimeout( step2, 750 );
+ }
+
+ function step2() {
+ value = element.val();
+ ok( value > 11, "repeating while key is down" );
+
+ element.bind( "blur", function() {
+ value = element.val();
+ setTimeout( step3, 750 );
+ })[ 0 ].blur();
+ }
+
+ function step3() {
+ equal( element.val(), value, "stopped repeating on blur" );
+ start();
+ }
+
+ element[ 0 ].focus();
+ setTimeout( step1 );
+});
+
+test( "mouse click on up button, increases value not greater than max", function() {
+ expect( 3 );
+ var element = $( "#spin" ).val( 18 ).spinner({
+ max: 20
+ }),
+ button = element.spinner( "widget" ).find( ".ui-spinner-up" );
+
+ button.trigger( "mousedown" ).trigger( "mouseup" );
+ equal( element.val(), 19 );
+ button.trigger( "mousedown" ).trigger( "mouseup" );
+ equal( element.val(), 20 );
+ button.trigger( "mousedown" ).trigger( "mouseup" );
+ equal( element.val(), 20 );
+});
+
+test( "mouse click on up button, increases value not greater than max", function() {
+ expect( 3 );
+ var element = $( "#spin" ).val( 2 ).spinner({
+ min: 0
+ }),
+ button = element.spinner( "widget" ).find( ".ui-spinner-down" );
+
+ button.trigger( "mousedown" ).trigger( "mouseup" );
+ equal( element.val(), 1 );
+ button.trigger( "mousedown" ).trigger( "mouseup" );
+ equal( element.val(), 0 );
+ button.trigger( "mousedown" ).trigger( "mouseup" );
+ equal( element.val(), 0 );
+});
+
+test( "mousewheel on input", function() {
+ expect( 4 );
+
+ var element = $( "#spin" ).val( 0 ).spinner({
+ step: 2
+ });
+
+ element.trigger( "mousewheel" );
+ equal( element.val(), 0, "mousewheel event without delta does not change value" );
+
+ element.trigger( "mousewheel", 1 );
+ equal( element.val(), 2 );
+
+ element.trigger( "mousewheel", -0.2 );
+ equal( element.val(), 0 );
+
+ element.trigger( "mousewheel", -15 );
+ equal(element.val(), -2 );
+});
+
+test( "reading HTML5 attributes", function() {
+ expect( 6 );
+ var markup = "<input type='number' min='-100' max='100' value='5' step='2'>",
+ element = $( markup ).spinner();
+ equal( element.spinner( "option", "min" ), -100, "min from markup" );
+ equal( element.spinner( "option", "max" ), 100, "max from markup" );
+ equal( element.spinner( "option", "step" ), 2, "step from markup" );
+
+ element = $( markup ).spinner({
+ min: -200,
+ max: 200,
+ step: 5
+ });
+ equal( element.spinner( "option", "min" ), -200, "min from options" );
+ equal( element.spinner( "option", "max" ), 200, "max from options" );
+ equal( element.spinner( "option", "step" ), 5, "stop from options" );
+});
+
+test( "ARIA attributes", function() {
+ expect( 9 );
+ var element = $( "#spin" ).val( 2 ).spinner({ min: -5, max: 5 });
+
+ equal( element.attr( "role" ), "spinbutton", "role" );
+ equal( element.attr( "aria-valuemin" ), "-5", "aria-valuemin" );
+ equal( element.attr( "aria-valuemax" ), "5", "aria-valuemax" );
+ equal( element.attr( "aria-valuenow" ), "2", "aria-valuenow" );
+
+ element.spinner( "stepUp" );
+
+ equal( element.attr( "aria-valuenow" ), "3", "stepUp 1 step changes aria-valuenow" );
+
+ element.spinner( "option", { min: -10, max: 10 } );
+
+ equal( element.attr( "aria-valuemin" ), "-10", "min option changed aria-valuemin changes" );
+ equal( element.attr( "aria-valuemax" ), "10", "max option changed aria-valuemax changes" );
+
+ element.spinner( "option", "min", null );
+ equal( element.attr( "aria-valuemin" ), undefined, "aria-valuemin not set when no min" );
+
+ element.spinner( "option", "max", null );
+ equal( element.attr( "aria-valuemax" ), undefined, "aria-valuemax not set when no max" );
+});
+
+test( "focus text field when pressing button", function() {
+ expect( 2 );
+ var element = $( "#spin" ).spinner();
+ $( "body" ).focus();
+ ok( element[ 0 ] !== document.activeElement, "not focused before" );
+ element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown();
+ ok( element[ 0 ] === document.activeElement, "focused after" );
+});
+
+test( "don't clear invalid value on blur", function() {
+ expect( 1 );
+ var element = $( "#spin" ).spinner();
+ element.focus().val( "a" ).blur();
+ equal( element.val(), "a" );
+});
+
+test( "precision", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 0.05 ).spinner({
+ step: 0.0001
+ });
+ element.spinner( "stepUp" );
+ equal( element.val(), "0.0501", "precision from step" );
+
+ element.val( 1.05 ).spinner( "option", {
+ step: 1,
+ min: -9.95
+ });
+ element.spinner( "stepDown" );
+ equal( element.val(), "0.05", "precision from min" );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/spinner/spinner_events.js b/apps/it/static/js/ui/tests/unit/spinner/spinner_events.js
new file mode 100644
index 0000000..610f7a2
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/spinner_events.js
@@ -0,0 +1,259 @@
+(function( $ ) {
+
+var simulateKeyDownUp = TestHelpers.spinner.simulateKeyDownUp;
+
+module( "spinner: events" );
+
+test( "start", function() {
+ expect( 10 );
+ var element = $( "#spin" ).spinner();
+
+ function shouldStart( expectation, msg ) {
+ element.spinner( "option", "start", function() {
+ ok( expectation, msg );
+ });
+ }
+
+ shouldStart( true, "key UP" );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ shouldStart( true, "key DOWN" );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+
+ shouldStart( true, "key PAGE_UP" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ shouldStart( true, "key PAGE_DOWN" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+
+ shouldStart( true, "button up" );
+ element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup();
+ shouldStart( true, "button down" );
+ element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup();
+
+ shouldStart( true, "stepUp" );
+ element.spinner( "stepUp" );
+ shouldStart( true, "stepDown" );
+ element.spinner( "stepDown" );
+
+ shouldStart( true, "pageUp" );
+ element.spinner( "pageUp" );
+ shouldStart( true, "pageDown" );
+ element.spinner( "pageDown" );
+
+ shouldStart( false, "value" );
+ element.spinner( "value", 999 );
+});
+
+test( "spin", function() {
+ expect( 10 );
+ var element = $( "#spin" ).spinner();
+
+ function shouldSpin( expectation, msg ) {
+ element.spinner( "option", "spin", function() {
+ ok( expectation, msg );
+ });
+ }
+
+ shouldSpin( true, "key UP" );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ shouldSpin( true, "key DOWN" );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+
+ shouldSpin( true, "key PAGE_UP" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ shouldSpin( true, "key PAGE_DOWN" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+
+ shouldSpin( true, "button up" );
+ element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup();
+ shouldSpin( true, "button down" );
+ element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup();
+
+ shouldSpin( true, "stepUp" );
+ element.spinner( "stepUp" );
+ shouldSpin( true, "stepDown" );
+ element.spinner( "stepDown" );
+
+ shouldSpin( true, "pageUp" );
+ element.spinner( "pageUp" );
+ shouldSpin( true, "pageDown" );
+ element.spinner( "pageDown" );
+
+ shouldSpin( false, "value" );
+ element.spinner( "value", 999 );
+});
+
+test( "stop", function() {
+ expect( 10 );
+ var element = $( "#spin" ).spinner();
+
+ function shouldStop( expectation, msg ) {
+ element.spinner( "option", "stop", function() {
+ ok( expectation, msg );
+ });
+ }
+
+ shouldStop( true, "key UP" );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ shouldStop( true, "key DOWN" );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+
+ shouldStop( true, "key PAGE_UP" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ shouldStop( true, "key PAGE_DOWN" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+
+ shouldStop( true, "button up" );
+ element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup();
+ shouldStop( true, "button down" );
+ element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup();
+
+ shouldStop( true, "stepUp" );
+ element.spinner( "stepUp" );
+ shouldStop( true, "stepDown" );
+ element.spinner( "stepDown" );
+
+ shouldStop( true, "pageUp" );
+ element.spinner( "pageUp" );
+ shouldStop( true, "pageDown" );
+ element.spinner( "pageDown" );
+
+ shouldStop( false, "value" );
+ element.spinner( "value", 999 );
+});
+
+asyncTest( "change", function() {
+ expect( 14 );
+ var element = $( "#spin" ).spinner();
+
+ function shouldChange( expectation, msg ) {
+ element.spinner( "option", "change", function() {
+ ok( expectation, msg );
+ });
+ }
+
+ function focusWrap( fn, next ) {
+ element[0].focus();
+ setTimeout( function() {
+ fn();
+ setTimeout(function() {
+ element[0].blur();
+ setTimeout( next );
+ });
+ });
+ }
+
+ function step1() {
+ focusWrap(function() {
+ shouldChange( false, "key UP, before blur" );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ shouldChange( true, "blur after key UP" );
+ }, step2 );
+ }
+
+ function step2() {
+ focusWrap(function() {
+ shouldChange( false, "key DOWN, before blur" );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ shouldChange( true, "blur after key DOWN" );
+ }, step3 );
+ }
+
+ function step3() {
+ focusWrap(function() {
+ shouldChange( false, "key PAGE_UP, before blur" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ shouldChange( true, "blur after key PAGE_UP" );
+ }, step4 );
+ }
+
+ function step4() {
+ focusWrap(function() {
+ shouldChange( false, "key PAGE_DOWN, before blur" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ shouldChange( true, "blur after key PAGE_DOWN" );
+ }, step5 );
+ }
+
+ function step5() {
+ focusWrap(function() {
+ shouldChange( false, "many keys, before blur" );
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ shouldChange( true, "blur after many keys" );
+ }, step6 );
+ }
+
+ function step6() {
+ focusWrap(function() {
+ shouldChange( false, "many keys, same final value, before blur" );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ shouldChange( false, "blur after many keys, same final value" );
+
+ shouldChange( false, "button up, before blur" );
+ element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup();
+ shouldChange( true, "blur after button up" );
+ }, step7 );
+ }
+
+ function step7() {
+ focusWrap(function() {
+ shouldChange( false, "button down, before blur" );
+ element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup();
+ shouldChange( true, "blur after button down" );
+ }, step8 );
+ }
+
+ function step8() {
+ focusWrap(function() {
+ shouldChange( false, "many buttons, same final value, before blur" );
+ element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup();
+ element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup();
+ element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup();
+ element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup();
+ shouldChange( false, "blur after many buttons, same final value" );
+ }, step9 );
+ }
+
+ function step9() {
+ shouldChange( true, "stepUp" );
+ element.spinner( "stepUp" );
+
+ shouldChange( true, "stepDown" );
+ element.spinner( "stepDown" );
+
+ shouldChange( true, "pageUp" );
+ element.spinner( "pageUp" );
+
+ shouldChange( true, "pageDown" );
+ element.spinner( "pageDown" );
+
+ shouldChange( true, "value" );
+ element.spinner( "value", 999 );
+
+ shouldChange( false, "value, same value" );
+ element.spinner( "value", 999 );
+
+ shouldChange( true, "max, value changed" );
+ element.spinner( "option", "max", 900 );
+
+ shouldChange( false, "max, value not changed" );
+ element.spinner( "option", "max", 1000 );
+
+ shouldChange( true, "min, value changed" );
+ element.spinner( "option", "min", 950 );
+
+ shouldChange( false, "min, value not changed" );
+ element.spinner( "option", "min", 200 );
+ start();
+ }
+
+ setTimeout( step1 );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/spinner/spinner_methods.js b/apps/it/static/js/ui/tests/unit/spinner/spinner_methods.js
new file mode 100644
index 0000000..af872f2
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/spinner_methods.js
@@ -0,0 +1,174 @@
+(function( $ ) {
+
+var simulateKeyDownUp = TestHelpers.spinner.simulateKeyDownUp;
+
+module( "spinner: methods" );
+
+test( "destroy", function() {
+ expect( 1 );
+ domEqual( "#spin", function() {
+ $( "#spin" ).spinner().spinner( "destroy" );
+ });
+});
+
+test( "disable", function() {
+ expect( 14 );
+ var element = $( "#spin" ).val( 2 ).spinner(),
+ wrapper = $( "#spin" ).spinner( "widget" );
+
+ ok( !wrapper.hasClass( "ui-spinner-disabled" ), "before: wrapper does not have ui-spinner-disabled class" );
+ ok( !element.is( ":disabled" ), "before: input does not have disabled attribute" );
+
+ element.spinner( "disable" );
+ ok( wrapper.hasClass( "ui-spinner-disabled" ), "after: wrapper has ui-spinner-disabled class" );
+ ok( element.is( ":disabled"), "after: input has disabled attribute" );
+
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ equal( 2, element.val(), "keyboard - value does not change on key UP" );
+
+ simulateKeyDownUp( element, $.ui.keyCode.DOWN );
+ equal( 2, element.val(), "keyboard - value does not change on key DOWN" );
+
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_UP );
+ equal( 2, element.val(), "keyboard - value does not change on key PGUP" );
+
+ simulateKeyDownUp( element, $.ui.keyCode.PAGE_DOWN );
+ equal( 2, element.val(), "keyboard - value does not change on key PGDN" );
+
+ wrapper.find( ".ui-spinner-up" ).trigger( "mousedown" ).trigger( "mouseup" );
+ equal( 2, element.val(), "mouse - value does not change on clicking up button" );
+
+ wrapper.find( ".ui-spinner-down" ).trigger( "mousedown" ).trigger( "mouseup" );
+ equal( 2, element.val(), "mouse - value does not change on clicking down button" );
+
+ element.spinner( "stepUp", 6 );
+ equal( 8, element.val(), "script - stepUp 6 steps changes value");
+
+ element.spinner( "stepDown" );
+ equal( 7, element.val(), "script - stepDown 1 step changes value" );
+
+ element.spinner( "pageUp" );
+ equal( 17, element.val(), "script - pageUp 1 page changes value" );
+
+ element.spinner( "pageDown" );
+ equal( 7, element.val(), "script - pageDown 1 page changes value" );
+});
+
+test( "enable", function() {
+ expect( 5 );
+ var element = $( "#spin" ).val( 1 ).spinner({ disabled: true }),
+ wrapper = element.spinner( "widget" );
+
+ ok( wrapper.hasClass( "ui-spinner-disabled" ), "before: wrapper has ui-spinner-disabled class" );
+ ok( element.is( ":disabled" ), "before: input has disabled attribute" );
+
+ element.spinner( "enable" );
+
+ ok( !wrapper.hasClass( ".ui-spinner-disabled" ), "after: wrapper does not have ui-spinner-disabled class" );
+ ok( !element.is( ":disabled" ), "after: input does not have disabled attribute" );
+
+ simulateKeyDownUp( element, $.ui.keyCode.UP );
+ equal( 2, element.val(), "keyboard - value changes on key UP" );
+});
+
+test( "pageDown", function() {
+ expect( 4 );
+ var element = $( "#spin" ).val( -12 ).spinner({
+ page: 20,
+ min: -100
+ });
+
+ element.spinner( "pageDown" );
+ equal( element.val(), -32, "pageDown 1 page" );
+
+ element.spinner( "pageDown", 3 );
+ equal( element.val(), -92, "pageDown 3 pages" );
+
+ element.spinner( "pageDown" );
+ equal( element.val(), -100, "value close to min and pageDown 1 page" );
+
+ element.spinner( "pageDown", 10 );
+ equal( element.val(), -100, "value at min and pageDown 10 pages" );
+});
+
+test( "pageUp", function() {
+ expect( 4 );
+ var element = $( "#spin" ).val( 12 ).spinner({
+ page: 20,
+ max: 100
+ });
+
+ element.spinner( "pageUp" );
+ equal( element.val(), 32, "pageUp 1 page" );
+
+ element.spinner( "pageUp", 3 );
+ equal( element.val(), 92, "pageUp 3 pages" );
+
+ element.spinner( "pageUp" );
+ equal( element.val(), 100, "value close to max and pageUp 1 page" );
+
+ element.spinner( "pageUp", 10 );
+ equal( element.val(), 100, "value at max and pageUp 10 pages" );
+});
+
+test( "stepDown", function() {
+ expect( 4 );
+ var element = $( "#spin" ).val( 0 ).spinner({
+ step: 2,
+ min: -15
+ });
+
+ element.spinner( "stepDown" );
+ equal( element.val(), "-1", "stepDown 1 step" );
+
+ element.spinner( "stepDown", 5 );
+ equal( element.val(), "-11", "stepDown 5 steps" );
+
+ element.spinner( "stepDown", 4 );
+ equal( element.val(), "-15", "close to min and stepDown 4 steps" );
+
+ element.spinner( "stepDown" );
+ equal( element.val(), "-15", "at min and stepDown 1 step" );
+});
+
+test( "stepUp", function() {
+ expect( 4 );
+ var element = $( "#spin" ).val( 0 ).spinner({
+ step: 2,
+ max: 16
+ });
+
+ element.spinner( "stepUp" );
+ equal( element.val(), 2, "stepUp 1 step" );
+
+ element.spinner( "stepUp", 5 );
+ equal( element.val(), 12, "stepUp 5 steps" );
+
+ element.spinner( "stepUp", 4 );
+ equal( element.val(), 16, "close to min and stepUp 4 steps" );
+
+ element.spinner( "stepUp" );
+ equal( element.val(), 16, "at max and stepUp 1 step" );
+});
+
+test( "value", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 0 ).spinner({
+ step: 3
+ });
+
+ element.spinner( "value", 10 );
+ equal( element.val(), 9, "change value via value method" );
+
+ equal( element.spinner( "value" ), 9, "get value via value method" );
+});
+
+test( "widget", function() {
+ expect( 2 );
+ var element = $( "#spin" ).spinner(),
+ widgetElement = element.spinner( "widget" );
+ equal( widgetElement.length, 1, "one element" );
+ strictEqual( widgetElement[ 0 ], element.parent()[ 0 ], "parent element" );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/spinner/spinner_options.js b/apps/it/static/js/ui/tests/unit/spinner/spinner_options.js
new file mode 100644
index 0000000..6f3650f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/spinner_options.js
@@ -0,0 +1,262 @@
+(function( $ ) {
+
+module( "spinner: options" );
+
+// culture is tested after numberFormat, since it depends on numberFormat
+
+test( "icons: default ", function() {
+ expect( 4 );
+ var element = $( "#spin" ).val( 0 ).spinner();
+ equal( element.spinner( "widget" ).find( ".ui-icon:first" ).attr( "class" ), "ui-icon ui-icon-triangle-1-n" );
+ equal( element.spinner( "widget" ).find( ".ui-icon:last" ).attr( "class" ), "ui-icon ui-icon-triangle-1-s" );
+
+ element.spinner( "option", "icons", {
+ up: "ui-icon-carat-1-n",
+ down: "ui-icon-carat-1-s"
+ });
+ equal( element.spinner( "widget" ).find( ".ui-icon:first" ).attr( "class" ), "ui-icon ui-icon-carat-1-n" );
+ equal( element.spinner( "widget" ).find( ".ui-icon:last" ).attr( "class" ), "ui-icon ui-icon-carat-1-s" );
+});
+
+test( "icons: custom ", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 0 ).spinner({
+ icons: {
+ down: "custom-down",
+ up: "custom-up"
+ }
+ }).spinner( "widget" );
+ equal( element.find( ".ui-icon:first" ).attr( "class" ), "ui-icon custom-up" );
+ equal( element.find( ".ui-icon:last" ).attr( "class" ), "ui-icon custom-down" );
+});
+
+test( "incremental, false", function() {
+ expect( 100 );
+
+ var i,
+ prev = 0,
+ element = $( "#spin" ).val( prev ).spinner({
+ incremental: false,
+ spin: function( event, ui ) {
+ equal( ui.value - prev, 1 );
+ prev = ui.value;
+ }
+ });
+
+ for ( i = 0; i < 100; i++ ) {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ }
+ element.simulate( "keyup", { keyCode: $.ui.keyCode.UP } );
+});
+
+test( "incremental, true", function() {
+ expect( 100 );
+
+ function fill( num, val ) {
+ return $.map( new Array( num ), function() {
+ return val;
+ });
+ }
+
+ var i,
+ prev = 0,
+ expected = [].concat( fill( 18, 1 ), fill( 37, 2 ), fill( 14, 3 ),
+ fill( 9, 4 ), fill( 6, 5 ), fill( 5, 6 ), fill ( 5, 7 ),
+ fill( 4, 8 ), fill( 2, 9 ) ),
+ element = $( "#spin" ).val( prev ).spinner({
+ incremental: true,
+ spin: function( event, ui ) {
+ equal( ui.value - prev, expected[ i ] );
+ prev = ui.value;
+ }
+ });
+
+ for ( i = 0; i < 100; i++ ) {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ }
+ element.simulate( "keyup", { keyCode: $.ui.keyCode.UP } );
+});
+
+test( "incremental, function", function() {
+ expect( 100 );
+
+ var i,
+ prev = 0,
+ element = $( "#spin" ).val( prev ).spinner({
+ incremental: function( i ) {
+ return i;
+ },
+ spin: function( event, ui ) {
+ equal( ui.value - prev, i + 1 );
+ prev = ui.value;
+ }
+ });
+
+ for ( i = 0; i < 100; i++ ) {
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ }
+ element.simulate( "keyup", { keyCode: $.ui.keyCode.UP } );
+});
+
+test( "numberFormat, number", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 0 ).spinner({ numberFormat: "n" });
+ equal( element.val(), "0.00", "formatted on init" );
+ element.spinner( "stepUp" );
+ equal( element.val(), "1.00", "formatted after step" );
+});
+
+test( "numberFormat, number, simple", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 0 ).spinner({ numberFormat: "n0" });
+ equal( element.val(), "0", "formatted on init" );
+ element.spinner( "stepUp" );
+ equal( element.val(), "1", "formatted after step" );
+});
+
+test( "numberFormat, currency", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 0 ).spinner({ numberFormat: "C" });
+ equal( element.val(), "$0.00", "formatted on init" );
+ element.spinner( "stepUp" );
+ equal( element.val(), "$1.00", "formatted after step" );
+});
+
+test( "numberFormat, change", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 5 ).spinner({ numberFormat: "n1" });
+ equal( element.val(), "5.0", "formatted on init" );
+ element.spinner( "option", "numberFormat", "c" );
+ equal( element.val(), "$5.00", "formatted after change" );
+});
+
+test( "culture, null", function() {
+ expect( 2 );
+ Globalize.culture( "ja-JP" );
+ var element = $( "#spin" ).val( 0 ).spinner({ numberFormat: "C" });
+ equal( element.val(), "¥0", "formatted on init" );
+ element.spinner( "stepUp" );
+ equal( element.val(), "¥1", "formatted after step" );
+
+ // reset culture
+ Globalize.culture( "default" );
+});
+
+test( "currency, ja-JP", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 0 ).spinner({
+ numberFormat: "C",
+ culture: "ja-JP"
+ });
+ equal( element.val(), "¥0", "formatted on init" );
+ element.spinner( "stepUp" );
+ equal( element.val(), "¥1", "formatted after step" );
+});
+
+test( "currency, change", function() {
+ expect( 2 );
+ var element = $( "#spin" ).val( 5 ).spinner({
+ numberFormat: "C",
+ culture: "ja-JP"
+ });
+ equal( element.val(), "¥5", "formatted on init" );
+ element.spinner( "option", "culture", "en" );
+ equal( element.val(), "$5.00", "formatted after change" );
+});
+
+test( "max", function() {
+ expect( 3 );
+ var element = $( "#spin" ).val( 1000 ).spinner({ max: 100 });
+ equal( element.val(), 1000, "value not constrained on init" );
+
+ element.spinner( "value", 1000 );
+ equal( element.val(), 100, "max constrained in value method" );
+
+ element.val( 1000 ).blur();
+ equal( element.val(), 1000, "max not constrained if manual entry" );
+});
+
+test( "max, string", function() {
+ expect( 3 );
+ var element = $( "#spin" )
+ .val( 1000 )
+ .spinner({
+ max: "$100.00",
+ numberFormat: "C",
+ culture: "en"
+ });
+ equal( element.val(), "$1,000.00", "value not constrained on init" );
+ equal( element.spinner( "option", "max" ), 100, "option converted to number" );
+
+ element.spinner( "value", 1000 );
+ equal( element.val(), "$100.00", "max constrained in value method" );
+});
+
+test( "min", function() {
+ expect( 3 );
+ var element = $( "#spin" ).val( -1000 ).spinner({ min: -100 });
+ equal( element.val(), -1000, "value not constrained on init" );
+
+ element.spinner( "value", -1000 );
+ equal( element.val(), -100, "min constrained in value method" );
+
+ element.val( -1000 ).blur();
+ equal( element.val(), -1000, "min not constrained if manual entry" );
+});
+
+test( "min, string", function() {
+ expect( 3 );
+ var element = $( "#spin" )
+ .val( -1000 )
+ .spinner({
+ min: "-$100.00",
+ numberFormat: "C",
+ culture: "en"
+ });
+ equal( element.val(), "($1,000.00)", "value not constrained on init" );
+ equal( element.spinner( "option", "min" ), -100, "option converted to number" );
+
+ element.spinner( "value", -1000 );
+ equal( element.val(), "($100.00)", "min constrained in value method" );
+});
+
+test( "step, 2", function() {
+ expect( 3 );
+ var element = $( "#spin" ).val( 0 ).spinner({ step: 2 });
+
+ element.spinner( "stepUp" );
+ equal( element.val(), "2", "stepUp" );
+
+ element.spinner( "value", "10.5" );
+ equal( element.val(), "10", "value reset to 10" );
+
+ element.val( "4.5" );
+ element.spinner( "stepUp" );
+ equal( element.val(), "6", "stepUp" );
+});
+
+test( "step, 0.7", function() {
+ expect( 1 );
+ var element = $("#spin").val( 0 ).spinner({
+ step: 0.7
+ });
+
+ element.spinner( "stepUp" );
+ equal( element.val(), "0.7", "stepUp" );
+});
+
+test( "step, string", function() {
+ expect( 2 );
+ var element = $("#spin").val( 0 ).spinner({
+ step: "$0.70",
+ numberFormat: "C",
+ culture: "en"
+ });
+
+ equal( element.spinner( "option", "step" ), 0.7, "option converted to number" );
+
+ element.spinner( "stepUp" );
+ equal( element.val(), "$0.70", "stepUp" );
+});
+
+})( jQuery );
diff --git a/apps/it/static/js/ui/tests/unit/spinner/spinner_test_helpers.js b/apps/it/static/js/ui/tests/unit/spinner/spinner_test_helpers.js
new file mode 100644
index 0000000..2021e8f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/spinner/spinner_test_helpers.js
@@ -0,0 +1,8 @@
+TestHelpers.spinner = {
+ simulateKeyDownUp: function( element, keyCode, shift ) {
+ element
+ .simulate( "keydown", { keyCode: keyCode, shiftKey: shift || false } )
+ .simulate( "keyup", { keyCode: keyCode, shiftKey: shift || false } );
+ }
+};
+
diff --git a/apps/it/static/js/ui/tests/unit/subsuite.js b/apps/it/static/js/ui/tests/unit/subsuite.js
new file mode 100644
index 0000000..c81b20f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/subsuite.js
@@ -0,0 +1,25 @@
+(function() {
+
+var versions = [
+ "1.6", "1.6.1", "1.6.2", "1.6.3", "1.6.4",
+ "1.7", "1.7.1", "1.7.2",
+ "1.8.0", "1.8.1", "1.8.2", "1.8.3",
+ "1.9.0", "1.9.1",
+ "1.10.0", "1.10.1", "1.10.2",
+ "git"
+ ],
+ additionalTests = {
+ // component: [ "other_test.html" ]
+ };
+
+window.testAllVersions = function( widget ) {
+ QUnit.testSuites( $.map(
+ [ widget + ".html" ].concat( additionalTests[ widget ] || [] ),
+ function( test ) {
+ return $.map( versions, function( version ) {
+ return test + "?jquery=" + version;
+ });
+ }));
+};
+
+}());
diff --git a/apps/it/static/js/ui/tests/unit/swarminject.js b/apps/it/static/js/ui/tests/unit/swarminject.js
new file mode 100644
index 0000000..ebd3ccf
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/swarminject.js
@@ -0,0 +1,10 @@
+// load testswarm agent
+(function() {
+ var url = window.location.search;
+ url = decodeURIComponent( url.slice( url.indexOf("swarmURL=") + 9 ) );
+ if ( !url || url.indexOf("http") !== 0 ) {
+ return;
+ }
+ document.write( "<scr" + "ipt src='http://swarm.jquery.org/js/inject.js?" +
+ (new Date()).getTime() + "'></scr" + "ipt>" );
+})();
diff --git a/apps/it/static/js/ui/tests/unit/tabs/all.html b/apps/it/static/js/ui/tests/unit/tabs/all.html
new file mode 100644
index 0000000..355a05d
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Tabs Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "tabs" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Tabs Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/tabs/data/test.html b/apps/it/static/js/ui/tests/unit/tabs/data/test.html
new file mode 100644
index 0000000..cd59e64
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/data/test.html
@@ -0,0 +1 @@
+<p>&#8230;content loaded via Ajax.</p> \ No newline at end of file
diff --git a/apps/it/static/js/ui/tests/unit/tabs/tabs.html b/apps/it/static/js/ui/tests/unit/tabs/tabs.html
new file mode 100644
index 0000000..7c79823
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/tabs.html
@@ -0,0 +1,155 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Tabs Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.tabs" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.tabs.js"
+ ]
+ });
+ </script>
+
+ <script src="tabs_test_helpers.js"></script>
+ <script src="tabs_common.js"></script>
+ <script src="tabs_core.js"></script>
+ <script src="tabs_events.js"></script>
+ <script src="tabs_methods.js"></script>
+ <script src="tabs_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+ <style>
+ #tabs8, #tabs8 * {
+ margin: 0;
+ padding: 0;
+ font-size: 12px;
+ line-height: 15px;
+ }
+ </style>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Tabs Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="tabs1">
+ <ul>
+ <li><a href="#fragment-1"><span>1</span></a></li>
+ <li><a href="#fragment-2"><span>2</span></a></li>
+ <li><a href="#fragment-3"><span>3</span></a></li>
+ </ul>
+ <div id="fragment-1"></div>
+ <div id="fragment-2"></div>
+ <div id="fragment-3"></div>
+</div>
+
+<div id="tabs2">
+ <ul>
+ <li><a href="#colon:test"><span>1</span></a></li>
+ <li><a href="#inline-style"><span>2</span></a></li>
+ <li><a href="data/test.html#test"><span>3</span></a></li>
+ <li aria-controls="custom-id"><a href="data/test.html"><span>4</span></a></li>
+ <li><a href="data/test.html" title="∫ßáö Սե"><span>5</span></a></li>
+ </ul>
+ <div id="colon:test"></div>
+ <div style="height: 300px;" id="inline-style"></div>
+ <div id="custom-id"></div>
+</div>
+
+<div id="tabs3">
+ <div>
+ <ul id="tabs3-list">
+ <li><a href="#tabs3-1">1</a></li>
+ </ul>
+ </div>
+</div>
+
+<div id="tabs4">
+ <ul id="tabs4-list">
+ <li><a href="#tabs4-1">1</a></li>
+ </ul>
+ <ol>
+ <li><a href="#tabs4-1">1</a></li>
+ </ol>
+</div>
+
+<div id="tabs4a">
+ <ol id="tabs4a-list">
+ <li><a href="#tabs4a-1">1</a></li>
+ </ol>
+ <ul>
+ <li><a href="#tabs4a-1">1</a></li>
+ </ul>
+</div>
+
+<div id="tabs5">
+ <div>
+ <ul id="tabs5-list"></ul>
+ </div>
+</div>
+
+<div id="tabs6">
+ <ul id="tabs6-list">
+ <li><a href="#tabs6-1">1</a>
+ <ul>
+ <li><a href="#item6-3">3</a></li>
+ <li><a href="#item6-4">4</a></li>
+ </ul>
+ </li>
+ <li><a href="#tabs6-2">2</a></li>
+ </ul>
+ <div id="tabs6-1"></div>
+ <div id="tabs6-2"></div>
+</div>
+
+<div id="tabs7">
+ <ul id="tabs7-list">
+ <li><a href="#tabs7-1">1</a></li>
+ <li><a href="#tabs7-2">2</a></li>
+ </ul>
+ <div id="tabs7-2"></div>
+ <div id="tabs7-1"></div>
+</div>
+
+<div id="tabs8Wrapper">
+ <div id="tabs8">
+ <ul id="tabs8-list">
+ <li><a href="#tabs8-1">1</a></li>
+ <li><a href="#tabs8-2">2</a></li>
+ </ul>
+ <div id="tabs8-1">
+ <p>Lorem ipsum</p>
+ <p>Lorem ipsum</p>
+ <p>Lorem ipsum</p>
+ </div>
+ <div id="tabs8-2">
+ <p>Lorem ipsum</p>
+ </div>
+ </div>
+</div>
+
+<div id="tabs9">
+ <ul>
+ <li>not a tab</li>
+ <li><a href="#tabs9-1">tab</a></li>
+ </ul>
+ <div id="tabs9-1"></div>
+</div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/tabs/tabs_common.js b/apps/it/static/js/ui/tests/unit/tabs/tabs_common.js
new file mode 100644
index 0000000..a589515
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/tabs_common.js
@@ -0,0 +1,18 @@
+TestHelpers.commonWidgetTests( "tabs", {
+ defaults: {
+ active: null,
+ collapsible: false,
+ disabled: false,
+ event: "click",
+ heightStyle: "content",
+ hide: null,
+ show: null,
+
+ // callbacks
+ activate: null,
+ beforeActivate: null,
+ beforeLoad: null,
+ create: null,
+ load: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/tabs/tabs_core.js b/apps/it/static/js/ui/tests/unit/tabs/tabs_core.js
new file mode 100644
index 0000000..5f70206
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/tabs_core.js
@@ -0,0 +1,615 @@
+(function( $ ) {
+
+var state = TestHelpers.tabs.state;
+
+module( "tabs: core" );
+
+test( "markup structure", function() {
+ expect( 3 );
+ var element = $( "#tabs1" ).tabs();
+ ok( element.hasClass( "ui-tabs" ), "main element is .ui-tabs" );
+ ok( element.find( "ul" ).hasClass( "ui-tabs-nav" ), "list item is .ui-tabs-nav" );
+ equal( element.find( ".ui-tabs-panel" ).length, 3,
+ ".ui-tabs-panel elements exist, correct number" );
+});
+
+$.each({
+ "deep ul": "#tabs3",
+ "multiple lists, ul first": "#tabs4",
+ "multiple lists, ol first": "#tabs5",
+ "empty list": "#tabs6"
+}, function( type, selector ) {
+ test( "markup structure: " + type, function() {
+ expect( 2 );
+ var element = $( selector ).tabs();
+ ok( element.hasClass( "ui-tabs" ), "main element is .ui-tabs" );
+ ok( $( selector + "-list" ).hasClass( "ui-tabs-nav" ),
+ "list item is .ui-tabs-nav" );
+ });
+});
+
+// #5893 - Sublist in the tab list are considered as tab
+test( "nested list", function() {
+ expect( 1 );
+
+ var element = $( "#tabs6" ).tabs();
+ equal( element.data( "ui-tabs" ).anchors.length, 2, "should contain 2 tab" );
+});
+
+test( "disconnected from DOM", function() {
+ expect( 2 );
+
+ var element = $( "#tabs1" ).remove().tabs();
+ equal( element.find( ".ui-tabs-nav" ).length, 1, "should initialize nav" );
+ equal( element.find( ".ui-tabs-panel" ).length, 3, "should initialize panels" );
+});
+
+test( "non-tab list items", function() {
+ expect( 2 );
+
+ var element = $( "#tabs9" ).tabs();
+ equal( element.tabs( "option", "active" ), 0, "defaults to first tab" );
+ equal( element.find( ".ui-tabs-nav li.ui-state-active" ).index(), 1,
+ "first actual tab is active" );
+});
+
+test( "aria-controls", function() {
+ expect( 7 );
+ var element = $( "#tabs1" ).tabs(),
+ tabs = element.find( ".ui-tabs-nav li" );
+ tabs.each(function() {
+ var tab = $( this ),
+ anchor = tab.find( ".ui-tabs-anchor" );
+ equal( anchor.prop( "hash" ).substring( 1 ), tab.attr( "aria-controls" ) );
+ });
+
+ element = $( "#tabs2" ).tabs();
+ tabs = element.find( ".ui-tabs-nav li" );
+ equal( tabs.eq( 0 ).attr( "aria-controls" ), "colon:test" );
+ equal( tabs.eq( 1 ).attr( "aria-controls" ), "inline-style" );
+ ok( /^ui-tabs-\d+$/.test( tabs.eq( 2 ).attr( "aria-controls" ) ), "generated id" );
+ equal( tabs.eq( 3 ).attr( "aria-controls" ), "custom-id" );
+});
+
+test( "accessibility", function() {
+ expect( 49 );
+ var element = $( "#tabs1" ).tabs({
+ active: 1,
+ disabled: [ 2 ]
+ }),
+ tabs = element.find( ".ui-tabs-nav li" ),
+ anchors = tabs.find( ".ui-tabs-anchor" ),
+ panels = element.find( ".ui-tabs-panel" );
+
+ equal( element.find( ".ui-tabs-nav" ).attr( "role" ), "tablist", "tablist role" );
+ tabs.each(function( index ) {
+ var tab = tabs.eq( index ),
+ anchor = anchors.eq( index ),
+ anchorId = anchor.attr( "id" ),
+ panel = panels.eq( index );
+ equal( tab.attr( "role" ), "tab", "tab " + index + " role" );
+ equal( tab.attr( "aria-labelledby" ), anchorId, "tab " + index + " aria-labelledby" );
+ equal( anchor.attr( "role" ), "presentation", "anchor " + index + " role" );
+ equal( anchor.attr( "tabindex" ), -1, "anchor " + index + " tabindex" );
+ equal( panel.attr( "role" ), "tabpanel", "panel " + index + " role" );
+ equal( panel.attr( "aria-labelledby" ), anchorId, "panel " + index + " aria-labelledby" );
+ });
+
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "true", "active tab has aria-selected=true" );
+ equal( tabs.eq( 1 ).attr( "tabindex" ), 0, "active tab has tabindex=0" );
+ equal( tabs.eq( 1 ).attr( "aria-disabled" ), null, "enabled tab does not have aria-disabled" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "true", "active panel has aria-expanded=true" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "false", "active panel has aria-hidden=false" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( tabs.eq( 0 ).attr( "tabindex" ), -1, "inactive tab has tabindex=-1" );
+ equal( tabs.eq( 0 ).attr( "aria-disabled" ), null, "enabled tab does not have aria-disabled" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "false", "inactive panel has aria-expanded=false" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "inactive panel has aria-hidden=true" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( tabs.eq( 2 ).attr( "tabindex" ), -1, "inactive tab has tabindex=-1" );
+ equal( tabs.eq( 2 ).attr( "aria-disabled" ), "true", "disabled tab has aria-disabled=true" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "inactive panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "inactive panel has aria-hidden=true" );
+
+ element.tabs( "option", "active", 0 );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "active tab has aria-selected=true" );
+ equal( tabs.eq( 0 ).attr( "tabindex" ), 0, "active tab has tabindex=0" );
+ equal( tabs.eq( 0 ).attr( "aria-disabled" ), null, "enabled tab does not have aria-disabled" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "active panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "active panel has aria-hidden=false" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( tabs.eq( 1 ).attr( "tabindex" ), -1, "inactive tab has tabindex=-1" );
+ equal( tabs.eq( 1 ).attr( "aria-disabled" ), null, "enabled tab does not have aria-disabled" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "inactive panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "inactive panel has aria-hidden=true" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" );
+ equal( tabs.eq( 2 ).attr( "tabindex" ), -1, "inactive tab has tabindex=-1" );
+ equal( tabs.eq( 2 ).attr( "aria-disabled" ), "true", "disabled tab has aria-disabled=true" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "inactive panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "inactive panel has aria-hidden=true" );
+});
+
+asyncTest( "accessibility - ajax", function() {
+ expect( 4 );
+ var element = $( "#tabs2" ).tabs(),
+ panel = $( "#custom-id" );
+
+ equal( panel.attr( "aria-live" ), "polite", "remote panel has aria-live" );
+ equal( panel.attr( "aria-busy" ), null, "does not have aria-busy on init" );
+ element.tabs( "option", "active", 3 );
+ equal( panel.attr( "aria-busy" ), "true", "panel has aria-busy during load" );
+ element.one( "tabsload", function() {
+ setTimeout(function() {
+ equal( panel.attr( "aria-busy" ), null, "panel does not have aria-busy after load" );
+ start();
+ }, 1 );
+ });
+});
+
+asyncTest( "keyboard support - LEFT, RIGHT, UP, DOWN, HOME, END, SPACE, ENTER", function() {
+ expect( 92 );
+ var element = $( "#tabs1" ).tabs({
+ collapsible: true
+ }),
+ tabs = element.find( ".ui-tabs-nav li" ),
+ panels = element.find( ".ui-tabs-panel" ),
+ keyCode = $.ui.keyCode;
+
+ element.data( "ui-tabs" ).delay = 50;
+
+ equal( tabs.filter( ".ui-state-focus" ).length, 0, "no tabs focused on init" );
+ tabs.eq( 0 ).simulate( "focus" );
+
+ // down, right, down (wrap), up (wrap)
+ function step1() {
+ ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab has focus" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN } );
+ ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next tab" );
+ ok( !tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab is no longer focused" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "true", "second tab has aria-selected=true" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.RIGHT } );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.DOWN } );
+ ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first tab" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.UP } );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step2, 100 );
+ }
+
+ // left, home, space
+ function step2() {
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" );
+ ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "true", "third panel has aria-expanded=true" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "false", "first panel has aria-expanded=false" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.LEFT } );
+ ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous tab" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "true", "second tab has aria-selected=true" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+ ok( panels.eq( 2 ).is( ":visible" ), "third panel is still visible" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "true", "third panel has aria-expanded=true" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+
+ tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.HOME } );
+ ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first tab" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel is still hidden" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "false", "first panel has aria-expanded=false" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+ ok( panels.eq( 2 ).is( ":visible" ), "third panel is still visible" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "true", "third panel has aria-expanded=true" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+
+ // SPACE activates, cancels delay
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.SPACE } );
+ setTimeout( step3, 1 );
+ }
+
+ // end, enter
+ function step3() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.END } );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ // ENTER activates, cancels delay
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.ENTER } );
+ setTimeout( step4, 1 );
+ }
+
+ // enter (collapse)
+ function step4() {
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "true", "third panel has aria-expanded=true" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "false", "first panel has aria-expanded=false" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+
+ // ENTER collapses if active
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.ENTER } );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+ setTimeout( start, 1 );
+ }
+
+ setTimeout( step1, 1 );
+});
+
+asyncTest( "keyboard support - CTRL navigation", function() {
+ expect( 115 );
+ var element = $( "#tabs1" ).tabs(),
+ tabs = element.find( ".ui-tabs-nav li" ),
+ panels = element.find( ".ui-tabs-panel" ),
+ keyCode = $.ui.keyCode;
+
+ element.data( "ui-tabs" ).delay = 50;
+
+ equal( tabs.filter( ".ui-state-focus" ).length, 0, "no tabs focused on init" );
+ tabs.eq( 0 ).simulate( "focus" );
+
+ // down
+ function step1() {
+ ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab has focus" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN, ctrlKey: true } );
+ ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next tab" );
+ ok( !tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab is no longer focused" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step2, 100 );
+ }
+
+ // right
+ function step2() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+
+ tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.RIGHT, ctrlKey: true } );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step3, 100 );
+ }
+
+ // down (wrap)
+ function step3() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.DOWN, ctrlKey: true } );
+ ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first tab" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step4, 100 );
+ }
+
+ // up (wrap)
+ function step4() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step5, 100 );
+ }
+
+ // left
+ function step5() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.LEFT, ctrlKey: true } );
+ ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous tab" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step6, 100 );
+ }
+
+ // home
+ function step6() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+
+ tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.HOME, ctrlKey: true } );
+ ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first tab" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step7, 100 );
+ }
+
+ // end
+ function step7() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.END, ctrlKey: true } );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+ setTimeout( step8, 100 );
+ }
+
+ // space
+ function step8() {
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.SPACE } );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" );
+ ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "true", "third panel has aria-expanded=true" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "false", "first panel has aria-expanded=false" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+
+ setTimeout( start, 1 );
+ }
+
+ setTimeout( step1, 1 );
+});
+
+asyncTest( "keyboard support - CTRL+UP, ALT+PAGE_DOWN, ALT+PAGE_UP", function() {
+ expect( 50 );
+ var element = $( "#tabs1" ).tabs(),
+ tabs = element.find( ".ui-tabs-nav li" ),
+ panels = element.find( ".ui-tabs-panel" ),
+ keyCode = $.ui.keyCode;
+
+ equal( tabs.filter( ".ui-state-focus" ).length, 0, "no tabs focused on init" );
+ panels.attr( "tabindex", -1 );
+ panels.eq( 0 ).simulate( "focus" );
+
+ function step1() {
+ strictEqual( document.activeElement, panels[ 0 ], "first panel is activeElement" );
+
+ panels.eq( 0 ).simulate( "keydown", { keyCode: keyCode.PAGE_DOWN, altKey: true } );
+ strictEqual( document.activeElement, tabs[ 1 ], "second tab is activeElement" );
+ ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "ALT+PAGE_DOWN moves focus to next tab" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "true", "second tab has aria-selected=true" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel is visible" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "true", "second panel has aria-expanded=true" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "false", "second panel has aria-hidden=false" );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "false", "first panel has aria-expanded=false" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+
+ tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.PAGE_DOWN, altKey: true } );
+ strictEqual( document.activeElement, tabs[ 2 ], "third tab is activeElement" );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "ALT+PAGE_DOWN moves focus to next tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "true", "third panel has aria-expanded=true" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+ ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "false", "second panel has aria-expanded=false" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.PAGE_DOWN, altKey: true } );
+ strictEqual( document.activeElement, tabs[ 0 ], "first tab is activeElement" );
+ ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "ALT+PAGE_DOWN wraps focus to first tab" );
+ equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "true", "first panel has aria-expanded=true" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+ panels.eq( 0 ).simulate( "focus" );
+ setTimeout( step2, 1 );
+ }
+
+ function step2() {
+ strictEqual( document.activeElement, panels[ 0 ], "first panel is activeElement" );
+
+ panels.eq( 0 ).simulate( "keydown", { keyCode: keyCode.PAGE_UP, altKey: true } );
+ strictEqual( document.activeElement, tabs[ 2 ], "third tab is activeElement" );
+ ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "ALT+PAGE_UP wraps focus to last tab" );
+ equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+ ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "true", "third panel has aria-expanded=true" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" );
+ equal( panels.eq( 0 ).attr( "aria-expanded" ), "false", "first panel has aria-expanded=false" );
+ equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+
+ tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.PAGE_UP, altKey: true } );
+ strictEqual( document.activeElement, tabs[ 1 ], "second tab is activeElement" );
+ ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "ALT+PAGE_UP moves focus to previous tab" );
+ equal( tabs.eq( 1 ).attr( "aria-selected" ), "true", "second tab has aria-selected=true" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel is visible" );
+ equal( panels.eq( 1 ).attr( "aria-expanded" ), "true", "second panel has aria-expanded=true" );
+ equal( panels.eq( 1 ).attr( "aria-hidden" ), "false", "second panel has aria-hidden=false" );
+ ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+ equal( panels.eq( 2 ).attr( "aria-expanded" ), "false", "third panel has aria-expanded=false" );
+ equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+ panels.eq( 1 ).simulate( "focus" );
+ setTimeout( step3, 1 );
+ }
+
+ function step3() {
+ strictEqual( document.activeElement, panels[ 1 ], "second panel is activeElement" );
+
+ panels.eq( 1 ).simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } );
+ strictEqual( document.activeElement, tabs[ 1 ], "second tab is activeElement" );
+
+ setTimeout( start, 1 );
+ }
+
+ setTimeout( step1, 1 );
+});
+
+test( "#3627 - Ajax tab with url containing a fragment identifier fails to load", function() {
+ expect( 1 );
+
+ $( "#tabs2" ).tabs({
+ active: 2,
+ beforeLoad: function( event, ui ) {
+ event.preventDefault();
+ ok( /test.html$/.test( ui.ajaxSettings.url ), "should ignore fragment identifier" );
+ }
+ });
+});
+
+test( "#4033 - IE expands hash to full url and misinterprets tab as ajax", function() {
+ expect( 2 );
+
+ var element = $("<div><ul><li><a href='#tab'>Tab</a></li></ul><div id='tab'></div></div>");
+ element.appendTo("#qunit-fixture");
+ element.tabs({
+ beforeLoad: function() {
+ event.preventDefault();
+ ok( false, "should not be an ajax tab" );
+ }
+ });
+
+ equal( element.find(".ui-tabs-nav li").attr("aria-controls"), "tab", "aria-contorls attribute is correct" );
+ state( element, 1 );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/tabs/tabs_events.js b/apps/it/static/js/ui/tests/unit/tabs/tabs_events.js
new file mode 100644
index 0000000..f9b1755
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/tabs_events.js
@@ -0,0 +1,318 @@
+(function( $ ) {
+
+var state = TestHelpers.tabs.state;
+
+module( "tabs: events" );
+
+test( "create", function() {
+ expect( 10 );
+
+ var element = $( "#tabs1" ),
+ tabs = element.find( "ul li" ),
+ panels = element.children( "div" );
+
+ element.tabs({
+ create: function( event, ui ) {
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tabs[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panels[ 0 ], "panel" );
+ }
+ });
+ element.tabs( "destroy" );
+
+ element.tabs({
+ active: 2,
+ create: function( event, ui ) {
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tabs[ 2 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panels[ 2 ], "panel" );
+ }
+ });
+ element.tabs( "destroy" );
+
+ element.tabs({
+ active: false,
+ collapsible: true,
+ create: function( event, ui ) {
+ equal( ui.tab.length, 0, "tab length" );
+ equal( ui.panel.length, 0, "panel length" );
+ }
+ });
+ element.tabs( "destroy" );
+});
+
+test( "beforeActivate", function() {
+ expect( 38 );
+
+ var element = $( "#tabs1" ).tabs({
+ active: false,
+ collapsible: true
+ }),
+ tabs = element.find( ".ui-tabs-nav li" ),
+ anchors = tabs.find( ".ui-tabs-anchor" ),
+ panels = element.find( ".ui-tabs-panel" );
+
+ // from collapsed
+ element.one( "tabsbeforeactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.oldTab.length, 0, "oldTab length" );
+ equal( ui.oldPanel.length, 0, "oldPanel length" );
+ equal( ui.newTab.length, 1, "newTab length" );
+ strictEqual( ui.newTab[ 0 ], tabs[ 0 ], "newTab" );
+ equal( ui.newPanel.length, 1, "newPanel length" );
+ strictEqual( ui.newPanel[ 0 ], panels[ 0 ], "newPanel" );
+ state( element, 0, 0, 0 );
+ });
+ element.tabs( "option", "active", 0 );
+ state( element, 1, 0, 0 );
+
+ // switching tabs
+ element.one( "tabsbeforeactivate", function( event, ui ) {
+ equal( event.originalEvent.type, "click", "originalEvent" );
+ equal( ui.oldTab.length, 1, "oldTab length" );
+ strictEqual( ui.oldTab[ 0 ], tabs[ 0 ], "oldTab" );
+ equal( ui.oldPanel.length, 1, "oldPanel length" );
+ strictEqual( ui.oldPanel[ 0 ], panels[ 0 ], "oldPanel" );
+ equal( ui.newTab.length, 1, "newTab length" );
+ strictEqual( ui.newTab[ 0 ], tabs[ 1 ], "newTab" );
+ equal( ui.newPanel.length, 1, "newPanel length" );
+ strictEqual( ui.newPanel[ 0 ], panels[ 1 ], "newPanel" );
+ state( element, 1, 0, 0 );
+ });
+ anchors.eq( 1 ).click();
+ state( element, 0, 1, 0 );
+
+ // collapsing
+ element.one( "tabsbeforeactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.oldTab.length, 1, "oldTab length" );
+ strictEqual( ui.oldTab[ 0 ], tabs[ 1 ], "oldTab" );
+ equal( ui.oldPanel.length, 1, "oldPanel length" );
+ strictEqual( ui.oldPanel[ 0 ], panels[ 1 ], "oldPanel" );
+ equal( ui.newTab.length, 0, "newTab length" );
+ equal( ui.newPanel.length, 0, "newPanel length" );
+ state( element, 0, 1, 0 );
+ });
+ element.tabs( "option", "active", false );
+ state( element, 0, 0, 0 );
+
+ // prevent activation
+ element.one( "tabsbeforeactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.oldTab.length, 0, "oldTab length" );
+ equal( ui.oldPanel.length, 0, "oldTab" );
+ equal( ui.newTab.length, 1, "newTab length" );
+ strictEqual( ui.newTab[ 0 ], tabs[ 1 ], "newTab" );
+ equal( ui.newPanel.length, 1, "newPanel length" );
+ strictEqual( ui.newPanel[ 0 ], panels[ 1 ], "newPanel" );
+ event.preventDefault();
+ state( element, 0, 0, 0 );
+ });
+ element.tabs( "option", "active", 1 );
+ state( element, 0, 0, 0 );
+});
+
+test( "activate", function() {
+ expect( 30 );
+
+ var element = $( "#tabs1" ).tabs({
+ active: false,
+ collapsible: true
+ }),
+ tabs = element.find( ".ui-tabs-nav li" ),
+ anchors = element.find( ".ui-tabs-anchor" ),
+ panels = element.find( ".ui-tabs-panel" );
+
+ // from collapsed
+ element.one( "tabsactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.oldTab.length, 0, "oldTab length" );
+ equal( ui.oldPanel.length, 0, "oldPanel length" );
+ equal( ui.newTab.length, 1, "newTab length" );
+ strictEqual( ui.newTab[ 0 ], tabs[ 0 ], "newTab" );
+ equal( ui.newPanel.length, 1, "newPanel length" );
+ strictEqual( ui.newPanel[ 0 ], panels[ 0 ], "newPanel" );
+ state( element, 1, 0, 0 );
+ });
+ element.tabs( "option", "active", 0 );
+ state( element, 1, 0, 0 );
+
+ // switching tabs
+ element.one( "tabsactivate", function( event, ui ) {
+ equal( event.originalEvent.type, "click", "originalEvent" );
+ equal( ui.oldTab.length, 1, "oldTab length" );
+ strictEqual( ui.oldTab[ 0 ], tabs[ 0 ], "oldTab" );
+ equal( ui.oldPanel.length, 1, "oldPanel length" );
+ strictEqual( ui.oldPanel[ 0 ], panels[ 0 ], "oldPanel" );
+ equal( ui.newTab.length, 1, "newTab length" );
+ strictEqual( ui.newTab[ 0 ], tabs[ 1 ], "newTab" );
+ equal( ui.newPanel.length, 1, "newPanel length" );
+ strictEqual( ui.newPanel[ 0 ], panels[ 1 ], "newPanel" );
+ state( element, 0, 1, 0 );
+ });
+ anchors.eq( 1 ).click();
+ state( element, 0, 1, 0 );
+
+ // collapsing
+ element.one( "tabsactivate", function( event, ui ) {
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.oldTab.length, 1, "oldTab length" );
+ strictEqual( ui.oldTab[ 0 ], tabs[ 1 ], "oldTab" );
+ equal( ui.oldPanel.length, 1, "oldPanel length" );
+ strictEqual( ui.oldPanel[ 0 ], panels[ 1 ], "oldPanel" );
+ equal( ui.newTab.length, 0, "newTab length" );
+ equal( ui.newPanel.length, 0, "newPanel length" );
+ state( element, 0, 0, 0 );
+ });
+ element.tabs( "option", "active", false );
+ state( element, 0, 0, 0 );
+
+ // prevent activation
+ element.one( "tabsbeforeactivate", function( event ) {
+ ok( true, "tabsbeforeactivate" );
+ event.preventDefault();
+ });
+ element.one( "tabsactivate", function() {
+ ok( false, "tabsactivate" );
+ });
+ element.tabs( "option", "active", 1 );
+});
+
+test( "beforeLoad", function() {
+ expect( 32 );
+
+ var tab, panelId, panel,
+ element = $( "#tabs2" );
+
+ // init
+ element.one( "tabsbeforeload", function( event, ui ) {
+ tab = element.find( ".ui-tabs-nav li" ).eq( 2 );
+ panelId = tab.attr( "aria-controls" );
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ ok( "abort" in ui.jqXHR, "jqXHR" );
+ ok( ui.ajaxSettings.url, "data/test.html", "ajaxSettings.url" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ equal( ui.panel.html(), "", "panel html" );
+ event.preventDefault();
+ state( element, 0, 0, 1, 0, 0 );
+ });
+ element.tabs({ active: 2 });
+ state( element, 0, 0, 1, 0, 0 );
+ equal( panel.html(), "", "panel html after" );
+ element.tabs( "destroy" );
+
+ // .option()
+ element.one( "tabsbeforeload", function( event, ui ) {
+ tab = element.find( ".ui-tabs-nav li" ).eq( 2 );
+ panelId = tab.attr( "aria-controls" );
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ ok( "abort" in ui.jqXHR, "jqXHR" );
+ ok( ui.ajaxSettings.url, "data/test.html", "ajaxSettings.url" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ equal( ui.panel.html(), "", "panel html" );
+ event.preventDefault();
+ state( element, 1, 0, 0, 0, 0 );
+ });
+ element.tabs();
+ element.tabs( "option", "active", 2 );
+ state( element, 0, 0, 1, 0, 0 );
+ equal( panel.html(), "", "panel html after" );
+
+ // click, change panel content
+ element.one( "tabsbeforeload", function( event, ui ) {
+ tab = element.find( ".ui-tabs-nav li" ).eq( 3 );
+ panelId = tab.attr( "aria-controls" );
+ panel = $( "#" + panelId );
+
+ equal( event.originalEvent.type, "click", "originalEvent" );
+ ok( "abort" in ui.jqXHR, "jqXHR" );
+ ok( ui.ajaxSettings.url, "data/test.html", "ajaxSettings.url" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ ui.panel.html( "<p>testing</p>" );
+ event.preventDefault();
+ state( element, 0, 0, 1, 0, 0 );
+ });
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 3 ).click();
+ state( element, 0, 0, 0, 1, 0 );
+ // .toLowerCase() is needed to convert <P> to <p> in old IEs
+ equal( panel.html().toLowerCase(), "<p>testing</p>", "panel html after" );
+});
+
+asyncTest( "load", function() {
+ expect( 21 );
+
+ var tab, panelId, panel,
+ element = $( "#tabs2" );
+
+ // init
+ element.one( "tabsload", function( event, ui ) {
+ tab = element.find( ".ui-tabs-nav li" ).eq( 2 );
+ panelId = tab.attr( "aria-controls" );
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ equal( ui.panel.find( "p" ).length, 1, "panel html" );
+ state( element, 0, 0, 1, 0, 0 );
+ tabsload1();
+ });
+ element.tabs({ active: 2 });
+
+ function tabsload1() {
+ // .option()
+ element.one( "tabsload", function( event, ui ) {
+ tab = element.find( ".ui-tabs-nav li" ).eq( 3 );
+ panelId = tab.attr( "aria-controls" );
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ equal( ui.panel.find( "p" ).length, 1, "panel html" );
+ state( element, 0, 0, 0, 1, 0 );
+ tabsload2();
+ });
+ element.tabs( "option", "active", 3 );
+ }
+
+ function tabsload2() {
+ // click, change panel content
+ element.one( "tabsload", function( event, ui ) {
+ tab = element.find( ".ui-tabs-nav li" ).eq( 4 );
+ panelId = tab.attr( "aria-controls" );
+ panel = $( "#" + panelId );
+
+ equal( event.originalEvent.type, "click", "originalEvent" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ equal( ui.panel.find( "p" ).length, 1, "panel html" );
+ state( element, 0, 0, 0, 0, 1 );
+ start();
+ });
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 4 ).click();
+ }
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/tabs/tabs_methods.js b/apps/it/static/js/ui/tests/unit/tabs/tabs_methods.js
new file mode 100644
index 0000000..a3d663f
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/tabs_methods.js
@@ -0,0 +1,270 @@
+(function( $ ) {
+
+var disabled = TestHelpers.tabs.disabled,
+ state = TestHelpers.tabs.state;
+
+module( "tabs: methods" );
+
+test( "destroy", function() {
+ expect( 2 );
+ domEqual( "#tabs1", function() {
+ $( "#tabs1" ).tabs().tabs( "destroy" );
+ });
+ domEqual( "#tabs2", function() {
+ $( "#tabs2" ).tabs().tabs( "destroy" );
+ });
+});
+
+test( "enable", function() {
+ expect( 8 );
+
+ var element = $( "#tabs1" ).tabs({ disabled: true });
+ disabled( element, true );
+ element.tabs( "enable" );
+ disabled( element, false );
+ element.tabs( "destroy" );
+
+ element.tabs({ disabled: [ 0, 1 ] });
+ disabled( element, [ 0, 1 ] );
+ element.tabs( "enable" );
+ disabled( element, false );
+});
+
+test( "enable( index )", function() {
+ expect( 10 );
+
+ var element = $( "#tabs1" ).tabs({ disabled: true });
+ disabled( element, true );
+ // fully disabled -> partially disabled
+ element.tabs( "enable", 1 );
+ disabled( element, [ 0, 2 ] );
+ // partially disabled -> partially disabled
+ element.tabs( "enable", 2 );
+ disabled( element, [ 0 ] );
+ // already enabled tab, no change
+ element.tabs( "enable", 2 );
+ disabled( element, [ 0 ] );
+ // partially disabled -> fully enabled
+ element.tabs( "enable", 0 );
+ disabled( element, false );
+});
+
+test( "disable", function() {
+ expect( 8 );
+
+ var element = $( "#tabs1" ).tabs({ disabled: false });
+ disabled( element, false );
+ element.tabs( "disable" );
+ disabled( element, true );
+ element.tabs( "destroy" );
+
+ element.tabs({ disabled: [ 0, 1 ] });
+ disabled( element, [ 0, 1 ] );
+ element.tabs( "disable" );
+ disabled( element, true );
+});
+
+test( "disable( index )", function() {
+ expect( 10 );
+
+ var element = $( "#tabs1" ).tabs({ disabled: false });
+ disabled( element, false );
+ // fully enabled -> partially disabled
+ element.tabs( "disable", 1 );
+ disabled( element, [ 1 ] );
+ // partially disabled -> partially disabled
+ element.tabs( "disable", 2 );
+ disabled( element, [ 1, 2 ] );
+ // already disabled tab, no change
+ element.tabs( "disable", 2 );
+ disabled( element, [ 1, 2 ] );
+ // partially disabled -> fully disabled
+ element.tabs( "disable", 0 );
+ disabled( element, true );
+});
+
+test( "refresh", function() {
+ expect( 27 );
+
+ var element = $( "#tabs1" ).tabs();
+ state( element, 1, 0, 0 );
+ disabled( element, false );
+
+ // disable tab via markup
+ element.find( ".ui-tabs-nav li" ).eq( 1 ).addClass( "ui-state-disabled" );
+ element.tabs( "refresh" );
+ state( element, 1, 0, 0 );
+ disabled( element, [ 1 ] );
+
+ // add remote tab
+ element.find( ".ui-tabs-nav" ).append( "<li id='newTab'><a href='data/test.html'>new</a></li>" );
+ element.tabs( "refresh" );
+ state( element, 1, 0, 0, 0 );
+ disabled( element, [ 1 ] );
+ equal( element.find( "#" + $( "#newTab" ).attr( "aria-controls" ) ).length, 1,
+ "panel added for remote tab" );
+
+ // remove all tabs
+ element.find( ".ui-tabs-nav li, .ui-tabs-panel" ).remove();
+ element.tabs( "refresh" );
+ state( element );
+ equal( element.tabs( "option", "active" ), false, "no active tab" );
+
+ // add tabs
+ element.find( ".ui-tabs-nav" )
+ .append( "<li class='ui-state-disabled'><a href='#newTab2'>new 2</a></li>" )
+ .append( "<li><a href='#newTab3'>new 3</a></li>" )
+ .append( "<li><a href='#newTab4'>new 4</a></li>" )
+ .append( "<li><a href='#newTab5'>new 5</a></li>" );
+ element
+ .append( "<div id='newTab2'>new 2</div>" )
+ .append( "<div id='newTab3'>new 3</div>" )
+ .append( "<div id='newTab4'>new 4</div>" )
+ .append( "<div id='newTab5'>new 5</div>" );
+ element.tabs( "refresh" );
+ state( element, 0, 0, 0, 0 );
+ disabled( element, [ 0 ] );
+
+ // activate third tab
+ element.tabs( "option", "active", 2 );
+ state( element, 0, 0, 1, 0 );
+ disabled( element, [ 0 ] );
+
+ // remove fourth tab, third tab should stay active
+ element.find( ".ui-tabs-nav li" ).eq( 3 ).remove();
+ element.find( ".ui-tabs-panel" ).eq( 3 ).remove();
+ element.tabs( "refresh" );
+ state( element, 0, 0, 1 );
+ disabled( element, [ 0 ] );
+
+ // remove third (active) tab, second tab should become active
+ element.find( ".ui-tabs-nav li" ).eq( 2 ).remove();
+ element.find( ".ui-tabs-panel" ).eq( 2 ).remove();
+ element.tabs( "refresh" );
+ state( element, 0, 1 );
+ disabled( element, [ 0 ] );
+
+ // remove first tab, previously active tab (now first) should stay active
+ element.find( ".ui-tabs-nav li" ).eq( 0 ).remove();
+ element.find( ".ui-tabs-panel" ).eq( 0 ).remove();
+ element.tabs( "refresh" );
+ state( element, 1 );
+ disabled( element, false );
+});
+
+test( "refresh - looping", function() {
+ expect( 6 );
+
+ var element = $( "#tabs1" ).tabs({
+ disabled: [ 0 ],
+ active: 1
+ });
+ state( element, 0, 1, 0 );
+ disabled( element, [ 0 ] );
+
+ // remove active, jump to previous
+ // previous is disabled, just back one more
+ // reached first tab, move to end
+ // activate last tab
+ element.find( ".ui-tabs-nav li" ).eq( 2 ).remove();
+ element.tabs( "refresh" );
+ state( element, 0, 1 );
+ disabled( element, [ 0 ] );
+});
+
+asyncTest( "load", function() {
+ expect( 30 );
+
+ var element = $( "#tabs2" ).tabs();
+
+ // load content of inactive tab
+ // useful for preloading content with custom caching
+ element.one( "tabsbeforeload", function( event, ui ) {
+ var tab = element.find( ".ui-tabs-nav li" ).eq( 3 ),
+ panelId = tab.attr( "aria-controls" ),
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ state( element, 1, 0, 0, 0, 0 );
+ });
+ element.one( "tabsload", function( event, ui ) {
+ // TODO: remove wrapping in 2.0
+ var uiTab = $( ui.tab ),
+ uiPanel = $( ui.panel ),
+ tab = element.find( ".ui-tabs-nav li" ).eq( 3 ),
+ panelId = tab.attr( "aria-controls" ),
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( uiTab.length, 1, "tab length" );
+ strictEqual( uiTab[ 0 ], tab[ 0 ], "tab" );
+ equal( uiPanel.length, 1, "panel length" );
+ strictEqual( uiPanel[ 0 ], panel[ 0 ], "panel" );
+ equal( uiPanel.find( "p" ).length, 1, "panel html" );
+ state( element, 1, 0, 0, 0, 0 );
+ setTimeout( tabsload1, 100 );
+ });
+ element.tabs( "load", 3 );
+ state( element, 1, 0, 0, 0, 0 );
+
+ function tabsload1() {
+ // no need to test details of event (tested in events tests)
+ element.one( "tabsbeforeload", function() {
+ ok( true, "tabsbeforeload invoked" );
+ });
+ element.one( "tabsload", function() {
+ ok( true, "tabsload invoked" );
+ setTimeout( tabsload2, 100 );
+ });
+ element.tabs( "option", "active", 3 );
+ state( element, 0, 0, 0, 1, 0 );
+ }
+
+ function tabsload2() {
+ // reload content of active tab
+ element.one( "tabsbeforeload", function( event, ui ) {
+ var tab = element.find( ".ui-tabs-nav li" ).eq( 3 ),
+ panelId = tab.attr( "aria-controls" ),
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( ui.tab.length, 1, "tab length" );
+ strictEqual( ui.tab[ 0 ], tab[ 0 ], "tab" );
+ equal( ui.panel.length, 1, "panel length" );
+ strictEqual( ui.panel[ 0 ], panel[ 0 ], "panel" );
+ state( element, 0, 0, 0, 1, 0 );
+ });
+ element.one( "tabsload", function( event, ui ) {
+ // TODO: remove wrapping in 2.0
+ var uiTab = $( ui.tab ),
+ uiPanel = $( ui.panel ),
+ tab = element.find( ".ui-tabs-nav li" ).eq( 3 ),
+ panelId = tab.attr( "aria-controls" ),
+ panel = $( "#" + panelId );
+
+ ok( !( "originalEvent" in event ), "originalEvent" );
+ equal( uiTab.length, 1, "tab length" );
+ strictEqual( uiTab[ 0 ], tab[ 0 ], "tab" );
+ equal( uiPanel.length, 1, "panel length" );
+ strictEqual( uiPanel[ 0 ], panel[ 0 ], "panel" );
+ state( element, 0, 0, 0, 1, 0 );
+ start();
+ });
+ element.tabs( "load", 3 );
+ state( element, 0, 0, 0, 1, 0 );
+ }
+});
+
+test( "widget", function() {
+ expect( 2 );
+ var element = $( "#tabs1" ).tabs(),
+ widgetElement = element.tabs( "widget" );
+ equal( widgetElement.length, 1, "one element" );
+ strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/tabs/tabs_options.js b/apps/it/static/js/ui/tests/unit/tabs/tabs_options.js
new file mode 100644
index 0000000..c78c42b
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/tabs_options.js
@@ -0,0 +1,345 @@
+(function( $ ) {
+
+var disabled = TestHelpers.tabs.disabled,
+ equalHeight = TestHelpers.tabs.equalHeight,
+ state = TestHelpers.tabs.state;
+
+module( "tabs: options" );
+
+test( "{ active: default }", function() {
+ expect( 6 );
+
+ var element = $( "#tabs1" ).tabs();
+ equal( element.tabs( "option", "active" ), 0, "should be 0 by default" );
+ state( element, 1, 0, 0 );
+ element.tabs( "destroy" );
+
+ location.hash = "#fragment-3";
+ element = $( "#tabs1" ).tabs();
+ equal( element.tabs( "option", "active" ), 2, "should be 2 based on URL" );
+ state( element, 0, 0, 1 );
+ element.tabs( "destroy" );
+
+ location.hash = "#custom-id";
+ element = $( "#tabs2" ).tabs();
+ equal( element.tabs( "option", "active" ), 3, "should be 3 based on URL" );
+ state( element, 0, 0, 0, 1, 0 );
+ element.tabs( "destroy" );
+ location.hash = "#";
+});
+
+test( "{ active: false }", function() {
+ expect( 7 );
+
+ var element = $( "#tabs1" ).tabs({
+ active: false,
+ collapsible: true
+ });
+ state( element, 0, 0, 0 );
+ equal( element.find( ".ui-tabs-nav .ui-state-active" ).length, 0, "no tabs selected" );
+ strictEqual( element.tabs( "option", "active" ), false );
+
+ element.tabs( "option", "collapsible", false );
+ state( element, 1, 0, 0 );
+ equal( element.tabs( "option", "active" ), 0 );
+
+ element.tabs( "destroy" );
+ element.tabs({
+ active: false
+ });
+ state( element, 1, 0, 0 );
+ strictEqual( element.tabs( "option", "active" ), 0 );
+});
+
+test( "{ active: Number }", function() {
+ expect( 8 );
+
+ var element = $( "#tabs1" ).tabs({
+ active: 2
+ });
+ equal( element.tabs( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.tabs( "option", "active", 0 );
+ equal( element.tabs( "option", "active" ), 0 );
+ state( element, 1, 0, 0 );
+
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 1 ).click();
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.tabs( "option", "active", 10 );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ active: -Number }", function() {
+ expect( 8 );
+
+ var element = $( "#tabs1" ).tabs({
+ active: -1
+ });
+ equal( element.tabs( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.tabs( "option", "active", -2 );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.tabs( "option", "active", -10 );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.tabs( "option", "active", -3 );
+ equal( element.tabs( "option", "active" ), 0 );
+ state( element, 1, 0, 0 );
+});
+
+test( "active - mismatched tab/panel order", function() {
+ expect( 3 );
+
+ location.hash = "#tabs7-2";
+ var element = $( "#tabs7" ).tabs();
+ equal( element.tabs( "option", "active" ), 1, "should be 1 based on URL" );
+ state( element, 0, 1 );
+ element.tabs( "option", "active", 0 );
+ state( element, 1, 0 );
+ location.hash = "#";
+});
+
+test( "{ collapsible: false }", function() {
+ expect( 4 );
+
+ var element = $( "#tabs1" ).tabs({
+ active: 1
+ });
+ element.tabs( "option", "active", false );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.find( ".ui-state-active .ui-tabs-anchor" ).eq( 1 ).click();
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ collapsible: true }", function() {
+ expect( 6 );
+
+ var element = $( "#tabs1" ).tabs({
+ active: 1,
+ collapsible: true
+ });
+
+ element.tabs( "option", "active", false );
+ equal( element.tabs( "option", "active" ), false );
+ state( element, 0, 0, 0 );
+
+ element.tabs( "option", "active", 1 );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.find( ".ui-state-active .ui-tabs-anchor" ).click();
+ equal( element.tabs( "option", "active" ), false );
+ state( element, 0, 0, 0 );
+});
+
+test( "disabled", function() {
+ expect( 10 );
+
+ // fully enabled by default
+ var element = $( "#tabs1" ).tabs();
+ disabled( element, false );
+
+ // disable single tab
+ element.tabs( "option", "disabled", [ 1 ] );
+ disabled( element, [ 1 ] );
+
+ // disabled active tab
+ element.tabs( "option", "disabled", [ 0, 1 ] );
+ disabled( element, [ 0, 1 ] );
+
+ // disable all tabs
+ element.tabs( "option", "disabled", [ 0, 1, 2 ] );
+ disabled( element, true );
+
+ // enable all tabs
+ element.tabs( "option", "disabled", [] );
+ disabled( element, false );
+});
+
+test( "{ event: null }", function() {
+ expect( 5 );
+
+ var element = $( "#tabs1" ).tabs({
+ event: null
+ });
+ state( element, 1, 0, 0 );
+
+ element.tabs( "option", "active", 1 );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ // ensure default click handler isn't bound
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 2 ).click();
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ event: custom }", function() {
+ expect( 11 );
+
+ var element = $( "#tabs1" ).tabs({
+ event: "custom1 custom2"
+ });
+ state( element, 1, 0, 0 );
+
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 1 ).trigger( "custom1" );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ // ensure default click handler isn't bound
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 2 ).trigger( "click" );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 2 ).trigger( "custom2" );
+ equal( element.tabs( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.tabs( "option", "event", "custom3" );
+
+ // ensure old event handlers are unbound
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 1 ).trigger( "custom1" );
+ equal( element.tabs( "option", "active" ), 2 );
+ state( element, 0, 0, 1 );
+
+ element.find( ".ui-tabs-nav .ui-tabs-anchor" ).eq( 1 ).trigger( "custom3" );
+ equal( element.tabs( "option", "active" ), 1 );
+ state( element, 0, 1, 0 );
+});
+
+test( "{ heightStyle: 'auto' }", function() {
+ expect( 2 );
+ var element = $( "#tabs8" ).tabs({ heightStyle: "auto" });
+ equalHeight( element, 45 );
+});
+
+test( "{ heightStyle: 'content' }", function() {
+ expect( 2 );
+ var element = $( "#tabs8" ).tabs({ heightStyle: "content" }),
+ sizes = element.find( ".ui-tabs-panel" ).map(function() {
+ return $( this ).height();
+ }).get();
+ equal( sizes[ 0 ], 45 );
+ equal( sizes[ 1 ], 15 );
+});
+
+test( "{ heightStyle: 'fill' }", function() {
+ expect( 4 );
+ $( "#tabs8Wrapper" ).height( 500 );
+ var element = $( "#tabs8" ).tabs({ heightStyle: "fill" });
+ equalHeight( element, 485 );
+ element.tabs( "destroy" );
+
+ element = $( "#tabs8" ).css({
+ "border": "1px solid black",
+ "padding": "1px 0"
+ });
+ element.tabs({ heightStyle: "fill" });
+ equalHeight( element, 481 );
+});
+
+test( "{ heightStyle: 'fill' } with sibling", function() {
+ expect( 2 );
+ $( "#tabs8Wrapper" ).height( 500 );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 50,
+ marginTop: 20,
+ marginBottom: 30
+ })
+ .prependTo( "#tabs8Wrapper" );
+ var element = $( "#tabs8" ).tabs({ heightStyle: "fill" });
+ equalHeight( element, 385 );
+});
+
+test( "{ heightStyle: 'fill' } with multiple siblings", function() {
+ expect( 2 );
+ $( "#tabs8Wrapper" ).height( 500 );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 50,
+ marginTop: 20,
+ marginBottom: 30
+ })
+ .prependTo( "#tabs8Wrapper" );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 50,
+ marginTop: 20,
+ marginBottom: 30,
+ position: "absolute"
+ })
+ .prependTo( "#tabs8Wrapper" );
+ $( "<p>Lorem Ipsum</p>" )
+ .css({
+ height: 25,
+ marginTop: 10,
+ marginBottom: 15
+ })
+ .prependTo( "#tabs8Wrapper" );
+ var element = $( "#tabs8" ).tabs({ heightStyle: "fill" });
+ equalHeight( element, 335 );
+});
+
+test( "hide and show: false", function() {
+ expect( 3 );
+ var element = $( "#tabs1" ).tabs({
+ show: false,
+ hide: false
+ }),
+ widget = element.data( "ui-tabs" ),
+ panels = element.find( ".ui-tabs-panel" );
+ widget._show = function() {
+ ok( false, "_show() called" );
+ };
+ widget._hide = function() {
+ ok( false, "_hide() called" );
+ };
+
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" );
+ element.tabs( "option", "active", 1 );
+ ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" );
+ ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" );
+});
+
+asyncTest( "hide and show - animation", function() {
+ expect( 5 );
+ var element = $( "#tabs1" ).tabs({
+ show: "drop",
+ hide: 2000
+ }),
+ widget = element.data( "ui-tabs" ),
+ panels = element.find( ".ui-tabs-panel" );
+ widget._show = function( element, options, callback ) {
+ strictEqual( element[ 0 ], panels[ 1 ], "correct element in _show()" );
+ equal( options, "drop", "correct options in _show()" );
+ setTimeout(function() {
+ callback();
+ }, 1 );
+ };
+ widget._hide = function( element, options, callback ) {
+ strictEqual( element[ 0 ], panels[ 0 ], "correct element in _hide()" );
+ equal( options, 2000, "correct options in _hide()" );
+ setTimeout(function() {
+ callback();
+ start();
+ }, 1 );
+ };
+
+ ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" );
+ element.tabs( "option", "active", 1 );
+});
+
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/tabs/tabs_test_helpers.js b/apps/it/static/js/ui/tests/unit/tabs/tabs_test_helpers.js
new file mode 100644
index 0000000..0c93091
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tabs/tabs_test_helpers.js
@@ -0,0 +1,67 @@
+TestHelpers.tabs = {
+ disabled: function( tabs, state ) {
+ var expected, actual,
+ internalState = tabs.tabs( "option", "disabled" );
+
+ if ( internalState === false ) {
+ internalState = [];
+ }
+ if ( internalState === true ) {
+ internalState = $.map( new Array( tabs.find( ".ui-tabs-nav li" ).length ), function( _, index ) {
+ return index;
+ });
+ }
+
+ expected = $.map( new Array( tabs.find ( ".ui-tabs-nav li" ).length ), function( _, index ) {
+ if ( typeof state === "boolean" ) {
+ return state ? 1 : 0;
+ } else {
+ return $.inArray( index, state ) !== -1 ? 1 : 0;
+ }
+ });
+
+ actual = tabs.find( ".ui-tabs-nav li" ).map(function( index ) {
+ var tab = $( this ),
+ tabIsDisabled = tab.hasClass( "ui-state-disabled" );
+
+ if ( tabIsDisabled && $.inArray( index, internalState ) !== -1 ) {
+ return 1;
+ }
+ if ( !tabIsDisabled && $.inArray( index, internalState ) === -1 ) {
+ return 0;
+ }
+ // mixed state - invalid
+ return -1;
+ }).get();
+
+ deepEqual( tabs.tabs( "option", "disabled" ), state );
+ deepEqual( actual, expected );
+ },
+
+ equalHeight: function( tabs, height ) {
+ tabs.find( ".ui-tabs-panel" ).each(function() {
+ equal( $( this ).outerHeight(), height );
+ });
+ },
+
+ state: function( tabs ) {
+ var expected = $.makeArray( arguments ).slice( 1 ),
+ actual = tabs.find( ".ui-tabs-nav li" ).map(function() {
+ var tab = $( this ),
+ panel = $( $.ui.tabs.prototype._sanitizeSelector(
+ "#" + tab.attr( "aria-controls" ) ) ),
+ tabIsActive = tab.hasClass( "ui-state-active" ),
+ panelIsActive = panel.css( "display" ) !== "none";
+
+ if ( tabIsActive && panelIsActive ) {
+ return 1;
+ }
+ if ( !tabIsActive && !panelIsActive ) {
+ return 0;
+ }
+ return -1; // mixed state - invalid
+ }).get();
+ deepEqual( actual, expected );
+ }
+};
+
diff --git a/apps/it/static/js/ui/tests/unit/testsuite.js b/apps/it/static/js/ui/tests/unit/testsuite.js
new file mode 100644
index 0000000..eab1d4e
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/testsuite.js
@@ -0,0 +1,298 @@
+(function( $ ) {
+
+var reset, jshintLoaded;
+
+window.TestHelpers = {};
+
+function includeStyle( url ) {
+ document.write( "<link rel='stylesheet' href='../../../" + url + "'>" );
+}
+
+function includeScript( url ) {
+ document.write( "<script src='../../../" + url + "'></script>" );
+}
+
+function url( value ) {
+ return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random() * 100000, 10);
+}
+
+reset = QUnit.reset;
+QUnit.reset = function() {
+ // Ensure jQuery events and data on the fixture are properly removed
+ jQuery("#qunit-fixture").empty();
+ // Let QUnit reset the fixture
+ reset.apply( this, arguments );
+};
+
+
+QUnit.config.requireExpects = true;
+
+QUnit.config.urlConfig.push({
+ id: "min",
+ label: "Minified source",
+ tooltip: "Load minified source files instead of the regular unminified ones."
+});
+
+TestHelpers.loadResources = QUnit.urlParams.min ?
+ function() {
+ includeStyle( "dist/jquery-ui.min.css" );
+ includeScript( "dist/jquery-ui.min.js" );
+ } :
+ function( resources ) {
+ $.each( resources.css || [], function( i, resource ) {
+ includeStyle( "themes/base/jquery." + resource + ".css" );
+ });
+ $.each( resources.js || [], function( i, resource ) {
+ includeScript( resource );
+ });
+ };
+
+QUnit.config.urlConfig.push({
+ id: "nojshint",
+ label: "Skip JSHint",
+ tooltip: "Skip running JSHint, e.g. within TestSwarm, where Jenkins runs it already"
+});
+
+jshintLoaded = false;
+TestHelpers.testJshint = function( module ) {
+ if ( QUnit.urlParams.nojshint ) {
+ return;
+ }
+
+ if ( !jshintLoaded ) {
+ includeScript( "external/jshint.js" );
+ jshintLoaded = true;
+ }
+
+ asyncTest( "JSHint", function() {
+ expect( 1 );
+
+ $.when(
+ $.ajax({
+ url: url("../../../ui/.jshintrc"),
+ dataType: "json"
+ }),
+ $.ajax({
+ url: url("../../../ui/jquery.ui." + module + ".js"),
+ dataType: "text"
+ })
+ ).done(function( hintArgs, srcArgs ) {
+ var globals, passed, errors,
+ jshintrc = hintArgs[ 0 ],
+ source = srcArgs[ 0 ];
+
+ globals = jshintrc.globals || {};
+ delete jshintrc.globals;
+ passed = JSHINT( source, jshintrc, globals );
+ errors = $.map( JSHINT.errors, function( error ) {
+ // JSHINT may report null if there are too many errors
+ if ( !error ) {
+ return;
+ }
+
+ return "[L" + error.line + ":C" + error.character + "] " +
+ error.reason + "\n" + error.evidence + "\n";
+ }).join( "\n" );
+ ok( passed, errors );
+ start();
+ })
+ .fail(function() {
+ ok( false, "error loading source" );
+ start();
+ });
+ });
+};
+
+function testWidgetDefaults( widget, defaults ) {
+ var pluginDefaults = $.ui[ widget ].prototype.options;
+
+ // ensure that all defaults have the correct value
+ test( "defined defaults", function() {
+ var count = 0;
+ $.each( defaults, function( key, val ) {
+ expect( ++count );
+ if ( $.isFunction( val ) ) {
+ ok( $.isFunction( pluginDefaults[ key ] ), key );
+ return;
+ }
+ deepEqual( pluginDefaults[ key ], val, key );
+ });
+ });
+
+ // ensure that all defaults were tested
+ test( "tested defaults", function() {
+ var count = 0;
+ $.each( pluginDefaults, function( key ) {
+ expect( ++count );
+ ok( key in defaults, key );
+ });
+ });
+}
+
+function testWidgetOverrides( widget ) {
+ if ( $.uiBackCompat === false ) {
+ test( "$.widget overrides", function() {
+ expect( 4 );
+ $.each([
+ "_createWidget",
+ "destroy",
+ "option",
+ "_trigger"
+ ], function( i, method ) {
+ strictEqual( $.ui[ widget ].prototype[ method ],
+ $.Widget.prototype[ method ], "should not override " + method );
+ });
+ });
+ }
+}
+
+function testBasicUsage( widget ) {
+ test( "basic usage", function() {
+ expect( 3 );
+
+ var defaultElement = $.ui[ widget ].prototype.defaultElement;
+ $( defaultElement ).appendTo( "body" )[ widget ]().remove();
+ ok( true, "initialized on element" );
+
+ $( defaultElement )[ widget ]().remove();
+ ok( true, "initialized on disconnected DOMElement - never connected" );
+
+ $( defaultElement ).appendTo( "body" ).remove()[ widget ]().remove();
+ ok( true, "initialized on disconnected DOMElement - removed" );
+ });
+}
+
+TestHelpers.commonWidgetTests = function( widget, settings ) {
+ module( widget + ": common widget" );
+
+ TestHelpers.testJshint( widget );
+ testWidgetDefaults( widget, settings.defaults );
+ testWidgetOverrides( widget );
+ testBasicUsage( widget );
+ test( "version", function() {
+ expect( 1 );
+ ok( "version" in $.ui[ widget ].prototype, "version property exists" );
+ });
+};
+
+/*
+ * Taken from https://github.com/jquery/qunit/tree/master/addons/close-enough
+ */
+window.closeEnough = function( actual, expected, maxDifference, message ) {
+ var passes = (actual === expected) || Math.abs(actual - expected) <= maxDifference;
+ QUnit.push(passes, actual, expected, message);
+};
+
+/*
+ * Experimental assertion for comparing DOM objects.
+ *
+ * Serializes an element and some properties and attributes and it's children if any, otherwise the text.
+ * Then compares the result using deepEqual.
+ */
+window.domEqual = function( selector, modifier, message ) {
+ var expected, actual,
+ properties = [
+ "disabled",
+ "readOnly"
+ ],
+ attributes = [
+ "autocomplete",
+ "aria-activedescendant",
+ "aria-controls",
+ "aria-describedby",
+ "aria-disabled",
+ "aria-expanded",
+ "aria-haspopup",
+ "aria-hidden",
+ "aria-labelledby",
+ "aria-pressed",
+ "aria-selected",
+ "aria-valuemax",
+ "aria-valuemin",
+ "aria-valuenow",
+ "class",
+ "href",
+ "id",
+ "nodeName",
+ "role",
+ "tabIndex",
+ "title"
+ ];
+
+ function getElementStyles( elem ) {
+ var key, len,
+ style = elem.ownerDocument.defaultView ?
+ elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
+ elem.currentStyle,
+ styles = {};
+
+ if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
+ len = style.length;
+ while ( len-- ) {
+ key = style[ len ];
+ if ( typeof style[ key ] === "string" ) {
+ styles[ $.camelCase( key ) ] = style[ key ];
+ }
+ }
+ // support: Opera, IE <9
+ } else {
+ for ( key in style ) {
+ if ( typeof style[ key ] === "string" ) {
+ styles[ key ] = style[ key ];
+ }
+ }
+ }
+
+ return styles;
+ }
+
+ function extract( elem ) {
+ if ( !elem || !elem.length ) {
+ QUnit.push( false, actual, expected,
+ "domEqual failed, can't extract " + selector + ", message was: " + message );
+ return;
+ }
+
+ var children,
+ result = {};
+ $.each( properties, function( index, attr ) {
+ var value = elem.prop( attr );
+ result[ attr ] = value !== undefined ? value : "";
+ });
+ $.each( attributes, function( index, attr ) {
+ var value = elem.attr( attr );
+ result[ attr ] = value !== undefined ? value : "";
+ });
+ result.style = getElementStyles( elem[ 0 ] );
+ result.events = $._data( elem[ 0 ], "events" );
+ result.data = $.extend( {}, elem.data() );
+ delete result.data[ $.expando ];
+ children = elem.children();
+ if ( children.length ) {
+ result.children = elem.children().map(function() {
+ return extract( $( this ) );
+ }).get();
+ } else {
+ result.text = elem.text();
+ }
+ return result;
+ }
+
+ function done() {
+ actual = extract( $( selector ) );
+ QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
+ }
+
+ // Get current state prior to modifier
+ expected = extract( $( selector ) );
+
+ // Run modifier (async or sync), then compare state via done()
+ if ( modifier.length ) {
+ modifier( done );
+ } else {
+ modifier();
+ done();
+ }
+};
+
+}( jQuery ));
diff --git a/apps/it/static/js/ui/tests/unit/tooltip/all.html b/apps/it/static/js/ui/tests/unit/tooltip/all.html
new file mode 100644
index 0000000..614b7f7
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tooltip/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Tooltip Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "tooltip" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Tooltip Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/tooltip/tooltip.html b/apps/it/static/js/ui/tests/unit/tooltip/tooltip.html
new file mode 100644
index 0000000..ec616be
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tooltip/tooltip.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Tooltip Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.tooltip" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.position.js",
+ "ui/jquery.ui.tooltip.js"
+ ]
+ });
+ </script>
+
+ <script src="tooltip_common.js"></script>
+ <script src="tooltip_core.js"></script>
+ <script src="tooltip_events.js"></script>
+ <script src="tooltip_methods.js"></script>
+ <script src="tooltip_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Tooltip Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div>
+ <a id="tooltipped1" href="#" title="anchortitle">anchor</a>
+ <input title="inputtitle">
+ <span id="multiple-describedby" aria-describedby="fixture-span" title="...">aria-describedby</span>
+ <span id="fixture-span" title="title-text">span</span>
+ <span id="contains-tooltipped" title="parent"><span id="contained-tooltipped" title="child">baz</span></span>
+</div>
+
+<form id="tooltip-form">
+ <input name="title" title="attroperties">
+</form>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/tooltip/tooltip_common.js b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_common.js
new file mode 100644
index 0000000..2d6ea91
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_common.js
@@ -0,0 +1,21 @@
+TestHelpers.commonWidgetTests( "tooltip", {
+ defaults: {
+ content: function() {},
+ disabled: false,
+ hide: true,
+ items: "[title]:not([disabled])",
+ position: {
+ my: "left top+15",
+ at: "left bottom",
+ collision: "flipfit flip"
+ },
+ show: true,
+ tooltipClass: null,
+ track: false,
+
+ // callbacks
+ close: null,
+ create: null,
+ open: null
+ }
+});
diff --git a/apps/it/static/js/ui/tests/unit/tooltip/tooltip_core.js b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_core.js
new file mode 100644
index 0000000..c3568bf
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_core.js
@@ -0,0 +1,137 @@
+(function( $ ) {
+
+module( "tooltip: core" );
+
+test( "markup structure", function() {
+ expect( 7 );
+ var element = $( "#tooltipped1" ).tooltip(),
+ tooltip = $( ".ui-tooltip" );
+
+ equal( element.attr( "aria-describedby" ), undefined, "no aria-describedby on init" );
+ equal( tooltip.length, 0, "no tooltip on init" );
+
+ element.tooltip( "open" );
+ tooltip = $( "#" + element.data( "ui-tooltip-id" ) );
+ equal( tooltip.length, 1, "tooltip exists" );
+ equal( element.attr( "aria-describedby"), tooltip.attr( "id" ), "aria-describedby" );
+ ok( tooltip.hasClass( "ui-tooltip" ), "tooltip is .ui-tooltip" );
+ equal( tooltip.length, 1, ".ui-tooltip exists" );
+ equal( tooltip.find( ".ui-tooltip-content" ).length, 1,
+ ".ui-tooltip-content exists" );
+});
+
+test( "accessibility", function() {
+ expect( 5 );
+
+ var tooltipId,
+ tooltip,
+ element = $( "#multiple-describedby" ).tooltip();
+
+ element.tooltip( "open" );
+ tooltipId = element.data( "ui-tooltip-id" );
+ tooltip = $( "#" + tooltipId );
+ equal( tooltip.attr( "role" ), "tooltip", "role" );
+ equal( element.attr( "aria-describedby" ), "fixture-span " + tooltipId,
+ "multiple describedby when open" );
+ // strictEqual to distinguish between .removeAttr( "title" ) and .attr( "title", "" )
+ // support: jQuery <1.6.2
+ // support: IE <8
+ // We should use strictEqual( ..., undefined ) when dropping jQuery 1.6.1 support (or IE6/7)
+ ok( !element.attr( "title" ), "no title when open" );
+ element.tooltip( "close" );
+ equal( element.attr( "aria-describedby" ), "fixture-span",
+ "correct describedby when closed" );
+ equal( element.attr( "title" ), "...", "title restored when closed" );
+});
+
+test( "delegated removal", function() {
+ expect( 2 );
+
+ var container = $( "#contains-tooltipped" ).tooltip(),
+ element = $( "#contained-tooltipped" );
+
+ element.trigger( "mouseover" );
+ equal( $( ".ui-tooltip" ).length, 1 );
+
+ container.empty();
+ equal( $( ".ui-tooltip" ).length, 0 );
+});
+
+test( "nested tooltips", function() {
+ expect( 2 );
+
+ var child = $( "#contained-tooltipped" ),
+ parent = $( "#contains-tooltipped" ).tooltip({
+ show: null,
+ hide: null
+ });
+
+ parent.trigger( "mouseover" );
+ equal( $( ".ui-tooltip:visible" ).text(), "parent" );
+
+ child.trigger( "mouseover" );
+ equal( $( ".ui-tooltip" ).text(), "child" );
+});
+
+// #8742
+test( "form containing an input with name title", function() {
+ expect( 4 );
+
+ var form = $( "#tooltip-form" ).tooltip({
+ show: null,
+ hide: null
+ }),
+ input = form.find( "[name=title]" );
+
+ equal( $( ".ui-tooltip" ).length, 0, "no tooltips on init" );
+
+ input.trigger( "mouseover" );
+ equal( $( ".ui-tooltip" ).length, 1, "tooltip for input" );
+ input.trigger( "mouseleave" );
+ equal( $( ".ui-tooltip" ).length, 0, "tooltip for input closed" );
+
+ form.trigger( "mouseover" );
+ equal( $( ".ui-tooltip" ).length, 0, "no tooltip for form" );
+});
+
+test( "tooltip on .ui-state-disabled element", function() {
+ expect( 2 );
+
+ var container = $( "#contains-tooltipped" ).tooltip(),
+ element = $( "#contained-tooltipped" ).addClass( "ui-state-disabled" );
+
+ element.trigger( "mouseover" );
+ equal( $( ".ui-tooltip" ).length, 1 );
+
+ container.empty();
+ equal( $( ".ui-tooltip" ).length, 0 );
+});
+
+// http://bugs.jqueryui.com/ticket/8740
+asyncTest( "programmatic focus with async content", function() {
+ expect( 2 );
+ var element = $( "#tooltipped1" ).tooltip({
+ content: function( response ) {
+ setTimeout(function() {
+ response( "test" );
+ });
+ }
+ });
+
+ element.bind( "tooltipopen", function( event ) {
+ deepEqual( event.originalEvent.type, "focusin" );
+
+ element.bind( "tooltipclose", function( event ) {
+ deepEqual( event.originalEvent.type, "focusout" );
+ start();
+ });
+
+ setTimeout(function() {
+ element.blur();
+ });
+ });
+
+ element.focus();
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/tooltip/tooltip_events.js b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_events.js
new file mode 100644
index 0000000..de16471
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_events.js
@@ -0,0 +1,57 @@
+(function( $ ) {
+
+module( "tooltip: events" );
+
+test( "programmatic triggers", function() {
+ expect( 4 );
+ var tooltip,
+ element = $( "#tooltipped1" ).tooltip();
+
+ element.one( "tooltipopen", function( event, ui ) {
+ tooltip = ui.tooltip;
+ ok( !( "originalEvent" in event ), "open" );
+ strictEqual( ui.tooltip[0],
+ $( "#" + element.data( "ui-tooltip-id" ) )[0], "ui.tooltip" );
+ });
+ element.tooltip( "open" );
+
+ element.one( "tooltipclose", function( event, ui ) {
+ ok( !( "originalEvent" in event ), "close" );
+ strictEqual( ui.tooltip[0], tooltip[0], "ui.tooltip" );
+ });
+ element.tooltip( "close" );
+});
+
+test( "mouse events", function() {
+ expect( 2 );
+ var element = $( "#tooltipped1" ).tooltip();
+
+ element.bind( "tooltipopen", function( event ) {
+ deepEqual( event.originalEvent.type, "mouseover" );
+ });
+ element.trigger( "mouseover" );
+
+ element.bind( "tooltipclose", function( event ) {
+ deepEqual( event.originalEvent.type, "mouseleave" );
+ });
+ element.trigger( "focusout" );
+ element.trigger( "mouseleave" );
+});
+
+test( "focus events", function() {
+ expect( 2 );
+ var element = $( "#tooltipped1" ).tooltip();
+
+ element.bind( "tooltipopen", function( event ) {
+ deepEqual( event.originalEvent.type, "focusin" );
+ });
+ element.trigger( "focusin" );
+
+ element.bind( "tooltipclose", function( event ) {
+ deepEqual( event.originalEvent.type, "focusout" );
+ });
+ element.trigger( "mouseleave" );
+ element.trigger( "focusout" );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/tooltip/tooltip_methods.js b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_methods.js
new file mode 100644
index 0000000..c846d21
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_methods.js
@@ -0,0 +1,94 @@
+(function( $ ) {
+
+module( "tooltip: methods" );
+
+test( "destroy", function() {
+ expect( 3 );
+ var element = $( "#tooltipped1" );
+
+ domEqual( "#tooltipped1", function() {
+ element.tooltip().tooltip( "destroy" );
+ });
+
+ // make sure that open tooltips are removed on destroy
+ domEqual( "#tooltipped1", function() {
+ element
+ .tooltip()
+ .tooltip( "open", $.Event( "mouseover", { target: element[0] }) )
+ .tooltip( "destroy" );
+ });
+ equal( $( ".ui-tooltip" ).length, 0 );
+});
+
+test( "open/close", function() {
+ expect( 3 );
+ $.fx.off = true;
+ var tooltip,
+ element = $( "#tooltipped1" ).tooltip();
+ equal( $( ".ui-tooltip" ).length, 0, "no tooltip on init" );
+
+ element.tooltip( "open" );
+ tooltip = $( "#" + element.data( "ui-tooltip-id" ) );
+ ok( tooltip.is( ":visible" ) );
+
+ element.tooltip( "close" );
+ ok( tooltip.is( ":hidden" ) );
+ $.fx.off = false;
+});
+
+// #8626 - Calling open() without an event
+test( "open/close with tracking", function() {
+ expect( 3 );
+ $.fx.off = true;
+ var tooltip,
+ element = $( "#tooltipped1" ).tooltip({ track: true });
+ equal( $( ".ui-tooltip" ).length, 0, "no tooltip on init" );
+
+ element.tooltip( "open" );
+ tooltip = $( "#" + element.data( "ui-tooltip-id" ) );
+ ok( tooltip.is( ":visible" ) );
+
+ element.tooltip( "close" );
+ ok( tooltip.is( ":hidden" ) );
+ $.fx.off = false;
+});
+
+test( "enable/disable", function() {
+ expect( 7 );
+ $.fx.off = true;
+ var tooltip,
+ element = $( "#tooltipped1" ).tooltip();
+ equal( $( ".ui-tooltip" ).length, 0, "no tooltip on init" );
+
+ element.tooltip( "open" );
+ tooltip = $( "#" + element.data( "ui-tooltip-id" ) );
+ ok( tooltip.is( ":visible" ) );
+
+ element.tooltip( "disable" );
+ equal( $( ".ui-tooltip" ).length, 0, "no tooltip when disabled" );
+ // support: jQuery <1.6.2
+ // support: IE <8
+ // We should use strictEqual( ..., undefined ) when dropping jQuery 1.6.1 support (or IE6/7)
+ ok( !tooltip.attr( "title" ), "title removed on disable" );
+
+ element.tooltip( "open" );
+ equal( $( ".ui-tooltip" ).length, 0, "open does nothing when disabled" );
+
+ element.tooltip( "enable" );
+ equal( element.attr( "title" ), "anchortitle", "title restored on enable" );
+
+ element.tooltip( "open" );
+ tooltip = $( "#" + element.data( "ui-tooltip-id" ) );
+ ok( tooltip.is( ":visible" ) );
+ $.fx.off = false;
+});
+
+test( "widget", function() {
+ expect( 2 );
+ var element = $( "#tooltipped1" ).tooltip(),
+ widgetElement = element.tooltip( "widget" );
+ equal( widgetElement.length, 1, "one element" );
+ strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/tooltip/tooltip_options.js b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_options.js
new file mode 100644
index 0000000..01ac250
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/tooltip/tooltip_options.js
@@ -0,0 +1,171 @@
+(function( $ ) {
+
+module( "tooltip: options" );
+
+test( "disabled: true", function() {
+ expect( 1 );
+ $( "#tooltipped1" ).tooltip({
+ disabled: true
+ }).tooltip( "open" );
+ equal( $( ".ui-tooltip" ).length, 0 );
+});
+
+test( "content: default", function() {
+ expect( 1 );
+ var element = $( "#tooltipped1" ).tooltip().tooltip( "open" );
+ deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "anchortitle" );
+});
+
+test( "content: default; HTML escaping", function() {
+ expect( 2 );
+ var scriptText = "<script>$.ui.tooltip.hacked = true;</script>",
+ element = $( "#tooltipped1" );
+
+ $.ui.tooltip.hacked = false;
+ element.attr( "title", scriptText )
+ .tooltip()
+ .tooltip( "open" );
+ equal( $.ui.tooltip.hacked, false, "script did not execute" );
+ deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), scriptText,
+ "correct tooltip text" );
+});
+
+test( "content: return string", function() {
+ expect( 1 );
+ var element = $( "#tooltipped1" ).tooltip({
+ content: function() {
+ return "customstring";
+ }
+ }).tooltip( "open" );
+ deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "customstring" );
+});
+
+test( "content: return jQuery", function() {
+ expect( 1 );
+ var element = $( "#tooltipped1" ).tooltip({
+ content: function() {
+ return $( "<div>" ).html( "cu<b>s</b>tomstring" );
+ }
+ }).tooltip( "open" );
+ deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "customstring" );
+});
+
+asyncTest( "content: sync + async callback", function() {
+ expect( 2 );
+ var element = $( "#tooltipped1" ).tooltip({
+ content: function( response ) {
+ setTimeout(function() {
+ deepEqual( $( "#" + element.data("ui-tooltip-id") ).text(), "loading..." );
+
+ response( "customstring2" );
+ setTimeout(function() {
+ deepEqual( $( "#" + element.data("ui-tooltip-id") ).text(), "customstring2" );
+ start();
+ }, 13 );
+ }, 13 );
+ return "loading...";
+ }
+ }).tooltip( "open" );
+});
+
+test( "content: change while open", function() {
+ expect( 2 ) ;
+ var element = $( "#tooltipped1" ).tooltip({
+ content: function() {
+ return "old";
+ }
+ });
+
+ element.one( "tooltipopen", function( event, ui ) {
+ equal( ui.tooltip.text(), "old", "original content" );
+ element.tooltip( "option", "content", function() {
+ return "new";
+ });
+ equal( ui.tooltip.text(), "new", "updated content" );
+ });
+
+ element.tooltip( "open" );
+});
+
+test( "content: string", function() {
+ expect( 1 );
+ $( "#tooltipped1" ).tooltip({
+ content: "just a string",
+ open: function( event, ui ) {
+ equal( ui.tooltip.text(), "just a string" );
+ }
+ }).tooltip( "open" );
+});
+
+test( "items", function() {
+ expect( 2 );
+ var event,
+ element = $( "#qunit-fixture" ).tooltip({
+ items: "#fixture-span"
+ });
+
+ event = $.Event( "mouseenter" );
+ event.target = $( "#fixture-span" )[ 0 ];
+ element.tooltip( "open", event );
+ deepEqual( $( "#" + $( "#fixture-span" ).data( "ui-tooltip-id" ) ).text(), "title-text" );
+
+ // make sure default [title] doesn't get used
+ event.target = $( "#tooltipped1" )[ 0 ];
+ element.tooltip( "open", event );
+ deepEqual( $( "#tooltipped1" ).data( "ui-tooltip-id" ), undefined );
+
+ element.tooltip( "destroy" );
+});
+
+test( "tooltipClass", function() {
+ expect( 1 );
+ var element = $( "#tooltipped1" ).tooltip({
+ tooltipClass: "custom"
+ }).tooltip( "open" );
+ ok( $( "#" + element.data( "ui-tooltip-id" ) ).hasClass( "custom" ) );
+});
+
+test( "track + show delay", function() {
+ expect( 2 );
+ var event,
+ leftVal = 314,
+ topVal = 159,
+ offsetVal = 26,
+ element = $( "#tooltipped1" ).tooltip({
+ track: true,
+ show: {
+ delay: 1
+ },
+ position: {
+ my: "left+" + offsetVal + " top+" + offsetVal,
+ at: "right bottom"
+ }
+ });
+
+ event = $.Event( "mouseover" );
+ event.target = $( "#tooltipped1" )[ 0 ];
+ event.originalEvent = { type: "mouseover" };
+ event.pageX = leftVal;
+ event.pageY = topVal;
+ element.trigger( event );
+
+ event = $.Event( "mousemove" );
+ event.target = $( "#tooltipped1" )[ 0 ];
+ event.originalEvent = { type: "mousemove" };
+ event.pageX = leftVal;
+ event.pageY = topVal;
+ element.trigger( event );
+
+ equal( $( ".ui-tooltip" ).css( "left" ), leftVal + offsetVal + "px" );
+ equal( $( ".ui-tooltip" ).css( "top" ), topVal + offsetVal + "px" );
+});
+
+test( "track and programmatic focus", function() {
+ expect( 1 );
+ $( "#qunit-fixture div input" ).tooltip({
+ track: true
+ }).focus();
+ equal( "inputtitle", $( ".ui-tooltip" ).text() );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/widget/all.html b/apps/it/static/js/ui/tests/unit/widget/all.html
new file mode 100644
index 0000000..ab493ab
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/widget/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Widget Test Suite</title>
+
+ <script src="../../../jquery-1.10.2.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../qunit-composite.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "widget" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Widget Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/widget/widget.html b/apps/it/static/js/ui/tests/unit/widget/widget.html
new file mode 100644
index 0000000..15eaee6
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/widget/widget.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Widget Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core" ],
+ js: [
+ "ui/jquery.ui.widget.js"
+ ]
+ });
+ </script>
+
+ <script src="widget_core.js"></script>
+ <script src="widget_extend.js"></script>
+ <script src="widget_animation.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Widget Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+<div id="widget-wrapper">
+ <div id="widget">
+ <div>...</div>
+ </div>
+</div>
+
+</div>
+</body>
+</html>
diff --git a/apps/it/static/js/ui/tests/unit/widget/widget_animation.js b/apps/it/static/js/ui/tests/unit/widget/widget_animation.js
new file mode 100644
index 0000000..8ef55aa
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/widget/widget_animation.js
@@ -0,0 +1,257 @@
+
+module( "widget animation", (function() {
+ var show = $.fn.show,
+ fadeIn = $.fn.fadeIn,
+ slideDown = $.fn.slideDown;
+ return {
+ setup: function() {
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ this.element.hide();
+ },
+ show: function( fn ) {
+ this._show( this.element, this.options.show, fn );
+ }
+ });
+ $.effects = { effect: { testEffect: $.noop } };
+ },
+ teardown: function() {
+ delete $.ui.testWidget;
+ delete $.effects.effect.testEffect;
+ $.fn.show = show;
+ $.fn.fadeIn = fadeIn;
+ $.fn.slideDown = slideDown;
+ }
+ };
+}()));
+
+asyncTest( "show: null", function() {
+ expect( 4 );
+
+ var element = $( "#widget" ).testWidget(),
+ hasRun = false;
+ $.fn.show = function() {
+ ok( true, "show called" );
+ equal( arguments.length, 0, "no args passed to show" );
+ };
+
+ element
+ .delay( 50 )
+ .queue(function( next ) {
+ ok( !hasRun, "queue before show" );
+ next();
+ })
+ .testWidget( "show", function() {
+ hasRun = true;
+ })
+ .queue(function( next ) {
+ ok( hasRun, "queue after show" );
+ start();
+ next();
+ });
+});
+
+asyncTest( "show: true", function() {
+ expect( 4 );
+
+ var element = $( "#widget" ).testWidget({
+ show: true
+ }),
+ hasRun = false;
+ $.fn.fadeIn = function( duration, easing, complete ) {
+ return this.queue(function( next ) {
+ strictEqual( duration, undefined, "duration" );
+ strictEqual( easing, undefined, "easing" );
+ complete();
+ next();
+ });
+ };
+
+ element
+ .delay( 50 )
+ .queue(function( next ) {
+ ok( !hasRun, "queue before show" );
+ next();
+ })
+ .testWidget( "show", function() {
+ hasRun = true;
+ })
+ .queue(function( next ) {
+ ok( hasRun, "queue after show" );
+ start();
+ next();
+ });
+});
+
+asyncTest( "show: number", function() {
+ expect( 4 );
+
+ var element = $( "#widget" ).testWidget({
+ show: 123
+ }),
+ hasRun = false;
+ $.fn.fadeIn = function( duration, easing, complete ) {
+ return this.queue(function( next ) {
+ strictEqual( duration, 123, "duration" );
+ strictEqual( easing, undefined, "easing" );
+ complete();
+ next();
+ });
+ };
+
+ element
+ .delay( 50 )
+ .queue(function( next ) {
+ ok( !hasRun, "queue before show" );
+ next();
+ })
+ .testWidget( "show", function() {
+ hasRun = true;
+ })
+ .queue(function( next ) {
+ ok( hasRun, "queue after show" );
+ start();
+ next();
+ });
+});
+
+asyncTest( "show: core animation", function() {
+ expect( 4 );
+
+ var element = $( "#widget" ).testWidget({
+ show: "slideDown"
+ }),
+ hasRun = false;
+ $.fn.slideDown = function( duration, easing, complete ) {
+ return this.queue(function( next ) {
+ strictEqual( duration, undefined, "duration" );
+ strictEqual( easing, undefined, "easing" );
+ complete();
+ next();
+ });
+ };
+
+ element
+ .delay( 50 )
+ .queue(function( next ) {
+ ok( !hasRun, "queue before show" );
+ next();
+ })
+ .testWidget( "show", function() {
+ hasRun = true;
+ })
+ .queue(function( next ) {
+ ok( hasRun, "queue after show" );
+ start();
+ next();
+ });
+});
+
+asyncTest( "show: effect", function() {
+ expect( 5 );
+
+ var element = $( "#widget" ).testWidget({
+ show: "testEffect"
+ }),
+ hasRun = false;
+ $.fn.show = function( options ) {
+ return this.queue(function( next ) {
+ equal( options.effect, "testEffect", "effect" );
+ ok( !("duration" in options), "duration" );
+ ok( !("easing" in options), "easing" );
+ options.complete();
+ next();
+ });
+ };
+
+ element
+ .delay( 50 )
+ .queue(function( next ) {
+ ok( !hasRun, "queue before show" );
+ next();
+ })
+ .testWidget( "show", function() {
+ hasRun = true;
+ })
+ .queue(function( next ) {
+ ok( hasRun, "queue after show" );
+ start();
+ next();
+ });
+});
+
+asyncTest( "show: object(core animation)", function() {
+ expect( 4 );
+
+ var element = $( "#widget" ).testWidget({
+ show: {
+ effect: "slideDown",
+ duration: 123,
+ easing: "testEasing"
+ }
+ }),
+ hasRun = false;
+ $.fn.slideDown = function( duration, easing, complete ) {
+ return this.queue(function( next ) {
+ equal( duration, 123, "duration" );
+ equal( easing, "testEasing", "easing" );
+ complete();
+ next();
+ });
+ };
+
+ element
+ .delay( 50 )
+ .queue(function( next ) {
+ ok( !hasRun, "queue before show" );
+ next();
+ })
+ .testWidget( "show", function() {
+ hasRun = true;
+ })
+ .queue(function( next ) {
+ ok( hasRun, "queue after show" );
+ start();
+ next();
+ });
+});
+
+asyncTest( "show: object(effect)", function() {
+ expect( 3 );
+
+ var element = $( "#widget" ).testWidget({
+ show: {
+ effect: "testEffect",
+ duration: 123,
+ easing: "testEasing"
+ }
+ }),
+ hasRun = false;
+ $.fn.show = function( options ) {
+ return this.queue(function( next ) {
+ deepEqual( options, {
+ effect: "testEffect",
+ duration: 123,
+ easing: "testEasing",
+ complete: options.complete
+ });
+ options.complete();
+ next();
+ });
+ };
+
+ element
+ .delay( 50 )
+ .queue(function( next ) {
+ ok( !hasRun, "queue before show" );
+ next();
+ })
+ .testWidget( "show", function() {
+ hasRun = true;
+ })
+ .queue(function( next ) {
+ ok( hasRun, "queue after show" );
+ start();
+ next();
+ });
+});
diff --git a/apps/it/static/js/ui/tests/unit/widget/widget_core.js b/apps/it/static/js/ui/tests/unit/widget/widget_core.js
new file mode 100644
index 0000000..7f9145c
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/widget/widget_core.js
@@ -0,0 +1,1459 @@
+(function( $ ) {
+
+module( "widget factory", {
+ teardown: function() {
+ if ( $.ui ) {
+ delete $.ui.testWidget;
+ delete $.fn.testWidget;
+ }
+ }
+});
+
+TestHelpers.testJshint( "widget" );
+
+test( "widget creation", function() {
+ expect( 5 );
+ var method,
+ myPrototype = {
+ _create: function() {
+ equal( method, "_create", "create function is copied over" );
+ },
+ creationTest: function() {
+ equal( method, "creationTest", "random function is copied over" );
+ }
+ };
+
+ $.widget( "ui.testWidget", myPrototype );
+ ok( $.isFunction( $.ui.testWidget ), "constructor was created" );
+ equal( typeof $.ui.testWidget.prototype, "object", "prototype was created" );
+ method = "_create";
+ $.ui.testWidget.prototype._create();
+ method = "creationTest";
+ $.ui.testWidget.prototype.creationTest();
+ equal( $.ui.testWidget.prototype.option, $.Widget.prototype.option,
+ "option method copied over from base widget" );
+});
+
+test( "element normalization", function() {
+ expect( 11 );
+ var elem;
+ $.widget( "ui.testWidget", {} );
+
+ $.ui.testWidget.prototype._create = function() {
+ // workaround for core ticket #8381
+ this.element.appendTo( "#qunit-fixture" );
+ ok( this.element.is( "div" ), "generated div" );
+ deepEqual( this.element.data( "ui-testWidget" ), this, "instance stored in .data()" );
+ };
+ $.ui.testWidget();
+
+ $.ui.testWidget.prototype.defaultElement = "<span data-test='pass'></span>";
+ $.ui.testWidget.prototype._create = function() {
+ ok( this.element.is( "span[data-test=pass]" ), "generated span with properties" );
+ deepEqual( this.element.data( "ui-testWidget" ), this, "instace stored in .data()" );
+ };
+ $.ui.testWidget();
+
+ elem = $( "<input>" );
+ $.ui.testWidget.prototype._create = function() {
+ deepEqual( this.element[ 0 ], elem[ 0 ], "from element" );
+ deepEqual( elem.data( "ui-testWidget" ), this, "instace stored in .data()" );
+ };
+ $.ui.testWidget( {}, elem[ 0 ] );
+
+ elem = $( "<div>" );
+ $.ui.testWidget.prototype._create = function() {
+ deepEqual( this.element[ 0 ], elem[ 0 ], "from jQuery object" );
+ deepEqual( elem.data( "ui-testWidget" ), this, "instace stored in .data()" );
+ };
+ $.ui.testWidget( {}, elem );
+
+ elem = $( "<div id='element-normalization-selector'></div>" )
+ .appendTo( "#qunit-fixture" );
+ $.ui.testWidget.prototype._create = function() {
+ deepEqual( this.element[ 0 ], elem[ 0 ], "from selector" );
+ deepEqual( elem.data( "ui-testWidget" ), this, "instace stored in .data()" );
+ };
+ $.ui.testWidget( {}, "#element-normalization-selector" );
+
+ $.ui.testWidget.prototype.defaultElement = null;
+ $.ui.testWidget.prototype._create = function() {
+ // using strictEqual throws an error (Maximum call stack size exceeded)
+ ok( this.element[ 0 ] === this, "instance as element" );
+ };
+ $.ui.testWidget();
+});
+
+test( "custom selector expression", function() {
+ expect( 1 );
+ var elem = $( "<div>" ).appendTo( "#qunit-fixture" );
+ $.widget( "ui.testWidget", {} );
+ elem.testWidget();
+ deepEqual( $( ":ui-testwidget" )[0], elem[0] );
+ elem.testWidget( "destroy" );
+});
+
+test( "jQuery usage", function() {
+ expect( 14 );
+
+ var elem, instance, ret,
+ shouldCreate = false;
+
+ $.widget( "ui.testWidget", {
+ getterSetterVal: 5,
+ _create: function() {
+ ok( shouldCreate, "create called on instantiation" );
+ },
+ methodWithParams: function( param1, param2 ) {
+ ok( true, "method called via .pluginName(methodName)" );
+ equal( param1, "value1",
+ "parameter passed via .pluginName(methodName, param)" );
+ equal( param2, "value2",
+ "multiple parameters passed via .pluginName(methodName, param, param)" );
+
+ return this;
+ },
+ getterSetterMethod: function( val ) {
+ if ( val ) {
+ this.getterSetterVal = val;
+ } else {
+ return this.getterSetterVal;
+ }
+ },
+ jQueryObject: function() {
+ return $( "body" );
+ }
+ });
+
+ shouldCreate = true;
+ elem = $( "<div>" )
+ .bind( "testwidgetcreate", function() {
+ ok( shouldCreate, "create event triggered on instantiation" );
+ })
+ .testWidget();
+ shouldCreate = false;
+
+ instance = elem.data( "ui-testWidget" );
+ equal( typeof instance, "object", "instance stored in .data(pluginName)" );
+ equal( instance.element[0], elem[0], "element stored on widget" );
+ ret = elem.testWidget( "methodWithParams", "value1", "value2" );
+ equal( ret, elem, "jQuery object returned from method call" );
+
+ ret = elem.testWidget( "getterSetterMethod" );
+ equal( ret, 5, "getter/setter can act as getter" );
+ ret = elem.testWidget( "getterSetterMethod", 30 );
+ equal( ret, elem, "getter/setter method can be chainable" );
+ equal( instance.getterSetterVal, 30, "getter/setter can act as setter" );
+ ret = elem.testWidget( "jQueryObject" );
+ equal( ret[ 0 ], document.body, "returned jQuery object" );
+ equal( ret.end(), elem, "stack preserved" );
+
+ elem.testWidget( "destroy" );
+ equal( elem.data( "ui-testWidget" ), null );
+});
+
+test( "direct usage", function() {
+ expect( 9 );
+
+ var elem, instance, ret,
+ shouldCreate = false;
+
+ $.widget( "ui.testWidget", {
+ getterSetterVal: 5,
+ _create: function() {
+ ok( shouldCreate, "create called on instantiation" );
+ },
+ methodWithParams: function( param1, param2 ) {
+ ok( true, "method called dirctly" );
+ equal( param1, "value1", "parameter passed via direct call" );
+ equal( param2, "value2", "multiple parameters passed via direct call" );
+
+ return this;
+ },
+ getterSetterMethod: function( val ) {
+ if ( val ) {
+ this.getterSetterVal = val;
+ } else {
+ return this.getterSetterVal;
+ }
+ }
+ });
+
+ elem = $( "<div>" )[ 0 ];
+
+ shouldCreate = true;
+ instance = new $.ui.testWidget( {}, elem );
+ shouldCreate = false;
+
+ equal( $( elem ).data( "ui-testWidget" ), instance,
+ "instance stored in .data(pluginName)" );
+ equal( instance.element[ 0 ], elem, "element stored on widget" );
+
+ ret = instance.methodWithParams( "value1", "value2" );
+ equal( ret, instance, "plugin returned from method call" );
+
+ ret = instance.getterSetterMethod();
+ equal( ret, 5, "getter/setter can act as getter" );
+ instance.getterSetterMethod( 30 );
+ equal( instance.getterSetterVal, 30, "getter/setter can act as setter" );
+});
+
+test( "error handling", function() {
+ expect( 3 );
+ var error = $.error;
+ $.widget( "ui.testWidget", {
+ _privateMethod: function () {}
+ });
+ $.error = function( msg ) {
+ equal( msg, "cannot call methods on testWidget prior to initialization; " +
+ "attempted to call method 'missing'", "method call before init" );
+ };
+ $( "<div>" ).testWidget( "missing" );
+ $.error = function( msg ) {
+ equal( msg, "no such method 'missing' for testWidget widget instance",
+ "invalid method call on widget instance" );
+ };
+ $( "<div>" ).testWidget().testWidget( "missing" );
+ $.error = function ( msg ) {
+ equal( msg, "no such method '_privateMethod' for testWidget widget instance",
+ "invalid method call on widget instance" );
+ };
+ $( "<div>" ).testWidget().testWidget( "_privateMethod" );
+ $.error = error;
+});
+
+test( "merge multiple option arguments", function() {
+ expect( 1 );
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ deepEqual( this.options, {
+ create: null,
+ disabled: false,
+ option1: "value1",
+ option2: "value2",
+ option3: "value3",
+ option4: {
+ option4a: "valuea",
+ option4b: "valueb"
+ }
+ });
+ }
+ });
+ $( "<div>" ).testWidget({
+ option1: "valuex",
+ option2: "valuex",
+ option3: "value3",
+ option4: {
+ option4a: "valuex"
+ }
+ }, {
+ option1: "value1",
+ option2: "value2",
+ option4: {
+ option4b: "valueb"
+ }
+ }, {
+ option4: {
+ option4a: "valuea"
+ }
+ });
+});
+
+test( "._getCreateOptions()", function() {
+ expect( 1 );
+ $.widget( "ui.testWidget", {
+ options: {
+ option1: "valuex",
+ option2: "valuex",
+ option3: "value3"
+ },
+ _getCreateOptions: function() {
+ return {
+ option1: "override1",
+ option2: "overideX"
+ };
+ },
+ _create: function() {
+ deepEqual( this.options, {
+ create: null,
+ disabled: false,
+ option1: "override1",
+ option2: "value2",
+ option3: "value3"
+ });
+ }
+ });
+ $( "<div>" ).testWidget({ option2: "value2" });
+});
+
+test( "._getCreateEventData()", function() {
+ expect( 1 );
+ var data = { foo: "bar" };
+ $.widget( "ui.testWidget", {
+ _getCreateEventData: function() {
+ return data;
+ }
+ });
+ $( "<div>" ).testWidget({
+ create: function( event, ui ) {
+ strictEqual( ui, data, "event data" );
+ }
+ });
+});
+
+test( "re-init", function() {
+ expect( 3 );
+ var div = $( "<div>" ),
+ actions = [];
+
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ actions.push( "create" );
+ },
+ _init: function() {
+ actions.push( "init" );
+ },
+ _setOption: function( key ) {
+ actions.push( "option" + key );
+ }
+ });
+
+ actions = [];
+ div.testWidget({ foo: "bar" });
+ deepEqual( actions, [ "create", "init" ], "correct methods called on init" );
+
+ actions = [];
+ div.testWidget();
+ deepEqual( actions, [ "init" ], "correct methods call on re-init" );
+
+ actions = [];
+ div.testWidget({ foo: "bar" });
+ deepEqual( actions, [ "optionfoo", "init" ], "correct methods called on re-init with options" );
+});
+
+test( "redeclare", function() {
+ expect( 2 );
+
+ $.widget( "ui.testWidget", {} );
+ equal( $.ui.testWidget.prototype.widgetEventPrefix, "testWidget" );
+
+ $.widget( "ui.testWidget", {} );
+ equal( $.ui.testWidget.prototype.widgetEventPrefix, "testWidget" );
+});
+
+test( "inheritance", function() {
+ expect( 6 );
+ // #5830 - Widget: Using inheritance overwrites the base classes options
+ $.widget( "ui.testWidgetBase", {
+ options: {
+ obj: {
+ key1: "foo",
+ key2: "bar"
+ },
+ arr: [ "testing" ]
+ }
+ });
+
+ $.widget( "ui.testWidgetExtension", $.ui.testWidgetBase, {
+ options: {
+ obj: {
+ key1: "baz"
+ },
+ arr: [ "alpha", "beta" ]
+ }
+ });
+
+ equal( $.ui.testWidgetBase.prototype.widgetEventPrefix, "testWidgetBase",
+ "base class event prefix" );
+ deepEqual( $.ui.testWidgetBase.prototype.options.obj, {
+ key1: "foo",
+ key2: "bar"
+ }, "base class option object not overridden");
+ deepEqual( $.ui.testWidgetBase.prototype.options.arr, [ "testing" ],
+ "base class option array not overridden");
+
+ equal( $.ui.testWidgetExtension.prototype.widgetEventPrefix, "testWidgetExtension",
+ "extension class event prefix" );
+ deepEqual( $.ui.testWidgetExtension.prototype.options.obj, {
+ key1: "baz",
+ key2: "bar"
+ }, "extension class option object extends base");
+ deepEqual( $.ui.testWidgetExtension.prototype.options.arr, [ "alpha", "beta" ],
+ "extension class option array overwrites base");
+
+ delete $.ui.testWidgetBase;
+ delete $.ui.testWidgetExtension;
+});
+
+test( "._super()", function() {
+ expect( 9 );
+ var instance;
+ $.widget( "ui.testWidget", {
+ method: function( a, b ) {
+ deepEqual( this, instance, "this is correct in testWidget" );
+ deepEqual( a, 5, "parameter passed to testWidget" );
+ deepEqual( b, 20, "second parameter passed to testWidget" );
+ return a + b;
+ }
+ });
+
+ $.widget( "ui.testWidget2", $.ui.testWidget, {
+ method: function( a, b ) {
+ deepEqual( this, instance, "this is correct in testWidget2" );
+ deepEqual( a, 5, "parameter passed to testWidget2" );
+ deepEqual( b, 10, "parameter passed to testWidget2" );
+ return this._super( a, b*2 );
+ }
+ });
+
+ $.widget( "ui.testWidget3", $.ui.testWidget2, {
+ method: function( a ) {
+ deepEqual( this, instance, "this is correct in testWidget3" );
+ deepEqual( a, 5, "parameter passed to testWidget3" );
+ var ret = this._super( a, a*2 );
+ deepEqual( ret, 25, "super returned value" );
+ }
+ });
+
+ instance = $( "<div>" ).testWidget3().data( "ui-testWidget3" );
+ instance.method( 5 );
+ delete $.ui.testWidget3;
+ delete $.ui.testWidget2;
+});
+
+test( "._superApply()", function() {
+ expect( 10 );
+ var instance;
+ $.widget( "ui.testWidget", {
+ method: function( a, b ) {
+ deepEqual( this, instance, "this is correct in testWidget" );
+ deepEqual( a, 5, "parameter passed to testWidget" );
+ deepEqual( b, 10, "second parameter passed to testWidget" );
+ return a + b;
+ }
+ });
+
+ $.widget( "ui.testWidget2", $.ui.testWidget, {
+ method: function( a, b ) {
+ deepEqual( this, instance, "this is correct in testWidget2" );
+ deepEqual( a, 5, "parameter passed to testWidget2" );
+ deepEqual( b, 10, "second parameter passed to testWidget2" );
+ return this._superApply( arguments );
+ }
+ });
+
+ $.widget( "ui.testWidget3", $.ui.testWidget2, {
+ method: function( a, b ) {
+ deepEqual( this, instance, "this is correct in testWidget3" );
+ deepEqual( a, 5, "parameter passed to testWidget3" );
+ deepEqual( b, 10, "second parameter passed to testWidget3" );
+ var ret = this._superApply( arguments );
+ deepEqual( ret, 15, "super returned value" );
+ }
+ });
+
+ instance = $( "<div>" ).testWidget3().data( "ui-testWidget3" );
+ instance.method( 5, 10 );
+ delete $.ui.testWidget3;
+ delete $.ui.testWidget2;
+});
+
+test( ".option() - getter", function() {
+ expect( 6 );
+ $.widget( "ui.testWidget", {
+ _create: function() {}
+ });
+
+ var options,
+ div = $( "<div>" ).testWidget({
+ foo: "bar",
+ baz: 5,
+ qux: [ "quux", "quuux" ]
+ });
+
+ deepEqual( div.testWidget( "option", "x" ), null, "non-existent option" );
+ deepEqual( div.testWidget( "option", "foo"), "bar", "single option - string" );
+ deepEqual( div.testWidget( "option", "baz"), 5, "single option - number" );
+ deepEqual( div.testWidget( "option", "qux"), [ "quux", "quuux" ],
+ "single option - array" );
+
+ options = div.testWidget( "option" );
+ deepEqual( options, {
+ create: null,
+ disabled: false,
+ foo: "bar",
+ baz: 5,
+ qux: [ "quux", "quuux" ]
+ }, "full options hash returned" );
+ options.foo = "notbar";
+ deepEqual( div.testWidget( "option", "foo"), "bar",
+ "modifying returned options hash does not modify plugin instance" );
+});
+
+test( ".option() - deep option getter", function() {
+ expect( 5 );
+ $.widget( "ui.testWidget", {} );
+ var div = $( "<div>" ).testWidget({
+ foo: {
+ bar: "baz",
+ qux: {
+ quux: "xyzzy"
+ }
+ }
+ });
+ equal( div.testWidget( "option", "foo.bar" ), "baz", "one level deep - string" );
+ deepEqual( div.testWidget( "option", "foo.qux" ), { quux: "xyzzy" },
+ "one level deep - object" );
+ equal( div.testWidget( "option", "foo.qux.quux" ), "xyzzy", "two levels deep - string" );
+ equal( div.testWidget( "option", "x.y" ), null, "top level non-existent" );
+ equal( div.testWidget( "option", "foo.x.y" ), null, "one level deep - non-existent" );
+});
+
+test( ".option() - delegate to ._setOptions()", function() {
+ expect( 2 );
+ var div,
+ calls = [];
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ _setOptions: function( options ) {
+ calls.push( options );
+ }
+ });
+ div = $( "<div>" ).testWidget();
+
+ calls = [];
+ div.testWidget( "option", "foo", "bar" );
+ deepEqual( calls, [{ foo: "bar" }], "_setOptions called for single option" );
+
+ calls = [];
+ div.testWidget( "option", {
+ bar: "qux",
+ quux: "quuux"
+ });
+ deepEqual( calls, [{ bar: "qux", quux: "quuux" }],
+ "_setOptions called with multiple options" );
+});
+
+test( ".option() - delegate to ._setOption()", function() {
+ expect( 3 );
+ var div,
+ calls = [];
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ _setOption: function( key, val ) {
+ calls.push({
+ key: key,
+ val: val
+ });
+ }
+ });
+ div = $( "<div>" ).testWidget();
+
+ calls = [];
+ div.testWidget( "option", "foo", "bar" );
+ deepEqual( calls, [{ key: "foo", val: "bar" }],
+ "_setOption called for single option" );
+
+ calls = [];
+ div.testWidget( "option", "foo", undefined );
+ deepEqual( calls, [{ key: "foo", val: undefined }],
+ "_setOption called for single option where value is undefined" );
+
+ calls = [];
+ div.testWidget( "option", {
+ bar: "qux",
+ quux: "quuux"
+ });
+ deepEqual( calls, [
+ { key: "bar", val: "qux" },
+ { key: "quux", val: "quuux" }
+ ], "_setOption called with multiple options" );
+});
+
+test( ".option() - deep option setter", function() {
+ expect( 9 );
+ $.widget( "ui.testWidget", {} );
+ var result, div = $( "<div>" ).testWidget();
+ function deepOption( from, to, msg ) {
+ div.data( "ui-testWidget" ).options.foo = from;
+ $.ui.testWidget.prototype._setOption = function( key, value ) {
+ deepEqual( key, "foo", msg + ": key" );
+ deepEqual( value, to, msg + ": value" );
+ };
+ }
+
+ deepOption( { bar: "baz" }, { bar: "qux" }, "one deep" );
+ div.testWidget( "option", "foo.bar", "qux" );
+
+ deepOption( { bar: "baz" }, { bar: undefined }, "one deep - value = undefined" );
+
+ result = div.testWidget( "option", "foo.bar", undefined );
+
+ deepEqual ( result, div, "option should return widget on successful set operation" );
+
+ deepOption( null, { bar: "baz" }, "null" );
+ div.testWidget( "option", "foo.bar", "baz" );
+
+ deepOption(
+ { bar: "baz", qux: { quux: "quuux" } },
+ { bar: "baz", qux: { quux: "quuux", newOpt: "newVal" } },
+ "add property" );
+ div.testWidget( "option", "foo.qux.newOpt", "newVal" );
+});
+
+test( ".enable()", function() {
+ expect( 2 );
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ _setOption: function( key, val ) {
+ deepEqual( key, "disabled", "_setOption called with disabled option" );
+ deepEqual( val, false, "disabled set to false" );
+ }
+ });
+ $( "<div>" ).testWidget().testWidget( "enable" );
+});
+
+test( ".disable()", function() {
+ expect( 2 );
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ _setOption: function( key, val ) {
+ deepEqual( key, "disabled", "_setOption called with disabled option" );
+ deepEqual( val, true, "disabled set to true" );
+ }
+ });
+ $( "<div>" ).testWidget().testWidget( "disable" );
+});
+
+test( ".widget() - base", function() {
+ expect( 1 );
+ $.widget( "ui.testWidget", {
+ _create: function() {}
+ });
+ var div = $( "<div>" ).testWidget();
+ deepEqual( div[0], div.testWidget( "widget" )[0]);
+});
+
+test( ".widget() - overriden", function() {
+ expect( 1 );
+ var wrapper = $( "<div>" );
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ widget: function() {
+ return wrapper;
+ }
+ });
+ deepEqual( wrapper[0], $( "<div>" ).testWidget().testWidget( "widget" )[0] );
+});
+
+test( "._on() to element (default)", function() {
+ expect( 12 );
+ var that, widget;
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ that = this;
+ this._on({
+ keyup: this.keyup,
+ keydown: "keydown"
+ });
+ },
+ keyup: function( event ) {
+ equal( that, this );
+ equal( that.element[0], event.currentTarget );
+ equal( "keyup", event.type );
+ },
+ keydown: function( event ) {
+ equal( that, this );
+ equal( that.element[0], event.currentTarget );
+ equal( "keydown", event.type );
+ }
+ });
+ widget = $( "<div></div>" )
+ .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" );
+});
+
+test( "._on() to element with suppressDisabledCheck", function() {
+ expect( 18 );
+ var that, widget;
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ that = this;
+ this._on( true, {
+ keyup: this.keyup,
+ keydown: "keydown"
+ });
+ },
+ keyup: function( event ) {
+ equal( that, this );
+ equal( that.element[0], event.currentTarget );
+ equal( "keyup", event.type );
+ },
+ keydown: function( event ) {
+ equal( that, this );
+ equal( that.element[0], event.currentTarget );
+ equal( "keydown", event.type );
+ }
+ });
+ widget = $( "<div></div>" )
+ .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" );
+});
+
+test( "._on() to descendent", function() {
+ expect( 12 );
+ var that, widget, descendant;
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ that = this;
+ this._on( this.element.find( "strong" ), {
+ keyup: this.keyup,
+ keydown: "keydown"
+ });
+ },
+ keyup: function( event ) {
+ equal( that, this );
+ equal( that.element.find( "strong" )[0], event.currentTarget );
+ equal( "keyup", event.type );
+ },
+ keydown: function(event) {
+ equal( that, this );
+ equal( that.element.find( "strong" )[0], event.currentTarget );
+ equal( "keydown", event.type );
+ }
+ });
+ // trigger events on both widget and descendent to ensure that only descendent receives them
+ widget = $( "<div><p><strong>hello</strong> world</p></div>" )
+ .testWidget()
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ descendant = widget.find( "strong" )
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ widget
+ .testWidget( "disable" )
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ descendant
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ widget
+ .testWidget( "enable" )
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ descendant
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ descendant
+ .addClass( "ui-state-disabled" )
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ widget
+ .testWidget( "destroy" )
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+ descendant
+ .trigger( "keyup" )
+ .trigger( "keydown" );
+});
+
+test( "_on() with delegate", function() {
+ expect( 8 );
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ var uuid = this.uuid;
+ this.element = {
+ bind: function( event, handler ) {
+ equal( event, "click.testWidget" + uuid );
+ ok( $.isFunction(handler) );
+ },
+ trigger: $.noop
+ };
+ this.widget = function() {
+ return {
+ delegate: function( selector, event, handler ) {
+ equal( selector, "a" );
+ equal( event, "click.testWidget" + uuid );
+ ok( $.isFunction(handler) );
+ }
+ };
+ };
+ this._on({
+ "click": "handler",
+ "click a": "handler"
+ });
+ this.widget = function() {
+ return {
+ delegate: function( selector, event, handler ) {
+ equal( selector, "form fieldset > input" );
+ equal( event, "change.testWidget" + uuid );
+ ok( $.isFunction(handler) );
+ }
+ };
+ };
+ this._on({
+ "change form fieldset > input": "handler"
+ });
+ }
+ });
+ $.ui.testWidget();
+});
+
+test( "_on() with delegate to descendent", function() {
+ expect( 4 );
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ this.target = $( "<p><strong>hello</strong> world</p>" );
+ this.child = this.target.children();
+ this._on( this.target, {
+ "keyup": "handlerDirect",
+ "keyup strong": "handlerDelegated"
+ });
+ this.child.trigger( "keyup" );
+ },
+ handlerDirect: function( event ) {
+ deepEqual( event.currentTarget, this.target[ 0 ] );
+ deepEqual( event.target, this.child[ 0 ] );
+ },
+ handlerDelegated: function( event ) {
+ deepEqual( event.currentTarget, this.child[ 0 ] );
+ deepEqual( event.target, this.child[ 0 ] );
+ }
+ });
+ $.ui.testWidget();
+});
+
+test( "_on() to common element", function() {
+ expect( 1 );
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ this._on( this.document, {
+ "customevent": "_handler"
+ });
+ },
+ _handler: function() {
+ ok( true, "handler triggered" );
+ }
+ });
+ var widget = $( "#widget" ).testWidget().data( "ui-testWidget" );
+ $( "#widget-wrapper" ).testWidget();
+ widget.destroy();
+ $( document ).trigger( "customevent" );
+});
+
+test( "_off() - single event", function() {
+ expect( 3 );
+
+ $.widget( "ui.testWidget", {} );
+ var shouldTriggerWidget, shouldTriggerOther,
+ element = $( "#widget" ),
+ widget = element.testWidget().data( "ui-testWidget" );
+ widget._on( element, { foo: function() {
+ ok( shouldTriggerWidget, "foo called from _on" );
+ }});
+ element.bind( "foo", function() {
+ ok( shouldTriggerOther, "foo called from bind" );
+ });
+ shouldTriggerWidget = true;
+ shouldTriggerOther = true;
+ element.trigger( "foo" );
+ shouldTriggerWidget = false;
+ widget._off( element, "foo" );
+ element.trigger( "foo" );
+});
+
+test( "_off() - multiple events", function() {
+ expect( 6 );
+
+ $.widget( "ui.testWidget", {} );
+ var shouldTriggerWidget, shouldTriggerOther,
+ element = $( "#widget" ),
+ widget = element.testWidget().data( "ui-testWidget" );
+ widget._on( element, {
+ foo: function() {
+ ok( shouldTriggerWidget, "foo called from _on" );
+ },
+ bar: function() {
+ ok( shouldTriggerWidget, "bar called from _on" );
+ }
+ });
+ element.bind( "foo bar", function( event ) {
+ ok( shouldTriggerOther, event.type + " called from bind" );
+ });
+ shouldTriggerWidget = true;
+ shouldTriggerOther = true;
+ element.trigger( "foo" );
+ element.trigger( "bar" );
+ shouldTriggerWidget = false;
+ widget._off( element, "foo bar" );
+ element.trigger( "foo" );
+ element.trigger( "bar" );
+});
+
+test( "_off() - all events", function() {
+ expect( 6 );
+
+ $.widget( "ui.testWidget", {} );
+ var shouldTriggerWidget, shouldTriggerOther,
+ element = $( "#widget" ),
+ widget = element.testWidget().data( "ui-testWidget" );
+ widget._on( element, {
+ foo: function() {
+ ok( shouldTriggerWidget, "foo called from _on" );
+ },
+ bar: function() {
+ ok( shouldTriggerWidget, "bar called from _on" );
+ }
+ });
+ element.bind( "foo bar", function( event ) {
+ ok( shouldTriggerOther, event.type + " called from bind" );
+ });
+ shouldTriggerWidget = true;
+ shouldTriggerOther = true;
+ element.trigger( "foo" );
+ element.trigger( "bar" );
+ shouldTriggerWidget = false;
+ widget._off( element );
+ element.trigger( "foo" );
+ element.trigger( "bar" );
+});
+
+test( "._hoverable()", function() {
+ expect( 10 );
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ this._hoverable( this.element.children() );
+ }
+ });
+
+ var div = $( "#widget" ).testWidget().children();
+ ok( !div.hasClass( "ui-state-hover" ), "not hovered on init" );
+ div.trigger( "mouseenter" );
+ ok( div.hasClass( "ui-state-hover" ), "hovered after mouseenter" );
+ div.trigger( "mouseleave" );
+ ok( !div.hasClass( "ui-state-hover" ), "not hovered after mouseleave" );
+
+ div.trigger( "mouseenter" );
+ ok( div.hasClass( "ui-state-hover" ), "hovered after mouseenter" );
+ $( "#widget" ).testWidget( "disable" );
+ ok( !div.hasClass( "ui-state-hover" ), "not hovered while disabled" );
+ div.trigger( "mouseenter" );
+ ok( !div.hasClass( "ui-state-hover" ), "can't hover while disabled" );
+ $( "#widget" ).testWidget( "enable" );
+ ok( !div.hasClass( "ui-state-hover" ), "enabling doesn't reset hover" );
+
+ div.trigger( "mouseenter" );
+ ok( div.hasClass( "ui-state-hover" ), "hovered after mouseenter" );
+ $( "#widget" ).testWidget( "destroy" );
+ ok( !div.hasClass( "ui-state-hover" ), "not hovered after destroy" );
+ div.trigger( "mouseenter" );
+ ok( !div.hasClass( "ui-state-hover" ), "event handler removed on destroy" );
+});
+
+test( "._focusable()", function() {
+ expect( 10 );
+ $.widget( "ui.testWidget", {
+ _create: function() {
+ this._focusable( this.element.children() );
+ }
+ });
+
+ var div = $( "#widget" ).testWidget().children();
+ ok( !div.hasClass( "ui-state-focus" ), "not focused on init" );
+ div.trigger( "focusin" );
+ ok( div.hasClass( "ui-state-focus" ), "focused after explicit focus" );
+ div.trigger( "focusout" );
+ ok( !div.hasClass( "ui-state-focus" ), "not focused after blur" );
+
+ div.trigger( "focusin" );
+ ok( div.hasClass( "ui-state-focus" ), "focused after explicit focus" );
+ $( "#widget" ).testWidget( "disable" );
+ ok( !div.hasClass( "ui-state-focus" ), "not focused while disabled" );
+ div.trigger( "focusin" );
+ ok( !div.hasClass( "ui-state-focus" ), "can't focus while disabled" );
+ $( "#widget" ).testWidget( "enable" );
+ ok( !div.hasClass( "ui-state-focus" ), "enabling doesn't reset focus" );
+
+ div.trigger( "focusin" );
+ ok( div.hasClass( "ui-state-focus" ), "focused after explicit focus" );
+ $( "#widget" ).testWidget( "destroy" );
+ ok( !div.hasClass( "ui-state-focus" ), "not focused after destroy" );
+ div.trigger( "focusin" );
+ ok( !div.hasClass( "ui-state-focus" ), "event handler removed on destroy" );
+});
+
+test( "._trigger() - no event, no ui", function() {
+ expect( 7 );
+ var handlers = [];
+
+ $.widget( "ui.testWidget", {
+ _create: function() {}
+ });
+
+ $( "#widget" ).testWidget({
+ foo: function( event, ui ) {
+ deepEqual( event.type, "testwidgetfoo", "correct event type in callback" );
+ deepEqual( ui, {}, "empty ui hash passed" );
+ handlers.push( "callback" );
+ }
+ });
+ $( document ).add( "#widget-wrapper" ).add( "#widget" )
+ .bind( "testwidgetfoo", function( event, ui ) {
+ deepEqual( ui, {}, "empty ui hash passed" );
+ handlers.push( this );
+ });
+ deepEqual( $( "#widget" ).data( "ui-testWidget" )._trigger( "foo" ), true,
+ "_trigger returns true when event is not cancelled" );
+ deepEqual( handlers, [
+ $( "#widget" )[ 0 ],
+ $( "#widget-wrapper" )[ 0 ],
+ document,
+ "callback"
+ ], "event bubbles and then invokes callback" );
+
+ $( document ).unbind( "testwidgetfoo" );
+});
+
+test( "._trigger() - cancelled event", function() {
+ expect( 3 );
+
+ $.widget( "ui.testWidget", {
+ _create: function() {}
+ });
+
+ $( "#widget" ).testWidget({
+ foo: function() {
+ ok( true, "callback invoked even if event is cancelled" );
+ }
+ })
+ .bind( "testwidgetfoo", function() {
+ ok( true, "event was triggered" );
+ return false;
+ });
+ deepEqual( $( "#widget" ).data( "ui-testWidget" )._trigger( "foo" ), false,
+ "_trigger returns false when event is cancelled" );
+});
+
+test( "._trigger() - cancelled callback", function() {
+ expect( 1 );
+ $.widget( "ui.testWidget", {
+ _create: function() {}
+ });
+
+ $( "#widget" ).testWidget({
+ foo: function() {
+ return false;
+ }
+ });
+ deepEqual( $( "#widget" ).data( "ui-testWidget" )._trigger( "foo" ), false,
+ "_trigger returns false when callback returns false" );
+});
+
+test( "._trigger() - provide event and ui", function() {
+ expect( 7 );
+
+ var originalEvent = $.Event( "originalTest" );
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ testEvent: function() {
+ var ui = {
+ foo: "bar",
+ baz: {
+ qux: 5,
+ quux: 20
+ }
+ };
+ this._trigger( "foo", originalEvent, ui );
+ deepEqual( ui, {
+ foo: "notbar",
+ baz: {
+ qux: 10,
+ quux: "jQuery"
+ }
+ }, "ui object modified" );
+ }
+ });
+ $( "#widget" ).bind( "testwidgetfoo", function( event, ui ) {
+ equal( event.originalEvent, originalEvent, "original event object passed" );
+ deepEqual( ui, {
+ foo: "bar",
+ baz: {
+ qux: 5,
+ quux: 20
+ }
+ }, "ui hash passed" );
+ ui.foo = "notbar";
+ });
+ $( "#widget-wrapper" ).bind( "testwidgetfoo", function( event, ui ) {
+ equal( event.originalEvent, originalEvent, "original event object passed" );
+ deepEqual( ui, {
+ foo: "notbar",
+ baz: {
+ qux: 5,
+ quux: 20
+ }
+ }, "modified ui hash passed" );
+ ui.baz.qux = 10;
+ });
+ $( "#widget" ).testWidget({
+ foo: function( event, ui ) {
+ equal( event.originalEvent, originalEvent, "original event object passed" );
+ deepEqual( ui, {
+ foo: "notbar",
+ baz: {
+ qux: 10,
+ quux: 20
+ }
+ }, "modified ui hash passed" );
+ ui.baz.quux = "jQuery";
+ }
+ })
+ .testWidget( "testEvent" );
+});
+
+test( "._trigger() - array as ui", function() {
+ // #6795 - Widget: handle array arguments to _trigger consistently
+ expect( 4 );
+
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ testEvent: function() {
+ var ui = {
+ foo: "bar",
+ baz: {
+ qux: 5,
+ quux: 20
+ }
+ },
+ extra = {
+ bar: 5
+ };
+ this._trigger( "foo", null, [ ui, extra ] );
+ }
+ });
+ $( "#widget" ).bind( "testwidgetfoo", function( event, ui, extra ) {
+ deepEqual( ui, {
+ foo: "bar",
+ baz: {
+ qux: 5,
+ quux: 20
+ }
+ }, "event: ui hash passed" );
+ deepEqual( extra, {
+ bar: 5
+ }, "event: extra argument passed" );
+ });
+ $( "#widget" ).testWidget({
+ foo: function( event, ui, extra ) {
+ deepEqual( ui, {
+ foo: "bar",
+ baz: {
+ qux: 5,
+ quux: 20
+ }
+ }, "callback: ui hash passed" );
+ deepEqual( extra, {
+ bar: 5
+ }, "callback: extra argument passed" );
+ }
+ })
+ .testWidget( "testEvent" );
+});
+
+test( "._trigger() - instance as element", function() {
+ expect( 4 );
+ $.widget( "ui.testWidget", {
+ defaultElement: null,
+ testEvent: function() {
+ this._trigger( "foo", null, { foo: "bar" } );
+ }
+ });
+ var instance = $.ui.testWidget({
+ foo: function( event, ui ) {
+ equal( event.type, "testwidgetfoo", "event object passed to callback" );
+ deepEqual( ui, { foo: "bar" }, "ui object passed to callback" );
+ }
+ });
+ $( instance ).bind( "testwidgetfoo", function( event, ui ) {
+ equal( event.type, "testwidgetfoo", "event object passed to event handler" );
+ deepEqual( ui, { foo: "bar" }, "ui object passed to event handler" );
+ });
+ instance.testEvent();
+});
+
+(function() {
+ function shouldDestroy( expected, callback ) {
+ expect( 1 );
+ var destroyed = false;
+ $.widget( "ui.testWidget", {
+ _create: function() {},
+ destroy: function() {
+ destroyed = true;
+ }
+ });
+ callback();
+ equal( destroyed, expected );
+ }
+
+ test( "auto-destroy - .remove()", function() {
+ shouldDestroy( true, function() {
+ $( "#widget" ).testWidget().remove();
+ });
+ });
+
+ test( "auto-destroy - .remove() when disabled", function() {
+ shouldDestroy( true, function() {
+ $( "#widget" ).testWidget({ disabled: true }).remove();
+ });
+ });
+
+ test( "auto-destroy - .remove() on parent", function() {
+ shouldDestroy( true, function() {
+ $( "#widget" ).testWidget().parent().remove();
+ });
+ });
+
+ test( "auto-destroy - .remove() on child", function() {
+ shouldDestroy( false, function() {
+ $( "#widget" ).testWidget().children().remove();
+ });
+ });
+
+ test( "auto-destroy - .empty()", function() {
+ shouldDestroy( false, function() {
+ $( "#widget" ).testWidget().empty();
+ });
+ });
+
+ test( "auto-destroy - .empty() on parent", function() {
+ shouldDestroy( true, function() {
+ $( "#widget" ).testWidget().parent().empty();
+ });
+ });
+
+ test( "auto-destroy - .detach()", function() {
+ shouldDestroy( false, function() {
+ $( "#widget" ).testWidget().detach();
+ });
+ });
+
+ test( "destroy - remove event bubbling", function() {
+ shouldDestroy( false, function() {
+ $( "<div>child</div>" ).appendTo( $( "#widget" ).testWidget() )
+ .trigger( "remove" );
+ });
+ });
+}());
+
+test( "redefine", function() {
+ expect( 4 );
+ $.widget( "ui.testWidget", {
+ method: function( str ) {
+ strictEqual( this, instance, "original invoked with correct this" );
+ equal( str, "bar", "original invoked with correct parameter" );
+ }
+ });
+ $.ui.testWidget.foo = "bar";
+ $.widget( "ui.testWidget", $.ui.testWidget, {
+ method: function( str ) {
+ equal( str, "foo", "new invoked with correct parameter" );
+ this._super( "bar" );
+ }
+ });
+
+ var instance = new $.ui.testWidget({});
+ instance.method( "foo" );
+ equal( $.ui.testWidget.foo, "bar", "static properties remain" );
+});
+
+test( "redefine deep prototype chain", function() {
+ expect( 8 );
+ $.widget( "ui.testWidget", {
+ method: function( str ) {
+ strictEqual( this, instance, "original invoked with correct this" );
+ equal( str, "level 4", "original invoked with correct parameter" );
+ }
+ });
+ $.widget( "ui.testWidget2", $.ui.testWidget, {
+ method: function( str ) {
+ strictEqual( this, instance, "testWidget2 invoked with correct this" );
+ equal( str, "level 2", "testWidget2 invoked with correct parameter" );
+ this._super( "level 3" );
+ }
+ });
+ $.widget( "ui.testWidget3", $.ui.testWidget2, {
+ method: function( str ) {
+ strictEqual( this, instance, "testWidget3 invoked with correct this" );
+ equal( str, "level 1", "testWidget3 invoked with correct parameter" );
+ this._super( "level 2" );
+ }
+ });
+ // redefine testWidget after other widgets have inherited from it
+ // this tests whether the inheriting widgets get updated prototype chains
+ $.widget( "ui.testWidget", $.ui.testWidget, {
+ method: function( str ) {
+ strictEqual( this, instance, "new invoked with correct this" );
+ equal( str, "level 3", "new invoked with correct parameter" );
+ this._super( "level 4" );
+ }
+ });
+ // redefine testWidget3 after it has been automatically redefined
+ // this tests whether we properly handle _super() when the topmost prototype
+ // doesn't have the method defined
+ $.widget( "ui.testWidget3", $.ui.testWidget3, {} );
+
+ var instance = new $.ui.testWidget3({});
+ instance.method( "level 1" );
+
+ delete $.ui.testWidget3;
+ delete $.ui.testWidget2;
+});
+
+test( "redefine - widgetEventPrefix", function() {
+ expect( 2 );
+
+ $.widget( "ui.testWidget", {
+ widgetEventPrefix: "test"
+ });
+ equal( $.ui.testWidget.prototype.widgetEventPrefix, "test",
+ "cusotm prefix in original" );
+
+ $.widget( "ui.testWidget", $.ui.testWidget, {} );
+ equal( $.ui.testWidget.prototype.widgetEventPrefix, "test",
+ "cusotm prefix in extension" );
+
+});
+
+test( "mixins", function() {
+ expect( 2 );
+
+ var mixin = {
+ method: function() {
+ return "mixed " + this._super();
+ }
+ };
+
+ $.widget( "ui.testWidget1", {
+ method: function() {
+ return "testWidget1";
+ }
+ });
+ $.widget( "ui.testWidget2", {
+ method: function() {
+ return "testWidget2";
+ }
+ });
+ $.widget( "ui.testWidget1", $.ui.testWidget1, mixin );
+ $.widget( "ui.testWidget2", $.ui.testWidget2, mixin );
+
+ equal( $( "<div>" ).testWidget1().testWidget1( "method" ),
+ "mixed testWidget1", "testWidget1 mixin successful" );
+ equal( $( "<div>" ).testWidget2().testWidget2( "method" ),
+ "mixed testWidget2", "testWidget2 mixin successful" );
+});
+
+asyncTest( "_delay", function() {
+ expect( 6 );
+ var order = 0,
+ that;
+ $.widget( "ui.testWidget", {
+ defaultElement: null,
+ _create: function() {
+ that = this;
+ var timer = this._delay(function() {
+ strictEqual( this, that );
+ equal( order, 1 );
+ start();
+ }, 500);
+ ok( timer !== undefined );
+ timer = this._delay("callback");
+ ok( timer !== undefined );
+ },
+ callback: function() {
+ strictEqual( this, that );
+ equal( order, 0 );
+ order += 1;
+ }
+ });
+ $( "#widget" ).testWidget();
+});
+
+test( "$.widget.bridge()", function() {
+ expect( 9 );
+
+ var instance, ret,
+ elem = $( "<div>" );
+
+ function TestWidget( options, element ) {
+ deepEqual( options, { foo: "bar" }, "options passed" );
+ strictEqual( element, elem[ 0 ], "element passed" );
+ }
+
+ $.extend( TestWidget.prototype, {
+ method: function( param ) {
+ ok( true, "method called via .pluginName(methodName)" );
+ equal( param, "value1",
+ "parameter passed via .pluginName(methodName, param)" );
+ },
+ getter: function() {
+ return "qux";
+ }
+ });
+
+ $.widget.bridge( "testWidget", TestWidget );
+
+ ok( $.isFunction( $.fn.testWidget ), "jQuery plugin was created" );
+
+ strictEqual( elem.testWidget({ foo: "bar" }), elem, "plugin returns original jQuery object" );
+ instance = elem.data( "testWidget" );
+ equal( typeof instance, "object", "instance stored in .data(pluginName)" );
+
+ ret = elem.testWidget( "method", "value1" );
+ equal( ret, elem, "jQuery object returned from method call" );
+
+ ret = elem.testWidget( "getter" );
+ equal( ret, "qux", "getter returns value" );
+});
+
+test( "$.widget.bridge() - widgetFullName", function() {
+ expect( 1 );
+
+ var instance,
+ elem = $( "<div>" );
+
+ function TestWidget() {}
+ TestWidget.prototype.widgetFullName = "custom-widget";
+ $.widget.bridge( "testWidget", TestWidget );
+
+ elem.testWidget();
+ instance = elem.data( "custom-widget" );
+ equal( typeof instance, "object", "instance stored in .data(widgetFullName)" );
+});
+
+}( jQuery ) );
diff --git a/apps/it/static/js/ui/tests/unit/widget/widget_extend.js b/apps/it/static/js/ui/tests/unit/widget/widget_extend.js
new file mode 100644
index 0000000..14f9a46
--- /dev/null
+++ b/apps/it/static/js/ui/tests/unit/widget/widget_extend.js
@@ -0,0 +1,105 @@
+test( "$.widget.extend()", function() {
+ expect( 27 );
+
+ var ret, empty, optionsWithLength, optionsWithDate, myKlass, customObject, optionsWithCustomObject, nullUndef,
+ target, recursive, obj, input, output,
+ settings = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" },
+ options = { xnumber2: 1, xstring2: "x", xxx: "newstring" },
+ optionsCopy = { xnumber2: 1, xstring2: "x", xxx: "newstring" },
+ merged = { xnumber1: 5, xnumber2: 1, xstring1: "peter", xstring2: "x", xxx: "newstring" },
+ deep1 = { foo: { bar: true } },
+ deep2 = { foo: { baz: true }, foo2: document },
+ deep2copy = { foo: { baz: true }, foo2: document },
+ deepmerged = { foo: { bar: true, baz: true }, foo2: document },
+ arr = [1, 2, 3],
+ nestedarray = { arr: arr },
+ defaults = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" },
+ defaultsCopy = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" },
+ options1 = { xnumber2: 1, xstring2: "x" },
+ options1Copy = { xnumber2: 1, xstring2: "x" },
+ options2 = { xstring2: "xx", xxx: "newstringx" },
+ options2Copy = { xstring2: "xx", xxx: "newstringx" },
+ merged2 = { xnumber1: 5, xnumber2: 1, xstring1: "peter", xstring2: "xx", xxx: "newstringx" };
+
+ $.widget.extend( settings, options );
+ deepEqual( settings, merged, "Check if extended: settings must be extended" );
+ deepEqual( options, optionsCopy, "Check if not modified: options must not be modified" );
+
+ $.widget.extend( deep1, deep2 );
+ deepEqual( deep1.foo, deepmerged.foo, "Check if foo: settings must be extended" );
+ deepEqual( deep2.foo, deep2copy.foo, "Check if not deep2: options must not be modified" );
+ equal( deep1.foo2, document, "Make sure that a deep clone was not attempted on the document" );
+
+ strictEqual( $.widget.extend({}, nestedarray).arr, arr, "Don't clone arrays" );
+ ok( $.isPlainObject( $.widget.extend({ arr: arr }, { arr: {} }).arr ), "Cloned object heve to be an plain object" );
+
+ empty = {};
+ optionsWithLength = { foo: { length: -1 } };
+ $.widget.extend( empty, optionsWithLength );
+ deepEqual( empty.foo, optionsWithLength.foo, "The length property must copy correctly" );
+
+ empty = {};
+ optionsWithDate = { foo: { date: new Date() } };
+ $.widget.extend( empty, optionsWithDate );
+ deepEqual( empty.foo, optionsWithDate.foo, "Dates copy correctly" );
+
+ myKlass = function() {};
+ customObject = new myKlass();
+ optionsWithCustomObject = { foo: { date: customObject } };
+ empty = {};
+ $.widget.extend( empty, optionsWithCustomObject );
+ strictEqual( empty.foo.date, customObject, "Custom objects copy correctly (no methods)" );
+
+ // Makes the class a little more realistic
+ myKlass.prototype = { someMethod: function(){} };
+ empty = {};
+ $.widget.extend( empty, optionsWithCustomObject );
+ strictEqual( empty.foo.date, customObject, "Custom objects copy correctly" );
+
+ ret = $.widget.extend({ foo: 4 }, { foo: Number(5) } );
+ equal( ret.foo, 5, "Wrapped numbers copy correctly" );
+
+ nullUndef = $.widget.extend( {}, options, { xnumber2: null } );
+ strictEqual( nullUndef.xnumber2, null, "Check to make sure null values are copied");
+
+ nullUndef = $.widget.extend( {}, options, { xnumber2: undefined } );
+ strictEqual( nullUndef.xnumber2, options.xnumber2, "Check to make sure undefined values are not copied");
+
+ nullUndef = $.widget.extend( {}, options, { xnumber0: null } );
+ strictEqual( nullUndef.xnumber0, null, "Check to make sure null values are inserted");
+
+ target = {};
+ recursive = { foo:target, bar:5 };
+ $.widget.extend( target, recursive );
+ deepEqual( target, { foo: {}, bar: 5 }, "Check to make sure a recursive obj doesn't go never-ending loop by not copying it over" );
+
+ ret = $.widget.extend( { foo: [] }, { foo: [0] } ); // 1907
+ equal( ret.foo.length, 1, "Check to make sure a value with coersion 'false' copies over when necessary to fix #1907" );
+
+ ret = $.widget.extend( { foo: "1,2,3" }, { foo: [ 1, 2, 3 ] } );
+ deepEqual( ret.foo, [ 1, 2, 3 ], "Properly extend a string to array." );
+
+ ret = $.widget.extend( { foo: "1,2,3" }, { foo: { to: "object" } } );
+ deepEqual( ret.foo, { to: "object" }, "Properly extend a string to object." );
+
+ ret = $.widget.extend( { foo: "bar" }, { foo: null } );
+ strictEqual( ret.foo, null, "Make sure a null value doesn't crash with deep extend, for #1908" );
+
+ obj = { foo: null };
+ $.widget.extend( obj, { foo:"notnull" } );
+ equal( obj.foo, "notnull", "Make sure a null value can be overwritten" );
+
+ settings = $.widget.extend( {}, defaults, options1, options2 );
+ deepEqual( settings, merged2, "Check if extended: settings must be extended" );
+ deepEqual( defaults, defaultsCopy, "Check if not modified: options1 must not be modified" );
+ deepEqual( options1, options1Copy, "Check if not modified: options1 must not be modified" );
+ deepEqual( options2, options2Copy, "Check if not modified: options2 must not be modified" );
+
+ input = {
+ key: [ 1, 2, 3 ]
+ };
+ output = $.widget.extend( {}, input );
+ deepEqual( input, output, "don't clone arrays" );
+ input.key[0] = 10;
+ deepEqual( input, output, "don't clone arrays" );
+});