kounderscore
Version:
Knockout Underscore integration.
212 lines (169 loc) • 8.74 kB
text/typescript
(function (root, factory: (exports: KnockoutUnderscore, ko: KnockoutStatic, _: UnderscoreStatic) => void) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["exports", "knockout", "underscore"], factory);
} else if (typeof exports === "object") {
// CommonJS
factory(exports, require("knockout"), require("underscore"));
} else {
// Browser globals
root.ko_ = {};
factory(root.ko_, root.ko, root._);
}
} (this, function (exports, ko, _) {
//#region UndescoreJS Extension
var p = Array.prototype;
_.mixin({
sum: function <T>(list: _.List<T>, iterator: _.ListIterator<T, number>, context?: any): number {
/// <summary>Sum each item of given array by using specified iterator function</summary>
/// <param name="list" type="Array">Array to sum in</param>
/// <param name="iterator" type="Function">Function which return operand for sum</param>
/// <param name="context" type="Object" optional="true">Context to bind iterator function</param>
/// <returns type="Number">Sum of result obtained by iterator method against each array element</returns>
var result = 0;
_.each(list, () => {
result += iterator.apply(context, arguments);
});
return result;
},
average: function <T>(list: _.List<T>, iterator: _.ListIterator<T, number>, context?: any): number {
/// <summary>Create average from each item of given array by using specified iterator function</summary>
/// <param name="list" type="Array">Array to average items</param>
/// <param name="iterator" type="Function">Function which return operand for average</param>
/// <param name="context" type="Object" optional="true">Context to bind iterator function</param>
/// <returns type="Number">Average of result obtained by iterator method against each array element</returns>
if (list.length === 0) {
return 0;
}
return _.sum(list, iterator, context) / list.length;
},
count: function <T>(list: _.List<T>, iterator?: _.ListIterator<T, boolean>, context?: any): number {
/// <summary>Count items in given list filtered by given iterator function</summary>
/// <param name="list" type="Array">Array to count items</param>
/// <param name="iterator" type="Function">Function which filter array items</param>
/// <param name="context" type="Object" optional="true">Context to bind iterator function</param>
/// <returns type="Number">Items count</returns>
if (!iterator) {
return _.size(list);
}
return _.filter(list, iterator, context).length;
},
filterMap: function <T, TResult>(list: _.List<T>, iterator: _.ListIterator<T, TResult>, context?: any): TResult[] {
/// <summary>Select is a mapping and filtering function, iterator can map or return false or undefined to filter items</summary>
/// <param name="list" type="Array">Array to select items</param>
/// <param name="iterator" type="Function">Function which filter and map items</param>
/// <param name="context" type="Object" optional="true">Context to bind iterator function</param>
/// <returns type="Array">Array of mapped and filtered items</returns>
var result = [];
_.each(list, () => {
var item = iterator.apply(context, arguments);
if (item) {
result.push(item);
}
});
return result;
},
index: function <T>(list: _.List<T>, iterator?: _.ListIterator<T, boolean>, context?: any): number {
/// <summary>Get index of first item with which iterator function return true</summary>
/// <param name="list" type="Array">Array to search</param>
/// <param name="iterator" type="Function">Function which filter items by returning true or false</param>
/// <param name="context" type="Object" optional="true">Context to bind iterator function</param>
/// <returns type="Number">Index of first element filtered by iterator methods</returns>
var result = -1;
_.find(list, (value, index) => {
if (iterator.apply(context, arguments) === true) {
result = index;
return true;
}
return false;
});
return result;
},
partialEnd: function (func: Function, ...args: any[]): Function {
return function () {
return func.apply(this, p.slice.call(arguments).concat(args));
};
}
});
//#endregion
//#region UnderscoreJS wrapping for Knockout
function createSimpleFunction(method: string, check?: boolean): () => any {
return function () {
var value = this();
if (check && !_.isArray(value)) {
value = _.values(value);
}
p.unshift.call(arguments, value);
return _[method].apply(_, arguments);
};
}
function createComputedFunction<T>(method: string, pure?: boolean, extend?: boolean): () => KnockoutComputed<T> {
return function () {
var args = arguments;
var result = ko.computed({
read: function () { return this[method].apply(this, args); },
pure: pure || false,
owner: this
});
if (extend) {
result = result.extend({ underscore: "collection" });
}
return result;
};
}
exports.objects = (function () {
var obj: any = {};
_.each(["keys", "values"], method => {
obj[method] = createSimpleFunction(method);
obj["_" + method] = createComputedFunction(method, true, true);
obj["__" + method] = createComputedFunction(method, false, true);
});
_.each(["clone", "isEmpty"], method => {
obj[method] = createSimpleFunction(method);
obj["_" + method] = createComputedFunction(method, true);
obj["__" + method] = createComputedFunction(method, false);
});
return obj;
})();
exports.collections = (function () {
var obj: any = {};
_.each(["map", "filterMap", "filter", "reject", "sortBy", "toArray"], method => {
obj[method] = createSimpleFunction(method);
obj["_" + method] = createComputedFunction(method, true, true);
obj["__" + method] = createComputedFunction(method, false, true);
});
_.each(["each", "reduce", "find", "sum", "average", "all", "any", "contains", "min", "max", "groupBy", "count", "index", "size"], method => {
obj[method] = createSimpleFunction(method);
obj["_" + method] = createComputedFunction(method, true);
obj["__" + method] = createComputedFunction(method, false);
});
_.each(["initial", "rest", "compact", "flatten", "without", "union", "intersection", "difference", "uniq"], method => {
obj[method] = createSimpleFunction(method, true);
obj["_" + method] = createComputedFunction(method, true, true);
obj["__" + method] = createComputedFunction(method, false, true);
});
_.each(["first", "last", "zip", "indexOf", "lastIndexOf"], method => {
obj[method] = createSimpleFunction(method, true);
obj["_" + method] = createComputedFunction(method, true);
obj["__" + method] = createComputedFunction(method, false);
});
return obj;
})();
//#endregion
//#region UnderscoreJS integration with KnockoutJS
function addTo(val: any, mode?: string): void {
if (mode === "object") {
ko.utils.extend(val, exports.objects);
}
ko.utils.extend(val, exports.collections);
}
exports.addTo = addTo;
addTo(ko.observableArray.fn);
//#endregion
//#region Extender
ko.extenders.underscore = function (target: any, mode: string): any {
addTo(target, mode);
return target;
};
//#endregion
}));