Skip to content

Commit

Permalink
Merge branch 'release-2.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
gvas committed Dec 23, 2014
2 parents 2ff3bcc + 8586cb8 commit d918e4f
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 55 deletions.
4 changes: 2 additions & 2 deletions MIT-LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### The MIT License

Copyright (c) 2012 Ben Tadiar
Copyright (c) 2012, 2014 Vas Gábor

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Expand All @@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 change: 1 addition & 0 deletions grunt/saucelabs-jasmine.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ module.exports = function (grunt, options) {
browsers: browsers,
tunneled: false,
maxRetries: 1,
maxPollRetries: 5,
onTestComplete: tagJob,
sauceConfig: {
'video-upload-on-pass': false,
Expand Down
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "knockout-jqueryui",
"description": "knockout binding handlers for jQuery UI",
"homepage": "https://github.com/gvas/knockout-jqueryui",
"version": "2.1.0",
"version": "2.2.0",
"author": {
"name": "Vas Gabor <[email protected]>"
},
Expand All @@ -17,20 +17,20 @@
"license": "MIT",
"dependencies": {},
"devDependencies": {
"change-case": "~2.1.1",
"grunt": "~0.4.0",
"grunt-cli": "~0.1.6",
"grunt-contrib-compress": "~0.10.0",
"change-case": "~2.1.6",
"grunt": "~0.4.5",
"grunt-cli": "~0.1.13",
"grunt-contrib-compress": "~0.12.0",
"grunt-contrib-concat": "~0.5.0",
"grunt-contrib-connect": "~0.8.0",
"grunt-contrib-connect": "~0.9.0",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-uglify": "~0.5.0",
"grunt-contrib-uglify": "~0.6.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-sauce-tunnel": "~0.2.1",
"grunt-saucelabs": "~8.2.1",
"load-grunt-config": "~0.13.0",
"q": "~1.0.1",
"request": "~2.40.0"
"grunt-saucelabs": "~8.4.1",
"load-grunt-config": "~0.16.0",
"q": "~1.1.2",
"request": "~2.51.0"
},
"scripts": {
"test": "grunt test"
Expand Down
35 changes: 33 additions & 2 deletions spec/bindingHandler.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'use strict';

describe('The binding handler', function () {
var createBindingHandler, $element;
var createBindingHandler, $element, match;

afterEach(function () {
$element.remove();
Expand Down Expand Up @@ -58,6 +58,37 @@
delete ko.bindingHandlers.descendantBindingHandler;
});

it('should not throw any exception when a foreach binding is applied to the same element', function () {

var $element = $('<div data-bind="foreach: [], test: {}"></div>').prependTo('body');

$.fn.test = function () { };

createBindingHandler();

ko.applyBindings({}, $element[0]);
});

match = ko.version.match(/^(\d)\.(\d+)/);
if (match && parseInt(match[1], 10) >= 3) {
it('should instantiate the widget after the standard foreach binding is processed', function () {

var $element;

$element = $('<div data-bind="test: {}, foreach: []"></div>').prependTo('body');

spyOn(ko.bindingHandlers.foreach, 'init').andCallThrough();

$.fn.test = function () {
expect(ko.bindingHandlers.foreach.init).toHaveBeenCalled();
};

createBindingHandler();

ko.applyBindings({}, $element[0]);
});
}

it('should set the options specified in the binding on the widget', function () {
var vm;

Expand Down Expand Up @@ -235,4 +266,4 @@
expect($.fn.test).toHaveBeenCalledWith('destroy');
});
});
}());
} ());
29 changes: 29 additions & 0 deletions spec/selectmenu.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,34 @@

ko.removeNode($element[0]);
});

it('should synchronize with knockout\'s value binding', function () {
var $element, vm, autoOpen;

$element = $([
'<select data-bind="value: valueObservable, selectmenu: {}">',
' <option value="1" selected="selected">One</option>',
' <option value="2">Two</option>',
'</select>'
].join('')).prependTo('body');
vm = { valueObservable: ko.observable() };
ko.applyBindings(vm, $element[0]);

expect(vm.valueObservable()).toBe('1');

// selectmenu -> value
$('.ui-selectmenu-button').click();
$('.ui-selectmenu-menu .ui-menu-item:nth-child(2)').trigger('mouseenter');
$('.ui-selectmenu-menu .ui-menu-item:nth-child(2)').click();

expect(vm.valueObservable()).toBe('2');

// value -> selectmenu
vm.valueObservable('1');

expect($('.ui-selectmenu-text').text()).toBe('One');

ko.removeNode($element[0]);
});
});
}());
7 changes: 3 additions & 4 deletions src/accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,20 @@ define(
/// <param name='valueAccessor' type='Function'></param>
/// <returns type='Object'></returns>

var widgetName, value;
var widgetName, value, result;

widgetName = this.widgetName;
value = valueAccessor();

BindingHandler.prototype.init.apply(this, arguments);
result = BindingHandler.prototype.init.apply(this, arguments);

if (ko.isWriteableObservable(value.active)) {
this.on(element, this.eventToWatch, function () {
value.active($(element)[widgetName]('option', 'active'));
});
}

// the inner elements have already been taken care of
return { controlsDescendantBindings: true };
return result;
};

utils.register(Accordion);
Expand Down
27 changes: 21 additions & 6 deletions src/bindingHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ define(
[
'jquery',
'knockout',
'./utils',
'jquery-ui/widget'
],

function ($, ko) {
function ($, ko, utils) {

'use strict';

Expand Down Expand Up @@ -59,22 +60,37 @@ define(
this.widgetEventPrefix = widgetName;
this.options = [];
this.events = [];
this.after = [];
this.hasRefresh = false;
};

/*jslint unparam:true*/
BindingHandler.prototype.init = function (element, valueAccessor,
allBindingsAccessor, viewModel, bindingContext) {

var widgetName, value, unwrappedOptions, unwrappedEvents;
var widgetName, value, unwrappedOptions, unwrappedEvents,
shouldApplyBindingsToDescendants;

widgetName = this.widgetName;
value = valueAccessor();
unwrappedOptions = filterAndUnwrapProperties(value, this.options);
unwrappedEvents = filterAndUnwrapProperties(value, this.events);

// allow inner elements' bindings to finish before initializing the widget
ko.applyBindingsToDescendants(bindingContext, element);
// There can be control flow- or other bindings on some of the descendant
// elements which affect the shape of the element-rooted DOM subtree. These
// should be processed before instantiating the jQuery UI widget, because they
// can add pages to the tabs widget, menu items to the menu widget, etc.
shouldApplyBindingsToDescendants = !ko.utils.arrayFirst(
utils.descendantControllingBindings,
function (bindingName) {
return this.hasOwnProperty(bindingName);
},
allBindingsAccessor()
);
if (shouldApplyBindingsToDescendants) {
// process descendant bindings
ko.applyBindingsToDescendants(bindingContext, element);
}

// store the options' values so they can be checked for changes in the
// update() method
Expand Down Expand Up @@ -102,8 +118,7 @@ define(
$(element)[widgetName]('destroy');
});

// the inner elements have already been taken care of
return { controlsDescendantBindings: true };
return { controlsDescendantBindings: shouldApplyBindingsToDescendants };
};
/*jslint unparam:false*/

Expand Down
7 changes: 3 additions & 4 deletions src/datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ define(
/// <param name='valueAccessor' type='Function'></param>
/// <returns type='Object'></returns>

var widgetName, options, value, subscription, origOnSelect;
var result, widgetName, options, value, subscription, origOnSelect;

BindingHandler.prototype.init.apply(this, arguments);
result = BindingHandler.prototype.init.apply(this, arguments);

widgetName = this.widgetName;
options = valueAccessor();
Expand Down Expand Up @@ -80,8 +80,7 @@ define(
});
}

// the inner elements have already been taken care of
return { controlsDescendantBindings: true };
return result;
};

utils.register(Datepicker);
Expand Down
7 changes: 3 additions & 4 deletions src/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ define(
/// <param name='valueAccessor' type='Function'></param>
/// <returns type='Object'></returns>

var marker, value;
var marker, result, value;

/// sets up the correct disposal
marker = document.createElement('DIV');
Expand All @@ -67,7 +67,7 @@ define(
});

/// invokes the prototype's init() method
BindingHandler.prototype.init.apply(this, arguments);
result = BindingHandler.prototype.init.apply(this, arguments);

/// sets up handling of the isOpen option
value = valueAccessor();
Expand Down Expand Up @@ -112,8 +112,7 @@ define(
/*jslint unparam:false*/
}

// the inner elements have already been taken care of
return { controlsDescendantBindings: true };
return result;
};

utils.register(Dialog);
Expand Down
34 changes: 28 additions & 6 deletions src/selectmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ define(

BindingHandler.call(this, 'selectmenu');

this.after = ['value'];
this.options = ['appendTo', 'disabled', 'icons', 'position', 'width'];
this.events = ['change', 'close', 'create', 'focus', 'open', 'select'];
this.hasRefresh = true;
Expand All @@ -26,19 +27,24 @@ define(
Selectmenu.prototype = utils.createObject(BindingHandler.prototype);
Selectmenu.prototype.constructor = Selectmenu;

Selectmenu.prototype.init = function (element, valueAccessor) {
Selectmenu.prototype.init = function (element, valueAccessor,
allBindingsAccessor) {
/// <summary>Connects the view model and the widget via the isOpen property.
// </summary>
/// <param name='element' type='DOMNode'></param>
/// <param name='valueAccessor' type='Function'></param>
/// <param name='allBindingsAccessor' type='Object'></param>
/// <returns type='Object'></returns>

var value = valueAccessor();
var value, result;

value = valueAccessor();

/// invokes the prototype's init() method
BindingHandler.prototype.init.apply(this, arguments);
result = BindingHandler.prototype.init.apply(this, arguments);

if (value.isOpen) {
// maintain the isOpen option
if (value.hasOwnProperty('isOpen')) {
ko.computed({
read: function () {
if (ko.utils.unwrapObservable(value.isOpen)) {
Expand All @@ -60,8 +66,24 @@ define(
});
}

// the inner elements have already been taken care of
return { controlsDescendantBindings: true };
// synchronize the selected option with knockout's standard value binding
if (allBindingsAccessor().hasOwnProperty('value')) {
ko.computed({
read: function () {
ko.utils.unwrapObservable(allBindingsAccessor().value);
$(element).selectmenu('refresh');
},
disposeWhenNodeIsRemoved: element
});
}

// Notify knockout's value- and selectedOptions bindings that the selected
// option has been changed.
this.on(element, 'change', function () {
$(element).trigger('change');
});

return result;
};

utils.register(Selectmenu);
Expand Down
7 changes: 3 additions & 4 deletions src/slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ define(
/// <param name='element' type='DOMNode'></param>
/// <param name='valueAccessor' type='Function'></param>

var value, changeEvent;
var result, value, changeEvent;

BindingHandler.prototype.init.apply(this, arguments);
result = BindingHandler.prototype.init.apply(this, arguments);

value = valueAccessor();
changeEvent = value.realtime ? 'slide' : 'change';
Expand Down Expand Up @@ -73,8 +73,7 @@ define(
/*jslint unparam:false*/
}

// the inner elements have already been taken care of
return { controlsDescendantBindings: true };
return result;
};

utils.register(Slider);
Expand Down
7 changes: 3 additions & 4 deletions src/spinner.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ define(
/// <param name='valueAccessor' type='Function'></param>
/// <param name='allBindingsAccessor' type='Function'></param>

var widgetName, value;
var result, widgetName, value;

BindingHandler.prototype.init.apply(this, arguments);
result = BindingHandler.prototype.init.apply(this, arguments);

widgetName = this.widgetName;
value = valueAccessor();
Expand Down Expand Up @@ -78,8 +78,7 @@ define(
}
}

// the inner elements have already been taken care of
return { controlsDescendantBindings: true };
return result;
};

utils.register(Spinner);
Expand Down
Loading

0 comments on commit d918e4f

Please sign in to comment.