Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions demos/selectmenu/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script src="../../ui/widget.js"></script>
<script src="../../ui/position.js"></script>
<script src="../../ui/menu.js"></script>
<script src="../../ui/form-reset-mixin.js"></script>
<script src="../../ui/selectmenu.js"></script>
<link rel="stylesheet" href="../demos.css">
<script>
Expand Down
1 change: 1 addition & 0 deletions tests/unit/all.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"draggable/draggable.html",
"droppable/droppable.html",
"effects/effects.html",
"form-reset-mixin/form-reset-mixin.html",
"menu/menu.html",
"position/position.html",
"progressbar/progressbar.html",
Expand Down
26 changes: 26 additions & 0 deletions tests/unit/form-reset-mixin/all.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Form Reset Mixin Test Suite</title>

<script src="../../../external/jquery/jquery.js"></script>

<link rel="stylesheet" href="../../../external/qunit/qunit.css">
<link rel="stylesheet" href="../../../external/qunit-composite/qunit-composite.css">
<script src="../../../external/qunit/qunit.js"></script>
<script src="../../../external/qunit-composite/qunit-composite.js"></script>
<script src="../subsuite.js"></script>

<script>
testAllVersions( "form-reset-mixin" );
</script>
</head>
<body>

<div id="qunit"></div>
<div id="qunit-fixture">

</div>
</body>
</html>
97 changes: 97 additions & 0 deletions tests/unit/form-reset-mixin/core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
define( [
"jquery",
"lib/common",
"ui/widget",
"ui/form-reset-mixin"
], function( $, common ) {

module( "widget factory", {
setup: function() {
$.widget( "ui.testWidget", [ $.ui.formResetMixin, {
_create: function() {
this._bindFormResetHandler();
},
_destroy: function() {
this._unbindFormResetHandler();
},
refresh: function() {
$.ui.testWidget.refreshed.push( this.element.attr( "id" ) );
}
} ] );

$.ui.testWidget.refreshed = [];
},

teardown: function() {
if ( $.ui ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this if actually needed? Looks like $.ui these will always be defined.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's always defined. I had copied this from the widget tests, where it may not exist yet.

delete $.ui.testWidget;
delete $.fn.testWidget;
}
}
});

common.testJshint( "form-reset-mixin" );

asyncTest( "form reset", function() {
expect( 2 );

var form = $( "#main" );
var inputs = form.find( "input" );

inputs.testWidget();
form.on( "reset", function() {
setTimeout(function() {
deepEqual( $.ui.testWidget.refreshed, [ "input1", "input2", "input3", "input4" ],
"All widgets are refreshed on form reset" );
equal( form.data( "ui-form-reset-instances" ).length, 4,
"All widget instances are tracked against the form" );
start();
} );
} );
form[ 0 ].reset();
} );

asyncTest( "destroy", function() {
expect( 2 );

var form = $( "#main" );
var inputs = form.find( "input" );

inputs
.testWidget()
.eq( 1 )
.testWidget( "destroy" );

form.on( "reset", function() {
setTimeout(function() {
deepEqual( $.ui.testWidget.refreshed, [ "input1", "input3", "input4" ],
"All widgets are refreshed on form reset" );
deepEqual( form.data( "ui-form-reset-instances" ).length, 3,
"All widget instances are tracked against the form" );
start();
} );
} );
form[ 0 ].reset();
} );

asyncTest( "destroy all", function() {
expect( 2 );

var form = $( "#main" );

form.find( "input" )
.testWidget()
.testWidget( "destroy" );

form.on( "reset", function() {
setTimeout(function() {
deepEqual( $.ui.testWidget.refreshed, [], "No widgets are refreshed after destroy" );
strictEqual( form.data( "ui-form-reset-instances" ), undefined,
"Form data is removed when the last widget instance is destroyed" );
start();
} );
} );
form[ 0 ].reset();
} );

} );
26 changes: 26 additions & 0 deletions tests/unit/form-reset-mixin/form-reset-mixin.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Form Reset Mixin Test Suite</title>

<script src="../../../external/requirejs/require.js"></script>
<script src="../../lib/css.js"></script>
<script src="../../lib/bootstrap.js" data-modules="core">
</script>
</head>
<body>

<div id="qunit"></div>
<div id="qunit-fixture">

<form id="main">
<input id="input1">
<input id="input2">
<input id="input3">
<input id="input4">
</form>

</div>
</body>
</html>
79 changes: 79 additions & 0 deletions tests/unit/widget/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,85 @@ test( "._superApply()", function() {
delete $.fn.testWidget2;
});

test( "mixins", function() {
expect( 5 );

var mixin1 = {
foo: function() {
equal( method, "foo", "Methods from first mixin are copied over" );
}
};
var mixin2 = {
bar: function() {
equal( method, "bar", "Methods from second mixin are copied over" );
}
};
var prototype = {
baz: function() {
equal( method, "baz", "Methods from protoype are copied over" );
}
};
var existingBar = mixin2.bar;
var method;

$.widget( "ui.testWidget", [ mixin1, mixin2, prototype ] );
method = "foo";
$.ui.testWidget.prototype.foo();
method = "bar";
$.ui.testWidget.prototype.bar();
method = "baz";
$.ui.testWidget.prototype.baz();

mixin1.foo = function() {
ok( false, "Changes to a mixin don't change the prototype" );
};
method = "foo";
$.ui.testWidget.prototype.foo();

$.ui.testWidget.prototype.bar = function() {};
strictEqual( mixin2.bar, existingBar, "Changes to a prototype don't change the mixin" );
});

test( "mixins with inheritance", function() {
expect( 4 );

var mixin1 = {
foo: function() {
equal( method, "foo", "Methods from first mixin are copied over" );
}
};
var mixin2 = {
bar: function() {
equal( method, "bar", "Methods from second mixin are copied over" );
}
};
var parentPrototype = {
baz: function() {
equal( method, "baz", "Methods from parent protoype are copied over" );
}
};
var childPrototype = {
qux: function() {
equal( method, "qux", "Methods from child protoype are copied over" );
}
};
var method;

$.widget( "ui.testWidget", [ mixin1, parentPrototype ] );
$.widget( "ui.testWidget2", $.ui.testWidget, [ mixin2, childPrototype ] );
method = "foo";
$.ui.testWidget2.prototype.foo();
method = "bar";
$.ui.testWidget2.prototype.bar();
method = "baz";
$.ui.testWidget2.prototype.baz();
method = "qux";
$.ui.testWidget2.prototype.qux();

delete $.ui.testWidget2;
delete $.fn.testWidget2;
});

test( ".option() - getter", function() {
expect( 6 );
$.widget( "ui.testWidget", {
Expand Down
62 changes: 62 additions & 0 deletions ui/form-reset-mixin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
( function( factory ) {
if ( typeof define === "function" && define.amd ) {

// AMD. Register as an anonymous module.
define( [
"jquery",
"ui/core"
], factory );
} else {

// Browser globals
factory( jQuery );
}
}( function( $ ) {

return $.ui.formResetMixin = {
_formResetHandler: function() {
var form = $( this );

// Wait for the form reset to actually happen before refreshing
setTimeout( function() {
var instances = form.data( "ui-form-reset-instances" );
$.each( instances, function() {
this.refresh();
} );
} );
},

_bindFormResetHandler: function() {
this.form = this.element.form();
if ( !this.form.length ) {
return;
}

var instances = this.form.data( "ui-form-reset-instances" ) || [];
if ( !instances.length ) {

// We don't use _on() here because we use a single event handler per form
this.form.on( "reset.ui-form-reset", this._formResetHandler );
}
instances.push( this );
this.form.data( "ui-form-reset-instances", instances );
},

_unbindFormResetHandler: function() {
if ( !this.form.length ) {
return;
}

var instances = this.form.data( "ui-form-reset-instances" );
instances.splice( $.inArray( this, instances ), 1 );
if ( instances.length ) {
this.form.data( "ui-form-reset-instances", instances );
} else {
this.form
.removeData( "ui-form-reset-instances" )
.off( "reset.ui-form-reset" );
}
}
};

} ) );
9 changes: 6 additions & 3 deletions ui/selectmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"./core",
"./widget",
"./position",
"./menu"
"./menu",
"./form-reset-mixin"
], factory );
} else {

Expand All @@ -34,7 +35,7 @@
}
}( function( $ ) {

return $.widget( "ui.selectmenu", {
return $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
version: "@VERSION",
defaultElement: "<select>",
options: {
Expand Down Expand Up @@ -72,6 +73,7 @@ return $.widget( "ui.selectmenu", {

this._drawButton();
this._drawMenu();
this._bindFormResetHandler();

this._rendered = false;
this.menuItems = $();
Expand Down Expand Up @@ -673,7 +675,8 @@ return $.widget( "ui.selectmenu", {
this.element.show();
this.element.removeUniqueId();
this.labels.attr( "for", this.ids.element );
this._unbindFormResetHandler();
}
} );
} ] );

} ) );
4 changes: 4 additions & 0 deletions ui/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ $.widget = function( name, base, prototype ) {
base = $.Widget;
}

if ( $.isArray( prototype ) ) {
prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
}

// create selector for plugin
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
return !!$.data( elem, fullName );
Expand Down