Skip to content

Commit

Permalink
Update to work with Knockout 3.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mbest committed Mar 6, 2015
1 parent 97db591 commit 1eb2362
Show file tree
Hide file tree
Showing 30 changed files with 1,649 additions and 442 deletions.
347 changes: 198 additions & 149 deletions knockout-deferred-updates.js

Large diffs are not rendered by default.

37 changes: 19 additions & 18 deletions knockout-deferred-updates.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "knockout-deferred-updates",
"description": "Deferred Updates plugin for Knockout",
"homepage": "http://mbest.github.io/knockout-deferred-updates/",
"version": "3.2.1",
"version": "3.3.0",
"license": "MIT",
"author": "Michael Best",
"main": "knockout-deferred-updates.js",
Expand All @@ -12,6 +12,6 @@
},
"bugs": "https://github.com/mbest/knockout-deferred-updates/issues",
"dependencies": {
"knockout": "~3.2 || ~3.1 || ~3.0 || ~2"
"knockout": "~3.3 || ~3.2 || ~3.1 || ~3.0 || ~2"
}
}
88 changes: 87 additions & 1 deletion spec/asyncBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,48 @@ describe('Rate-limited', function() {
jasmine.Clock.tick(500);
expect(notifySpy).not.toHaveBeenCalled();
});

it('Should delay update of dependent computed observable', function() {
var observable = ko.observable().extend({rateLimit:500});
var computed = ko.computed(observable);

// Check initial value
expect(computed()).toBeUndefined();

// Observable is changed, but computed is not
observable('a');
expect(observable()).toEqual('a');
expect(computed()).toBeUndefined();

// Second change also
observable('b');
expect(computed()).toBeUndefined();

// Advance clock; Change notification happens now using the latest value notified
jasmine.Clock.tick(500);
expect(computed()).toEqual('b');
});

it('Should delay update of dependent pure computed observable', function() {
var observable = ko.observable().extend({rateLimit:500});
var computed = ko.pureComputed(observable);

// Check initial value
expect(computed()).toBeUndefined();

// Observable is changed, but computed is not
observable('a');
expect(observable()).toEqual('a');
expect(computed()).toBeUndefined();

// Second change also
observable('b');
expect(computed()).toBeUndefined();

// Advance clock; Change notification happens now using the latest value notified
jasmine.Clock.tick(500);
expect(computed()).toEqual('b');
});
});

describe('Observable Array change tracking', function() {
Expand Down Expand Up @@ -367,7 +409,7 @@ describe('Rate-limited', function() {
});
});

describe('Dependent Observable', function() {
describe('Computed Observable', function() {
it('Should delay running evaluator where there are no subscribers', function() {
var observable = ko.observable();
var evalSpy = jasmine.createSpy('evalSpy');
Expand Down Expand Up @@ -534,6 +576,50 @@ describe('Rate-limited', function() {
observableSwitch(1);
expect(computed()).toEqual(2);
});

it('Should delay update of dependent computed observable', function() {
var observable = ko.observable();
var rateLimitComputed = ko.computed(observable).extend({rateLimit:500});
var dependentComputed = ko.computed(rateLimitComputed);

// Check initial value
expect(dependentComputed()).toBeUndefined();

// Rate-limited computed is changed, but dependent computed is not
observable('a');
expect(rateLimitComputed()).toEqual('a');
expect(dependentComputed()).toBeUndefined();

// Second change also
observable('b');
expect(dependentComputed()).toBeUndefined();

// Advance clock; Change notification happens now using the latest value notified
jasmine.Clock.tick(500);
expect(dependentComputed()).toEqual('b');
});

it('Should delay update of dependent pure computed observable', function() {
var observable = ko.observable();
var rateLimitComputed = ko.computed(observable).extend({rateLimit:500});
var dependentComputed = ko.pureComputed(rateLimitComputed);

// Check initial value
expect(dependentComputed()).toBeUndefined();

// Rate-limited computed is changed, but dependent computed is not
observable('a');
expect(rateLimitComputed()).toEqual('a');
expect(dependentComputed()).toBeUndefined();

// Second change also
observable('b');
expect(dependentComputed()).toBeUndefined();

// Advance clock; Change notification happens now using the latest value notified
jasmine.Clock.tick(500);
expect(dependentComputed()).toEqual('b');
});
});
});

Expand Down
94 changes: 53 additions & 41 deletions spec/bindingAttributeBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,47 +424,59 @@ describe('Binding attribute syntax', function() {
// Should not throw any errors
});

it('Should not bind against text content inside <script> tags', function() {
this.restoreAfter(ko.bindingProvider, 'instance');

// Developers won't expect or want binding to mutate the contents of <script> tags.
// Historically this wasn't a problem because the default binding provider only acts
// on elements, but now custom providers can act on text contents of elements, it's
// important to ensure we don't break <script> elements by mutating their contents.

// First replace the binding provider with one that's hardcoded to replace all text
// content with a special message, via a binding handler that operates on text nodes

var originalBindingProvider = ko.bindingProvider.instance;
ko.bindingProvider.instance = {
nodeHasBindings: function(node) {
// IE < 9 can't bind text nodes, as expando properties are not allowed on them
// this will still prove that the binding provider was not executed on the children of a script tag
if (node.nodeType === 3 && jasmine.ieVersion < 9) {
node.data = "replaced";
return false;
describe('Should not bind against text content inside restricted elements', function() {
this.beforeEach(function() {
this.restoreAfter(ko.bindingProvider, 'instance');

// Developers won't expect or want binding to mutate the contents of <script> or <textarea>
// elements. Historically this wasn't a problem because the default binding provider only
// acts on elements, but now custom providers can act on text contents of elements, it's
// important to ensure we don't break these elements by mutating their contents.

// First replace the binding provider with one that's hardcoded to replace all text
// content with a special message, via a binding handler that operates on text nodes

var originalBindingProvider = ko.bindingProvider.instance;
ko.bindingProvider.instance = {
nodeHasBindings: function(node) {
// IE < 9 can't bind text nodes, as expando properties are not allowed on them.
// This will still prove that the binding provider was not executed on the children of a restricted element.
if (node.nodeType === 3 && jasmine.ieVersion < 9) {
node.data = "replaced";
return false;
}

return true;
},
getBindingAccessors: function(node, bindingContext) {
if (node.nodeType === 3) {
return {
replaceTextNodeContent: function() { return "replaced"; }
};
} else {
return originalBindingProvider.getBindingAccessors(node, bindingContext);
}
}

return true;
},
getBindingAccessors: function(node, bindingContext) {
if (node.nodeType === 3) {
return {
replaceTextNodeContent: function() { return "replaced"; }
};
} else {
return originalBindingProvider.getBindingAccessors(node, bindingContext);
}
}
};
ko.bindingHandlers.replaceTextNodeContent = {
update: function(textNode, valueAccessor) { textNode.data = valueAccessor(); }
};

// Now check that the only text nodes whose contents are mutated are the ones
// *not* inside <script> tags.
testNode.innerHTML = "<p>Hello</p><script>alert(123);</script><p>Goodbye</p>";
ko.applyBindings({ sometext: 'hello' }, testNode);
expect(testNode).toContainHtml('<p>replaced</p><script>alert(123);</script><p>replaced</p>');
};
ko.bindingHandlers.replaceTextNodeContent = {
update: function(textNode, valueAccessor) { textNode.data = valueAccessor(); }
};
});


it('<script>', function() {
// Check that the only text nodes whose contents are mutated are the ones *not* inside <script> elements.
testNode.innerHTML = "<p>Hello</p><script>alert(123);</script><p>Goodbye</p>";
ko.applyBindings({ sometext: 'hello' }, testNode);
expect(testNode).toContainHtml('<p>replaced</p><script>alert(123);</script><p>replaced</p>');
});


it('<textarea>', function() {
// Check that the only text nodes whose contents are mutated are the ones *not* inside <textarea> elements.
testNode.innerHTML = "<p>Hello</p><textarea>test</textarea><p>Goodbye</p>";
ko.applyBindings({ sometext: 'hello' }, testNode);
expect(testNode).toContainHtml('<p>replaced</p><textarea>test</textarea><p>replaced</p>');
});
});
});
2 changes: 2 additions & 0 deletions spec/blank.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!doctype html>
<html><head></head><body></body></html>
Loading

0 comments on commit 1eb2362

Please sign in to comment.