Skip to content

Commit 8e42e99

Browse files
committed
Fix #8 - version 0.3.0 - call passed in select/change handlers. Upgrade Jasmine to 2.x code.
1 parent 2d4f3d7 commit 8e42e99

File tree

12 files changed

+2782
-2932
lines changed

12 files changed

+2782
-2932
lines changed

Gruntfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ module.exports = function(grunt) {
3535
options : {
3636
specs : "spec/*.js",
3737
vendor: [
38-
"bower_components/jquery/jquery.min.js",
38+
"bower_components/jquery/dist/jquery.min.js",
3939
"bower_components/jqueryui/ui/jquery-ui.js",
4040
"bower_components/knockout.js/knockout.js"
4141
],

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "knockout-jqAutocomplete",
3-
"version": "0.2.1",
3+
"version": "0.3.0",
44
"main": "build/knockout-jqAutocomplete.min.js",
55
"ignore": [
66
"examples",

build/knockout-jqAutocomplete.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// knockout-jqAutocomplete 0.2.1 | (c) 2013 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
1+
// knockout-jqAutocomplete 0.3.0 | (c) 2014 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
22
;(function(factory) {
33
if (typeof define === "function" && define.amd) {
44
// AMD anonymous module
@@ -14,7 +14,8 @@
1414

1515
//binding's init function
1616
this.init = function(element, valueAccessor, allBindings, data, context) {
17-
var options = unwrap(valueAccessor()),
17+
var existingSelect, existingChange,
18+
options = unwrap(valueAccessor()),
1819
config = {},
1920
filter = typeof options.filter === "function" ? options.filter : self.defaultFilter;
2021

@@ -40,6 +41,10 @@
4041
config.source = self.processOptions.bind(self, valueAccessor, filter, options.source);
4142
}
4243

44+
//save any passed in select/change calls
45+
existingSelect = typeof config.select === "function" && config.select;
46+
existingChange = typeof config.change === "function" && config.change;
47+
4348
//handle updating the actual value
4449
config.select = function(event, ui) {
4550
if (ui.item && ui.item.actual) {
@@ -49,6 +54,10 @@
4954
options.dataValue(ui.item.data);
5055
}
5156
}
57+
58+
if (existingSelect) {
59+
existingSelect.apply(this, arguments);
60+
}
5261
};
5362

5463
//user made a change without selecting a value from the list
@@ -60,6 +69,10 @@
6069
options.dataValue(null);
6170
}
6271
}
72+
73+
if (existingChange) {
74+
existingChange.apply(this, arguments);
75+
}
6376
};
6477

6578
//initialize the widget

build/knockout-jqAutocomplete.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "knockout-jqAutocomplete",
3-
"version": "0.2.1",
3+
"version": "0.3.0",
44
"devDependencies": {
55
"grunt": "~0.4.1",
66
"grunt-contrib-uglify": "0.x.x",

spec/knockout-jqAutocomplete.spec.js

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,13 @@ describe("knockout-jqAutocomplete", function(){
6767
it("should apply additional options passed in the binding", function() {
6868
instance.init(input, function() {
6969
return {
70-
delay: 1000
70+
options: {
71+
delay: 1000
72+
}
7173
};
7274
});
7375

74-
expect($input.autocomplete("option", "delay"), 1000);
76+
expect($input.autocomplete("option", "delay")).toEqual(1000);
7577
});
7678

7779
it("should apply global options", function() {
@@ -83,7 +85,7 @@ describe("knockout-jqAutocomplete", function(){
8385
return {};
8486
});
8587

86-
expect($input.autocomplete("option", "delay"), 2000);
88+
expect($input.autocomplete("option", "delay")).toEqual(2000);
8789
});
8890

8991
it("should override global options with local options", function() {
@@ -97,7 +99,7 @@ describe("knockout-jqAutocomplete", function(){
9799
};
98100
});
99101

100-
expect($input.autocomplete("option", "delay"), 2000);
102+
expect($input.autocomplete("option", "delay")).toEqual(2000);
101103
});
102104

103105
it("should destroy the widget when the node is removed by KO", function() {
@@ -198,7 +200,7 @@ describe("knockout-jqAutocomplete", function(){
198200

199201
instance.processOptions(valueAccessor, null, data, request, response);
200202

201-
responseData = response.mostRecentCall.args[0];
203+
responseData = response.calls.mostRecent().args[0];
202204

203205
expect(responseData.length).toEqual(3);
204206
expect(JSON.stringify(responseData[0])).toEqual('{"label":"one","value":"one","actual":"one","data":"one"}');
@@ -222,7 +224,7 @@ describe("knockout-jqAutocomplete", function(){
222224

223225
instance.processOptions(valueAccessor, instance.defaultFilter, data, request, response);
224226

225-
responseData = response.mostRecentCall.args[0];
227+
responseData = response.calls.mostRecent().args[0];
226228

227229
expect(responseData.length).toEqual(2);
228230
expect(JSON.stringify(responseData[0])).toEqual('{"label":"two","value":"two","actual":"two","data":"two"}');
@@ -245,7 +247,7 @@ describe("knockout-jqAutocomplete", function(){
245247

246248
instance.processOptions(valueAccessor, instance.defaultFilter, data, request, response);
247249

248-
responseData = response.mostRecentCall.args[0];
250+
responseData = response.calls.mostRecent().args[0];
249251

250252
expect(responseData.length).toEqual(2);
251253
expect(JSON.stringify(responseData[0])).toEqual('{"label":"two","value":"two","actual":"two","data":"two"}');
@@ -264,7 +266,7 @@ describe("knockout-jqAutocomplete", function(){
264266

265267
instance.processOptions(valueAccessor, instance.defaultFilter, data, request, response);
266268

267-
responseData = response.mostRecentCall.args[0];
269+
responseData = response.calls.mostRecent().args[0];
268270

269271
expect(responseData.length).toEqual(0);
270272
});
@@ -300,7 +302,7 @@ describe("knockout-jqAutocomplete", function(){
300302

301303
instance.processOptions(valueAccessor, null, data, request, response);
302304

303-
responseData = response.mostRecentCall.args[0];
305+
responseData = response.calls.mostRecent().args[0];
304306

305307
expect(responseData.length).toEqual(3);
306308
expect(responseData[0].label).toEqual("1-two");
@@ -872,5 +874,54 @@ describe("knockout-jqAutocomplete", function(){
872874

873875
expect(input.value).toEqual("updated");
874876
});
877+
878+
it("should call a passed in \"select\" function", function() {
879+
var $listItems,
880+
items = ["one", "two", "three"],
881+
value = ko.observable(),
882+
handler = jasmine.createSpy();
883+
884+
ko.applyBindingsToNode(input, {
885+
jqAuto: {
886+
value: value,
887+
source: items,
888+
options: {
889+
select: handler
890+
}
891+
}
892+
});
893+
894+
$input.autocomplete("search", "t");
895+
896+
$listItems = $("ul.ui-autocomplete li");
897+
898+
$listItems.first("a").click();
899+
900+
expect(handler.calls.count()).toEqual(1);
901+
expect(handler.calls.argsFor(0)[0].type).toEqual("autocompleteselect");
902+
expect("item" in handler.calls.argsFor(0)[1]).toBeTruthy();
903+
});
904+
905+
it("should call a passed in \"change\" function", function() {
906+
var items = [],
907+
value = ko.observable("testing"),
908+
handler = jasmine.createSpy();
909+
910+
ko.applyBindingsToNode(input, {
911+
jqAuto: {
912+
value: value,
913+
source: items,
914+
options: {
915+
change: handler
916+
}
917+
}
918+
});
919+
920+
$input.val("test").blur();
921+
922+
expect(handler.calls.count()).toEqual(1);
923+
expect(handler.calls.argsFor(0)[0].type).toEqual("autocompletechange");
924+
expect("item" in handler.calls.argsFor(0)[1]).toBeTruthy();
925+
});
875926
});
876927
});

spec/lib/boot.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
3+
4+
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
5+
6+
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
7+
8+
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
9+
*/
10+
11+
(function() {
12+
13+
/**
14+
* ## Require & Instantiate
15+
*
16+
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
17+
*/
18+
window.jasmine = jasmineRequire.core(jasmineRequire);
19+
20+
/**
21+
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
22+
*/
23+
jasmineRequire.html(jasmine);
24+
25+
/**
26+
* Create the Jasmine environment. This is used to run all specs in a project.
27+
*/
28+
var env = jasmine.getEnv();
29+
30+
/**
31+
* ## The Global Interface
32+
*
33+
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
34+
*/
35+
var jasmineInterface = jasmineRequire.interface(jasmine, env);
36+
37+
/**
38+
* Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
39+
*/
40+
if (typeof window == "undefined" && typeof exports == "object") {
41+
extend(exports, jasmineInterface);
42+
} else {
43+
extend(window, jasmineInterface);
44+
}
45+
46+
/**
47+
* ## Runner Parameters
48+
*
49+
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
50+
*/
51+
52+
var queryString = new jasmine.QueryString({
53+
getWindowLocation: function() { return window.location; }
54+
});
55+
56+
var catchingExceptions = queryString.getParam("catch");
57+
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
58+
59+
/**
60+
* ## Reporters
61+
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
62+
*/
63+
var htmlReporter = new jasmine.HtmlReporter({
64+
env: env,
65+
onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
66+
getContainer: function() { return document.body; },
67+
createElement: function() { return document.createElement.apply(document, arguments); },
68+
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
69+
timer: new jasmine.Timer()
70+
});
71+
72+
/**
73+
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
74+
*/
75+
env.addReporter(jasmineInterface.jsApiReporter);
76+
env.addReporter(htmlReporter);
77+
78+
/**
79+
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
80+
*/
81+
var specFilter = new jasmine.HtmlSpecFilter({
82+
filterString: function() { return queryString.getParam("spec"); }
83+
});
84+
85+
env.specFilter = function(spec) {
86+
return specFilter.matches(spec.getFullName());
87+
};
88+
89+
/**
90+
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
91+
*/
92+
window.setTimeout = window.setTimeout;
93+
window.setInterval = window.setInterval;
94+
window.clearTimeout = window.clearTimeout;
95+
window.clearInterval = window.clearInterval;
96+
97+
/**
98+
* ## Execution
99+
*
100+
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
101+
*/
102+
var currentWindowOnload = window.onload;
103+
104+
window.onload = function() {
105+
if (currentWindowOnload) {
106+
currentWindowOnload();
107+
}
108+
htmlReporter.initialize();
109+
env.execute();
110+
};
111+
112+
/**
113+
* Helper function for readability above.
114+
*/
115+
function extend(destination, source) {
116+
for (var property in source) destination[property] = source[property];
117+
return destination;
118+
}
119+
120+
}());

0 commit comments

Comments
 (0)