Update Knockout definitons and file version + tests

This commit is contained in:
Boris Yankov
2012-10-25 22:07:42 +03:00
parent 50138dabc4
commit be38ab26f9
2 changed files with 626 additions and 52 deletions
+109 -52
View File
@@ -1,6 +1,12 @@
// Type definitions for Knockout 2.1.0
// Type definitions for Knockout 2.2
// Project: http://knockoutjs.com
// https://github.com/borisyankov/DefinitelyTyped
interface KnockoutSubscription {
dispose(): void;
}
interface KnockoutObservableArrayFunctions {
// General Array functions
indexOf(searchElement, fromIndex?: number): number;
@@ -26,23 +32,33 @@ interface KnockoutObservableArrayFunctions {
}
interface KnockoutObservableArray extends KnockoutObservableArrayFunctions {
(): any[];
(value: any[]): void;
}
interface KnockoutObservableArrayStatic {
(): KnockoutObservableArray;
fn: KnockoutObservableArrayFunctions;
(): KnockoutObservableArray;
(value: any[]): KnockoutObservableArray;
}
interface KnockoutObservable {
fn;
(): any;
(value): void;
subscribe(func: Function): void;
extend(source);
subscribe(func: Function): KnockoutSubscription;
}
interface KnockoutComputed extends KnockoutObservable {
(): KnockoutComputed;
(func: Function, context?: any): KnockoutComputed;
(def: KnockoutComputedDefine): KnockoutComputed;
(options?: any): KnockoutComputed;
subscribe(callback: (newValue: number) => void ): KnockoutSubscription;
getDependenciesCount(): number;
hasWriteFunction(): bool;
}
interface KnockoutComputedDefine {
@@ -50,12 +66,6 @@ interface KnockoutComputedDefine {
write(any);
}
interface KnockoutComputedStatic {
(): KnockoutComputed;
(func: Function): KnockoutComputed;
(def: KnockoutComputedDefine) : KnockoutComputed;
}
interface KnockoutBindingContext {
$parent: any;
$parents: any[];
@@ -72,55 +82,102 @@ interface KnockoutBindingHandler {
//update(element: any, valueAccessor: any, allBindingsAccessor: any, viewModel: any, bindingContext: KnockoutBindingContext) : void;
init: any;
update: any;
options: any;
}
interface KnockoutBindingHandlers {
value: KnockoutBindingHandler;
}
interface KnockoutStatic {
utils: KnockoutUtilsStatic;
bindingHandlers: KnockoutBindingHandlers;
applyBindings(viewModel, rootNode?);
computed : KnockoutComputedStatic;
observableArray: KnockoutObservableArrayStatic;
observable(intial?): KnockoutObservable;
interface KnockoutMemoization {
memoize(callback);
unmemoize(memoId, callbackParams);
unmemoizeDomNodeAndDescendants(domNode, extraCallbackParamsArray);
parseMemoText(memoText);
}
interface KnockoutUtilsStatic {
arrayForEach(array: any[], action);
arrayIndexOf(array: any[], item);
arrayFirst(array: any[], predicate, predicateOwner?);
arrayRemoveItem(array: any[], itemToRemove);
arrayGetDistinctValues(array: any[]);
arrayMap(array: any[], mapping);
arrayFilter(array: any[], predicate);
arrayPushAll(array: any[], valuesToPush);
interface KnockoutVirtualElements {
allowedBindings;
emptyNode;
firstChild;
insertAfter;
nextSibling;
prepend;
setDomNodeChildren;
}
interface KnockoutExtenders {
throttle(target: any, timeout: number): KnockoutComputed;
notify(target: any, notifyWhen: string): any;
}
interface KnockoutUtils {
fieldsIncludedWithJsonPost: any[];
arrayForEach(array: any[], action: (any) => void ): void;
arrayIndexOf(array: any[], item: any): number;
arrayFirst(array: any[], predicate: (item) => bool, predicateOwner?: any): any;
arrayRemoveItem(array: any[], itemToRemove: any): void;
arrayGetDistinctValues(array: any[]): any[];
arrayMap(array: any[], mapping: (item) => any): any[];
arrayFilter(array: any[], predicate: (item) => bool): any[];
arrayPushAll(array: any[], valuesToPush: any[]): any[];
extend(target, source);
emptyDomNode(domNode);
moveCleanedNodesToContainerElement(nodes);
setDomNodeChildren(domNode, childNodes);
replaceDomNodes(nodeToReplaceOrNodeArray, newNodesArray);
setOptionNodeSelectionState(optionNode, isSelected);
stringTrim(str: string);
stringTokenize(str: string, delimiter);
stringStartsWith(str: string, startsWith);
buildEvalWithinScopeFunction(expression, scopeLevels);
domNodeIsContainedBy(node, containedByNode);
domNodeIsAttachedToDocument(node);
tagNameLower(element);
registerEventHandler(element, eventType, handler);
triggerEvent(element, eventType);
unwrapObservable(value);
toggleDomNodeCssClass(node, className, shouldHaveClass);
setTextContent(element, textContent);
emptyDomNode(domNode): void;
moveCleanedNodesToContainerElement(nodes: any[]): HTMLElement;
cloneNodes(nodesArray: any[], shouldCleanNodes: bool): any[];
setDomNodeChildren(domNode: any, childNodes: any[]): void;
replaceDomNodes(nodeToReplaceOrNodeArray: any, newNodesArray: any[]): void;
setOptionNodeSelectionState(optionNode: any, isSelected: bool): void;
stringTrim(str: string): string;
stringTokenize(str: string, delimiter: string): string;
stringStartsWith(str: string, startsWith: string): string;
domNodeIsContainedBy(node: any, containedByNode: any): bool;
domNodeIsAttachedToDocument(node: any): bool;
tagNameLower(element: any): string;
registerEventHandler(element: any, eventType: any, handler: Function): void;
triggerEvent(element: any, eventType: any): void;
unwrapObservable(value: any): any;
toggleDomNodeCssClass(node: any, className: string, shouldHaveClass: bool): void;
setTextContent(element: any, textContent: string): void;
setElementName(element: any, name: string): void;
ensureSelectElementIsRenderedCorrectly(selectElement);
range(min, max);
makeArray(arrayLikeObject);
getFormFields(form, fieldName);
parseJson(jsonString);
stringifyJson(data, replacer, space);
postJson(urlOrForm, data, options);
forceRefresh(node: any): void;
ensureSelectElementIsRenderedCorrectly(selectElement: any): void;
range(min: any, max: any): any;
makeArray(arrayLikeObject: any): any[];
getFormFields(form: any, fieldName: string): any[];
parseJson(jsonString: string): any;
stringifyJson(data: any, replacer: Function, space: string): string;
postJson(urlOrForm: any, data: any, options: any): void;
domNodeDisposal;
}
interface KnockoutStatic {
utils: KnockoutUtils;
memoization: KnockoutMemoization;
bindingHandlers: KnockoutBindingHandlers;
computed: KnockoutComputed;
observableArray: KnockoutObservableArray;
virtualElements: KnockoutVirtualElements;
extenders: KnockoutExtenders;
applyBindings(viewModel: any, rootNode?: any): void;
applyBindingsToDescendants(viewModel: any, rootNode: any): void;
observable(intial? ): KnockoutObservable;
contextFor(node: any): any;
isSubscribable(instance: any): bool;
subscribable(): void;
toJSON(viewModel: any, replacer?: Function, space?: any): string;
toJS(viewModel: any): any;
isObservable(instance: any): bool;
dataFor(node: any): any;
}
declare var ko: KnockoutStatic;
+517
View File
@@ -0,0 +1,517 @@
/// <reference path="../Definitions/knockout-2.2.d.ts" />
/// <reference path="../Definitions/knockoutmapping-2.0.d.ts" />
declare var $;
function test_creatingVMs() {
var myViewModel = {
personName: ko.observable('Bob'),
personAge: ko.observable(123)
};
ko.applyBindings(myViewModel);
ko.applyBindings(myViewModel, document.getElementById('someElementId'));
myViewModel.personName();
myViewModel.personName('Mary');
myViewModel.personName('Mary').personAge(50);
myViewModel.personName.subscribe(function (newValue) {
alert("The person's new name is " + newValue);
});
var subscription = myViewModel.personName.subscribe(function (newValue) { });
subscription.dispose();
}
function test_computed() {
function AppViewModel() {
var self = this;
self.firstName = ko.observable('Bob');
self.lastName = ko.observable('Smith');
self.fullName = ko.computed(function () {
return self.firstName() + " " + self.lastName();
});
}
function MyViewModel() {
this.firstName = ko.observable('Planet');
this.lastName = ko.observable('Earth');
this.fullName = ko.computed({
read: function () {
return this.firstName() + " " + this.lastName();
},
write: function (value) {
var lastSpacePos = value.lastIndexOf(" ");
if (lastSpacePos > 0) {
this.firstName(value.substring(0, lastSpacePos));
this.lastName(value.substring(lastSpacePos + 1));
}
},
owner: this
});
}
function MyViewModel() {
this.price = ko.observable(25.99);
this.formattedPrice = ko.computed({
read: function () {
return '$' + this.price().toFixed(2);
},
write: function (value) {
value = parseFloat(value.replace(/[^\.\d]/g, ""));
this.price(isNaN(value) ? 0 : value);
},
owner: this
});
}
function MyViewModel() {
this.acceptedNumericValue = ko.observable(123);
this.lastInputWasValid = ko.observable(true);
this.attemptedValue = ko.computed({
read: this.acceptedNumericValue,
write: function (value) {
if (isNaN(value))
this.lastInputWasValid(false);
else {
this.lastInputWasValid(true);
this.acceptedNumericValue(value);
}
},
owner: this
});
}
ko.applyBindings(new MyViewModel());
}
function test_observableArrays() {
var myObservableArray = ko.observableArray();
myObservableArray.push('Some value');
var anotherObservableArray = ko.observableArray([
{ name: "Bungle", type: "Bear" },
{ name: "George", type: "Hippo" },
{ name: "Zippy", type: "Unknown" }
]);
myObservableArray().length;
myObservableArray()[0];
myObservableArray.indexOf('Blah');
myObservableArray.push('Some new value');
myObservableArray.pop();
myObservableArray.unshift('Some new value');
myObservableArray.shift();
myObservableArray.reverse();
myObservableArray.sort(function (left, right) { return left.lastName == right.lastName ? 0 : (left.lastName < right.lastName ? -1 : 1) });
myObservableArray.splice(1, 3);
var someItem: KnockoutObservableArray;
myObservableArray.remove(someItem);
myObservableArray.remove(function (item) { return item.age < 18 });
myObservableArray.removeAll(['Chad', 132, undefined]);
myObservableArray.removeAll();
myObservableArray.destroy(someItem);
myObservableArray.destroy(function (someItem) { return someItem.age < 18 });
myObservableArray.destroyAll(['Chad', 132, undefined]);
myObservableArray.destroyAll();
}
function test_bindings() {
var currentProfit = ko.observable(150000);
ko.applyBindings({
people: [
{ firstName: 'Bert', lastName: 'Bertington' },
{ firstName: 'Charles', lastName: 'Charlesforth' },
{ firstName: 'Denise', lastName: 'Dentiste' }
]
});
var viewModel = { availableCountries: ko.observableArray(['France', 'Germany', 'Spain']) };
viewModel.availableCountries.push('China');
ko.bindingHandlers.yourBindingName = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
}
};
ko.bindingHandlers.slideVisible = {
update: function (element, valueAccessor, allBindingsAccessor) {
var value = valueAccessor(), allBindings = allBindingsAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);
var duration = allBindings.slideDuration || 400;
if (valueUnwrapped == true)
$(element).slideDown(duration);
else
$(element).slideUp(duration);
},
init: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
$(element).toggle(value);
},
update: function (element, valueAccessor, allBindingsAccessor) {
}
};
ko.bindingHandlers.hasFocus = {
init: function (element, valueAccessor) {
$(element).focus(function () {
var value = valueAccessor();
value(true);
});
$(element).blur(function () {
var value = valueAccessor();
value(false);
});
},
update: function (element, valueAccessor) {
var value = valueAccessor();
if (ko.utils.unwrapObservable(value))
element.focus();
else
element.blur();
}
};
ko.bindingHandlers.allowBindings = {
init: function (elem, valueAccessor) {
var shouldAllowBindings = ko.utils.unwrapObservable(valueAccessor());
return { controlsDescendantBindings: !shouldAllowBindings };
}
};
ko.bindingHandlers.withProperties = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var newProperties = valueAccessor(),
innerBindingContext = bindingContext.extend(newProperties);
ko.applyBindingsToDescendants(innerBindingContext, element);
return { controlsDescendantBindings: true };
}
};
ko.bindingHandlers.withProperties = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var newProperties = valueAccessor(),
childBindingContext = bindingContext.createChildContext(viewModel);
ko.utils.extend(childBindingContext, newProperties);
ko.applyBindingsToDescendants(childBindingContext, element);
return { controlsDescendantBindings: true };
}
};
ko.bindingHandlers.randomOrder = {
init: function (elem, valueAccessor) {
var child = ko.virtualElements.firstChild(elem),
childElems = [];
while (child) {
childElems.push(child);
child = ko.virtualElements.nextSibling(child);
}
ko.virtualElements.emptyNode(elem);
while (childElems.length) {
var randomIndex = Math.floor(Math.random() * childElems.length),
chosenChild = childElems.splice(randomIndex, 1);
ko.virtualElements.prepend(elem, chosenChild[0]);
}
}
};
var node, containerElem, nodeToInsert, insertAfter, nodeToPrepend, arrayOfNodes;
ko.virtualElements.allowedBindings.mySuperBinding = true;
ko.virtualElements.emptyNode(containerElem);
ko.virtualElements.firstChild(containerElem);
ko.virtualElements.insertAfter(containerElem, nodeToInsert, insertAfter);
ko.virtualElements.nextSibling(node);
ko.virtualElements.prepend(containerElem, nodeToPrepend);
ko.virtualElements.setDomNodeChildren(containerElem, arrayOfNodes);
}
function test_more() {
var viewModel = {
firstName: ko.observable("Bert"),
lastName: ko.observable("Smith"),
pets: ko.observableArray(["Cat", "Dog", "Fish"]),
type: "Customer",
hasALotOfPets: any
};
viewModel.hasALotOfPets = ko.computed(function () {
return this.pets().length > 2
}, viewModel);
var plainJs = ko.toJS(viewModel);
ko.extenders.logChange = function (target, option) {
target.subscribe(function (newValue) {
console.log(option + ": " + newValue);
});
return target;
};
ko.extenders.numeric = function (target, precision) {
var result = ko.computed({
read: target,
write: function (newValue) {
var current = target(),
roundingMultiplier = Math.pow(10, precision),
newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
if (valueToWrite !== current) {
target(valueToWrite);
} else {
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
});
result(target());
return result;
};
function AppViewModel(one, two) {
this.myNumberOne = ko.observable(one).extend({ numeric: 0 });
this.myNumberTwo = ko.observable(two).extend({ numeric: 2 });
}
ko.applyBindings(new AppViewModel(221.2234, 123.4525));
ko.extenders.required = function (target, overrideMessage) {
target.hasError = ko.observable();
target.validationMessage = ko.observable();
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
}
validate(target());
target.subscribe(validate);
return target;
};
function AppViewModel(first, last) {
this.firstName = ko.observable(first).extend({ required: "Please enter a first name" });
this.lastName = ko.observable(last).extend({ required: "" });
}
ko.applyBindings(new AppViewModel("Bob", "Smith"));
var first;
this.firstName = ko.observable(first).extend({ required: "Please enter a first name", logChange: "first name" });
var upperCaseName = ko.computed(function () {
return name().toUpperCase();
}).extend({ throttle: 500 });
function AppViewModel() {
this.instantaneousValue = ko.observable();
this.throttledValue = ko.computed(this.instantaneousValue)
.extend({ throttle: 400 });
this.loggedValues = ko.observableArray([]);
this.throttledValue.subscribe(function (val) {
if (val !== '')
this.loggedValues.push(val);
}, this);
}
function GridViewModel() {
this.pageSize = ko.observable(20);
this.pageIndex = ko.observable(1);
this.currentPageData = ko.observableArray();
ko.computed(function () {
var params = { page: this.pageIndex(), size: this.pageSize() };
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this);
}
this.setPageSize = function (newPageSize) {
this.pageSize(newPageSize);
this.pageIndex(1);
}
ko.computed(function () {
var params = { page: this.pageIndex(), size: this.pageSize() };
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this).extend({ throttle: 1 });
$(".remove").click(function () {
viewModel.items.remove(ko.dataFor(this));
});
$(".remove").live("click", function () {
viewModel.items.remove(ko.dataFor(this));
});
$("#people").delegate(".remove", "click", function () {
var context = ko.contextFor(this),
parentArray = context.$parent.people || context.$parent.children;
parentArray.remove(context.$data);
return false;
});
$("#people").delegate(".add", "click", function () {
var context = ko.contextFor(this),
childName = context.$data.name() + " child",
parentArray = context.$data.people || context.$data.children;
context.$root.addChild(childName, parentArray);
return false;
});
ko.observableArray.fn.filterByProperty = function (propName, matchValue) {
return ko.computed(function () {
var allItems = this(), matchingItems = [];
for (var i = 0; i < allItems.length; i++) {
var current = allItems[i];
if (ko.utils.unwrapObservable(current[propName]) === matchValue)
matchingItems.push(current);
}
return matchingItems;
}, this);
}
function Task(title, done) {
this.title = ko.observable(title);
this.done = ko.observable(done);
}
function AppViewModel() {
this.tasks = ko.observableArray([
new Task('Find new desktop background', true),
new Task('Put shiny stickers on laptop', false),
new Task('Request more reggae music in the office', true)
]);
this.doneTasks = this.tasks.filterByProperty("done", true);
}
ko.applyBindings(new AppViewModel());
this.doneTasks = ko.computed(function () {
var all = this.tasks(), done = [];
for (var i = 0; i < all.length; i++)
if (all[i].done())
done.push(all[i]);
return done;
}, this);
}
function test_mappingplugin() {
var viewModel = {
serverTime: ko.observable(),
numUsers: ko.observable()
}
var data = {
serverTime: '2010-01-07',
numUsers: 3
};
viewModel.serverTime(data.serverTime);
viewModel.numUsers(data.numUsers);
var viewModel = ko.mapping.fromJS(data);
ko.mapping.fromJS(data, viewModel);
var unmapped = ko.mapping.toJS(viewModel);
var viewModel = ko.mapping.fromJS(data);
ko.mapping.fromJS(data, viewModel);
var myChildModel = function (data) {
ko.mapping.fromJS(data, {}, this);
this.nameLength = ko.computed(function () {
return this.name().length;
}, this);
}
var oldOptions = ko.mapping.defaultOptions().include;
ko.mapping.defaultOptions().include = ["alwaysIncludeThis"];
var oldOptions = ko.mapping.defaultOptions().copy;
ko.mapping.defaultOptions().copy = ["alwaysCopyThis"];
var someObject;
ko.mapping.fromJS(data, {}, someObject);
ko.mapping.fromJS(data, {}, this);
var alice, aliceMappingOptions, bob, bobMappingOptions;
var viewModel = ko.mapping.fromJS(alice, aliceMappingOptions);
ko.mapping.fromJS(bob, bobMappingOptions, viewModel);
var obj;
var result = ko.mapping.fromJS(obj, {
key: function (item) {
return ko.utils.unwrapObservable(item.id);
}
});
result.mappedRemove({ id: 2 });
var newItem = result.mappedCreate({ id: 3 });
}
function test_misc() {
var postbox = new ko.subscribable();
postbox.subscribe(callback, target, topic);
postbox.subscribe(function (newValue) {
this.latestTopic(newValue);
}, vm, "mytopic");
postbox.notifySubscribers(value, "mytopic");
ko.subscribable.fn.publishOn = function (topic) {
this.subscribe(function (newValue) {
postbox.notifySubscribers(newValue, topic);
});
return this;
};
this.myObservable = ko.observable("myValue").publishOn("myTopic");
ko.subscribable.fn.subscribeTo = function (topic) {
postbox.subscribe(this, null, topic);
return this;
};
this.observableFromAnotherVM = ko.observable().subscribeTo("myTopic");
postbox.subscribe(function (newValue) {
this(newValue);
}, this, topic);
ko.bindingHandlers.isolatedOptions = {
init: function (element, valueAccessor) {
var args = arguments;
ko.computed({
read: function () {
ko.utils.unwrapObservable(valueAccessor());
ko.bindingHandlers.options.update.apply(this, args);
},
owner: this,
disposeWhenNodeIsRemoved: element
});
}
};
ko.subscribable.fn.publishOn = function (topic) {
this.subscribe(function (newValue) {
postbox.notifySubscribers(newValue, topic);
});
return this;
};
this.myObservable = ko.observable("myValue").publishOn("myTopic");
var x = ko.observableArray([1, 2, 3]);
var element;
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).datepicker("destroy");
});
}