/android applications/24 1 2016 .net server/server1/server1/Scripts/knockout-2.1.0.debug.js
JavaScript | 1138 lines | 907 code | 136 blank | 95 comment | 258 complexity | e83122301f60f44223ec8e23a44b2b83 MD5 | raw file
- // Knockout JavaScript library v2.1.0
- // (c) Steven Sanderson - http://knockoutjs.com/
- // License: MIT (http://www.opensource.org/licenses/mit-license.php)
- (function(window,document,navigator,undefined){
- var DEBUG=true;
- !function(factory) {
- // Support three module loading scenarios
- if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
- // [1] CommonJS/Node.js
- var target = module['exports'] || exports; // module.exports is for Node.js
- factory(target);
- } else if (typeof define === 'function' && define['amd']) {
- // [2] AMD anonymous module
- define(['exports'], factory);
- } else {
- // [3] No module loader (plain <script> tag) - put directly in global namespace
- factory(window['ko'] = {});
- }
- }(function(koExports){
- // Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
- // In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
- var ko = typeof koExports !== 'undefined' ? koExports : {};
- // Google Closure Compiler helpers (used only to make the minified file smaller)
- ko.exportSymbol = function(koPath, object) {
- var tokens = koPath.split(".");
- // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
- // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
- var target = ko;
- for (var i = 0; i < tokens.length - 1; i++)
- target = target[tokens[i]];
- target[tokens[tokens.length - 1]] = object;
- };
- ko.exportProperty = function(owner, publicName, object) {
- owner[publicName] = object;
- };
- ko.version = "2.1.0";
- ko.exportSymbol('version', ko.version);
- ko.utils = new (function () {
- var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
- // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
- var knownEvents = {}, knownEventTypesByEventName = {};
- var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
- knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
- knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
- for (var eventType in knownEvents) {
- var knownEventsForType = knownEvents[eventType];
- if (knownEventsForType.length) {
- for (var i = 0, j = knownEventsForType.length; i < j; i++)
- knownEventTypesByEventName[knownEventsForType[i]] = eventType;
- }
- }
- var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
- // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
- var ieVersion = (function() {
- var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
- // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
- while (
- div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
- iElems[0]
- );
- return version > 4 ? version : undefined;
- }());
- var isIe6 = ieVersion === 6,
- isIe7 = ieVersion === 7;
- function isClickOnCheckableElement(element, eventType) {
- if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
- if (eventType.toLowerCase() != "click") return false;
- var inputType = element.type;
- return (inputType == "checkbox") || (inputType == "radio");
- }
- return {
- fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
- arrayForEach: function (array, action) {
- for (var i = 0, j = array.length; i < j; i++)
- action(array[i]);
- },
- arrayIndexOf: function (array, item) {
- if (typeof Array.prototype.indexOf == "function")
- return Array.prototype.indexOf.call(array, item);
- for (var i = 0, j = array.length; i < j; i++)
- if (array[i] === item)
- return i;
- return -1;
- },
- arrayFirst: function (array, predicate, predicateOwner) {
- for (var i = 0, j = array.length; i < j; i++)
- if (predicate.call(predicateOwner, array[i]))
- return array[i];
- return null;
- },
- arrayRemoveItem: function (array, itemToRemove) {
- var index = ko.utils.arrayIndexOf(array, itemToRemove);
- if (index >= 0)
- array.splice(index, 1);
- },
- arrayGetDistinctValues: function (array) {
- array = array || [];
- var result = [];
- for (var i = 0, j = array.length; i < j; i++) {
- if (ko.utils.arrayIndexOf(result, array[i]) < 0)
- result.push(array[i]);
- }
- return result;
- },
- arrayMap: function (array, mapping) {
- array = array || [];
- var result = [];
- for (var i = 0, j = array.length; i < j; i++)
- result.push(mapping(array[i]));
- return result;
- },
- arrayFilter: function (array, predicate) {
- array = array || [];
- var result = [];
- for (var i = 0, j = array.length; i < j; i++)
- if (predicate(array[i]))
- result.push(array[i]);
- return result;
- },
- arrayPushAll: function (array, valuesToPush) {
- if (valuesToPush instanceof Array)
- array.push.apply(array, valuesToPush);
- else
- for (var i = 0, j = valuesToPush.length; i < j; i++)
- array.push(valuesToPush[i]);
- return array;
- },
- extend: function (target, source) {
- if (source) {
- for(var prop in source) {
- if(source.hasOwnProperty(prop)) {
- target[prop] = source[prop];
- }
- }
- }
- return target;
- },
- emptyDomNode: function (domNode) {
- while (domNode.firstChild) {
- ko.removeNode(domNode.firstChild);
- }
- },
- moveCleanedNodesToContainerElement: function(nodes) {
- // Ensure it's a real array, as we're about to reparent the nodes and
- // we don't want the underlying collection to change while we're doing that.
- var nodesArray = ko.utils.makeArray(nodes);
- var container = document.createElement('div');
- for (var i = 0, j = nodesArray.length; i < j; i++) {
- ko.cleanNode(nodesArray[i]);
- container.appendChild(nodesArray[i]);
- }
- return container;
- },
- setDomNodeChildren: function (domNode, childNodes) {
- ko.utils.emptyDomNode(domNode);
- if (childNodes) {
- for (var i = 0, j = childNodes.length; i < j; i++)
- domNode.appendChild(childNodes[i]);
- }
- },
- replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
- var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
- if (nodesToReplaceArray.length > 0) {
- var insertionPoint = nodesToReplaceArray[0];
- var parent = insertionPoint.parentNode;
- for (var i = 0, j = newNodesArray.length; i < j; i++)
- parent.insertBefore(newNodesArray[i], insertionPoint);
- for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
- ko.removeNode(nodesToReplaceArray[i]);
- }
- }
- },
- setOptionNodeSelectionState: function (optionNode, isSelected) {
- // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
- if (navigator.userAgent.indexOf("MSIE 6") >= 0)
- optionNode.setAttribute("selected", isSelected);
- else
- optionNode.selected = isSelected;
- },
- stringTrim: function (string) {
- return (string || "").replace(stringTrimRegex, "");
- },
- stringTokenize: function (string, delimiter) {
- var result = [];
- var tokens = (string || "").split(delimiter);
- for (var i = 0, j = tokens.length; i < j; i++) {
- var trimmed = ko.utils.stringTrim(tokens[i]);
- if (trimmed !== "")
- result.push(trimmed);
- }
- return result;
- },
- stringStartsWith: function (string, startsWith) {
- string = string || "";
- if (startsWith.length > string.length)
- return false;
- return string.substring(0, startsWith.length) === startsWith;
- },
- buildEvalWithinScopeFunction: function (expression, scopeLevels) {
- // Build the source for a function that evaluates "expression"
- // For each scope variable, add an extra level of "with" nesting
- // Example result: with(sc[1]) { with(sc[0]) { return (expression) } }
- var functionBody = "return (" + expression + ")";
- for (var i = 0; i < scopeLevels; i++) {
- functionBody = "with(sc[" + i + "]) { " + functionBody + " } ";
- }
- return new Function("sc", functionBody);
- },
- domNodeIsContainedBy: function (node, containedByNode) {
- if (containedByNode.compareDocumentPosition)
- return (containedByNode.compareDocumentPosition(node) & 16) == 16;
- while (node != null) {
- if (node == containedByNode)
- return true;
- node = node.parentNode;
- }
- return false;
- },
- domNodeIsAttachedToDocument: function (node) {
- return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
- },
- tagNameLower: function(element) {
- // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
- // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
- // we don't need to do the .toLowerCase() as it will always be lower case anyway.
- return element && element.tagName && element.tagName.toLowerCase();
- },
- registerEventHandler: function (element, eventType, handler) {
- var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
- if (!mustUseAttachEvent && typeof jQuery != "undefined") {
- if (isClickOnCheckableElement(element, eventType)) {
- // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
- // it toggles the element checked state *after* the click event handlers run, whereas native
- // click events toggle the checked state *before* the event handler.
- // Fix this by intecepting the handler and applying the correct checkedness before it runs.
- var originalHandler = handler;
- handler = function(event, eventData) {
- var jQuerySuppliedCheckedState = this.checked;
- if (eventData)
- this.checked = eventData.checkedStateBeforeEvent !== true;
- originalHandler.call(this, event);
- this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
- };
- }
- jQuery(element)['bind'](eventType, handler);
- } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
- element.addEventListener(eventType, handler, false);
- else if (typeof element.attachEvent != "undefined")
- element.attachEvent("on" + eventType, function (event) {
- handler.call(element, event);
- });
- else
- throw new Error("Browser doesn't support addEventListener or attachEvent");
- },
- triggerEvent: function (element, eventType) {
- if (!(element && element.nodeType))
- throw new Error("element must be a DOM node when calling triggerEvent");
- if (typeof jQuery != "undefined") {
- var eventData = [];
- if (isClickOnCheckableElement(element, eventType)) {
- // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
- eventData.push({ checkedStateBeforeEvent: element.checked });
- }
- jQuery(element)['trigger'](eventType, eventData);
- } else if (typeof document.createEvent == "function") {
- if (typeof element.dispatchEvent == "function") {
- var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
- var event = document.createEvent(eventCategory);
- event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
- element.dispatchEvent(event);
- }
- else
- throw new Error("The supplied element doesn't support dispatchEvent");
- } else if (typeof element.fireEvent != "undefined") {
- // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
- // so to make it consistent, we'll do it manually here
- if (isClickOnCheckableElement(element, eventType))
- element.checked = element.checked !== true;
- element.fireEvent("on" + eventType);
- }
- else
- throw new Error("Browser doesn't support triggering events");
- },
- unwrapObservable: function (value) {
- return ko.isObservable(value) ? value() : value;
- },
- toggleDomNodeCssClass: function (node, className, shouldHaveClass) {
- var currentClassNames = (node.className || "").split(/\s+/);
- var hasClass = ko.utils.arrayIndexOf(currentClassNames, className) >= 0;
- if (shouldHaveClass && !hasClass) {
- node.className += (currentClassNames[0] ? " " : "") + className;
- } else if (hasClass && !shouldHaveClass) {
- var newClassName = "";
- for (var i = 0; i < currentClassNames.length; i++)
- if (currentClassNames[i] != className)
- newClassName += currentClassNames[i] + " ";
- node.className = ko.utils.stringTrim(newClassName);
- }
- },
- setTextContent: function(element, textContent) {
- var value = ko.utils.unwrapObservable(textContent);
- if ((value === null) || (value === undefined))
- value = "";
- 'innerText' in element ? element.innerText = value
- : element.textContent = value;
- if (ieVersion >= 9) {
- // Believe it or not, this actually fixes an IE9 rendering bug
- // (See https://github.com/SteveSanderson/knockout/issues/209)
- element.style.display = element.style.display;
- }
- },
- ensureSelectElementIsRenderedCorrectly: function(selectElement) {
- // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
- // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
- if (ieVersion >= 9) {
- var originalWidth = selectElement.style.width;
- selectElement.style.width = 0;
- selectElement.style.width = originalWidth;
- }
- },
- range: function (min, max) {
- min = ko.utils.unwrapObservable(min);
- max = ko.utils.unwrapObservable(max);
- var result = [];
- for (var i = min; i <= max; i++)
- result.push(i);
- return result;
- },
- makeArray: function(arrayLikeObject) {
- var result = [];
- for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
- result.push(arrayLikeObject[i]);
- };
- return result;
- },
- isIe6 : isIe6,
- isIe7 : isIe7,
- ieVersion : ieVersion,
- getFormFields: function(form, fieldName) {
- var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
- var isMatchingField = (typeof fieldName == 'string')
- ? function(field) { return field.name === fieldName }
- : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
- var matches = [];
- for (var i = fields.length - 1; i >= 0; i--) {
- if (isMatchingField(fields[i]))
- matches.push(fields[i]);
- };
- return matches;
- },
- parseJson: function (jsonString) {
- if (typeof jsonString == "string") {
- jsonString = ko.utils.stringTrim(jsonString);
- if (jsonString) {
- if (window.JSON && window.JSON.parse) // Use native parsing where available
- return window.JSON.parse(jsonString);
- return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
- }
- }
- return null;
- },
- stringifyJson: function (data, replacer, space) { // replacer and space are optional
- if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
- throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
- return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
- },
- postJson: function (urlOrForm, data, options) {
- options = options || {};
- var params = options['params'] || {};
- var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
- var url = urlOrForm;
- // If we were given a form, use its 'action' URL and pick out any requested field values
- if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
- var originalForm = urlOrForm;
- url = originalForm.action;
- for (var i = includeFields.length - 1; i >= 0; i--) {
- var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
- for (var j = fields.length - 1; j >= 0; j--)
- params[fields[j].name] = fields[j].value;
- }
- }
- data = ko.utils.unwrapObservable(data);
- var form = document.createElement("form");
- form.style.display = "none";
- form.action = url;
- form.method = "post";
- for (var key in data) {
- var input = document.createElement("input");
- input.name = key;
- input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
- form.appendChild(input);
- }
- for (var key in params) {
- var input = document.createElement("input");
- input.name = key;
- input.value = params[key];
- form.appendChild(input);
- }
- document.body.appendChild(form);
- options['submitter'] ? options['submitter'](form) : form.submit();
- setTimeout(function () { form.parentNode.removeChild(form); }, 0);
- }
- }
- })();
- ko.exportSymbol('utils', ko.utils);
- ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
- ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
- ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
- ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
- ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
- ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
- ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
- ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
- ko.exportSymbol('utils.extend', ko.utils.extend);
- ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
- ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
- ko.exportSymbol('utils.postJson', ko.utils.postJson);
- ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
- ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
- ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
- ko.exportSymbol('utils.range', ko.utils.range);
- ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
- ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
- ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
- if (!Function.prototype['bind']) {
- // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
- // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
- Function.prototype['bind'] = function (object) {
- var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
- return function () {
- return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
- };
- };
- }
- ko.utils.domData = new (function () {
- var uniqueId = 0;
- var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
- var dataStore = {};
- return {
- get: function (node, key) {
- var allDataForNode = ko.utils.domData.getAll(node, false);
- return allDataForNode === undefined ? undefined : allDataForNode[key];
- },
- set: function (node, key, value) {
- if (value === undefined) {
- // Make sure we don't actually create a new domData key if we are actually deleting a value
- if (ko.utils.domData.getAll(node, false) === undefined)
- return;
- }
- var allDataForNode = ko.utils.domData.getAll(node, true);
- allDataForNode[key] = value;
- },
- getAll: function (node, createIfNotFound) {
- var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
- var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null");
- if (!hasExistingDataStore) {
- if (!createIfNotFound)
- return undefined;
- dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
- dataStore[dataStoreKey] = {};
- }
- return dataStore[dataStoreKey];
- },
- clear: function (node) {
- var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
- if (dataStoreKey) {
- delete dataStore[dataStoreKey];
- node[dataStoreKeyExpandoPropertyName] = null;
- }
- }
- }
- })();
- ko.exportSymbol('utils.domData', ko.utils.domData);
- ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
- ko.utils.domNodeDisposal = new (function () {
- var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
- var cleanableNodeTypes = { 1: true, 8: true, 9: true }; // Element, Comment, Document
- var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
- function getDisposeCallbacksCollection(node, createIfNotFound) {
- var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
- if ((allDisposeCallbacks === undefined) && createIfNotFound) {
- allDisposeCallbacks = [];
- ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
- }
- return allDisposeCallbacks;
- }
- function destroyCallbacksCollection(node) {
- ko.utils.domData.set(node, domDataKey, undefined);
- }
- function cleanSingleNode(node) {
- // Run all the dispose callbacks
- var callbacks = getDisposeCallbacksCollection(node, false);
- if (callbacks) {
- callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
- for (var i = 0; i < callbacks.length; i++)
- callbacks[i](node);
- }
- // Also erase the DOM data
- ko.utils.domData.clear(node);
- // Special support for jQuery here because it's so commonly used.
- // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
- // so notify it to tear down any resources associated with the node & descendants here.
- if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
- jQuery['cleanData']([node]);
- // Also clear any immediate-child comment nodes, as these wouldn't have been found by
- // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
- if (cleanableNodeTypesWithDescendants[node.nodeType])
- cleanImmediateCommentTypeChildren(node);
- }
- function cleanImmediateCommentTypeChildren(nodeWithChildren) {
- var child, nextChild = nodeWithChildren.firstChild;
- while (child = nextChild) {
- nextChild = child.nextSibling;
- if (child.nodeType === 8)
- cleanSingleNode(child);
- }
- }
- return {
- addDisposeCallback : function(node, callback) {
- if (typeof callback != "function")
- throw new Error("Callback must be a function");
- getDisposeCallbacksCollection(node, true).push(callback);
- },
- removeDisposeCallback : function(node, callback) {
- var callbacksCollection = getDisposeCallbacksCollection(node, false);
- if (callbacksCollection) {
- ko.utils.arrayRemoveItem(callbacksCollection, callback);
- if (callbacksCollection.length == 0)
- destroyCallbacksCollection(node);
- }
- },
- cleanNode : function(node) {
- // First clean this node, where applicable
- if (cleanableNodeTypes[node.nodeType]) {
- cleanSingleNode(node);
- // ... then its descendants, where applicable
- if (cleanableNodeTypesWithDescendants[node.nodeType]) {
- // Clone the descendants list in case it changes during iteration
- var descendants = [];
- ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
- for (var i = 0, j = descendants.length; i < j; i++)
- cleanSingleNode(descendants[i]);
- }
- }
- },
- removeNode : function(node) {
- ko.cleanNode(node);
- if (node.parentNode)
- node.parentNode.removeChild(node);
- }
- }
- })();
- ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
- ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
- ko.exportSymbol('cleanNode', ko.cleanNode);
- ko.exportSymbol('removeNode', ko.removeNode);
- ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
- ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
- ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
- (function () {
- var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
- function simpleHtmlParse(html) {
- // Based on jQuery's "clean" function, but only accounting for table-related elements.
- // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
- // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
- // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
- // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
- // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
- // Trim whitespace, otherwise indexOf won't work as expected
- var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
- // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
- var wrap = tags.match(/^<(thead|tbody|tfoot)/) && [1, "<table>", "</table>"] ||
- !tags.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] ||
- (!tags.indexOf("<td") || !tags.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
- /* anything else */ [0, "", ""];
- // Go to html and back, then peel off extra wrappers
- // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
- var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
- if (typeof window['innerShiv'] == "function") {
- div.appendChild(window['innerShiv'](markup));
- } else {
- div.innerHTML = markup;
- }
- // Move to the right depth
- while (wrap[0]--)
- div = div.lastChild;
- return ko.utils.makeArray(div.lastChild.childNodes);
- }
- function jQueryHtmlParse(html) {
- var elems = jQuery['clean']([html]);
- // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
- // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
- // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
- if (elems && elems[0]) {
- // Find the top-most parent element that's a direct child of a document fragment
- var elem = elems[0];
- while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
- elem = elem.parentNode;
- // ... then detach it
- if (elem.parentNode)
- elem.parentNode.removeChild(elem);
- }
- return elems;
- }
- ko.utils.parseHtmlFragment = function(html) {
- return typeof jQuery != 'undefined' ? jQueryHtmlParse(html) // As below, benefit from jQuery's optimisations where possible
- : simpleHtmlParse(html); // ... otherwise, this simple logic will do in most common cases.
- };
- ko.utils.setHtml = function(node, html) {
- ko.utils.emptyDomNode(node);
- if ((html !== null) && (html !== undefined)) {
- if (typeof html != 'string')
- html = html.toString();
- // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
- // for example <tr> elements which are not normally allowed to exist on their own.
- // If you've referenced jQuery we'll use that rather than duplicating its code.
- if (typeof jQuery != 'undefined') {
- jQuery(node)['html'](html);
- } else {
- // ... otherwise, use KO's own parsing logic.
- var parsedNodes = ko.utils.parseHtmlFragment(html);
- for (var i = 0; i < parsedNodes.length; i++)
- node.appendChild(parsedNodes[i]);
- }
- }
- };
- })();
- ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
- ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
- ko.memoization = (function () {
- var memos = {};
- function randomMax8HexChars() {
- return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
- }
- function generateRandomId() {
- return randomMax8HexChars() + randomMax8HexChars();
- }
- function findMemoNodes(rootNode, appendToArray) {
- if (!rootNode)
- return;
- if (rootNode.nodeType == 8) {
- var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
- if (memoId != null)
- appendToArray.push({ domNode: rootNode, memoId: memoId });
- } else if (rootNode.nodeType == 1) {
- for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
- findMemoNodes(childNodes[i], appendToArray);
- }
- }
- return {
- memoize: function (callback) {
- if (typeof callback != "function")
- throw new Error("You can only pass a function to ko.memoization.memoize()");
- var memoId = generateRandomId();
- memos[memoId] = callback;
- return "<!--[ko_memo:" + memoId + "]-->";
- },
- unmemoize: function (memoId, callbackParams) {
- var callback = memos[memoId];
- if (callback === undefined)
- throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
- try {
- callback.apply(null, callbackParams || []);
- return true;
- }
- finally { delete memos[memoId]; }
- },
- unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
- var memos = [];
- findMemoNodes(domNode, memos);
- for (var i = 0, j = memos.length; i < j; i++) {
- var node = memos[i].domNode;
- var combinedParams = [node];
- if (extraCallbackParamsArray)
- ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
- ko.memoization.unmemoize(memos[i].memoId, combinedParams);
- node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
- if (node.parentNode)
- node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
- }
- },
- parseMemoText: function (memoText) {
- var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
- return match ? match[1] : null;
- }
- };
- })();
- ko.exportSymbol('memoization', ko.memoization);
- ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
- ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
- ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
- ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
- ko.extenders = {
- 'throttle': function(target, timeout) {
- // Throttling means two things:
- // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
- // notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
- target['throttleEvaluation'] = timeout;
- // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
- // so the target cannot change value synchronously or faster than a certain rate
- var writeTimeoutInstance = null;
- return ko.dependentObservable({
- 'read': target,
- 'write': function(value) {
- clearTimeout(writeTimeoutInstance);
- writeTimeoutInstance = setTimeout(function() {
- target(value);
- }, timeout);
- }
- });
- },
- 'notify': function(target, notifyWhen) {
- target["equalityComparer"] = notifyWhen == "always"
- ? function() { return false } // Treat all values as not equal
- : ko.observable["fn"]["equalityComparer"];
- return target;
- }
- };
- function applyExtenders(requestedExtenders) {
- var target = this;
- if (requestedExtenders) {
- for (var key in requestedExtenders) {
- var extenderHandler = ko.extenders[key];
- if (typeof extenderHandler == 'function') {
- target = extenderHandler(target, requestedExtenders[key]);
- }
- }
- }
- return target;
- }
- ko.exportSymbol('extenders', ko.extenders);
- ko.subscription = function (target, callback, disposeCallback) {
- this.target = target;
- this.callback = callback;
- this.disposeCallback = disposeCallback;
- ko.exportProperty(this, 'dispose', this.dispose);
- };
- ko.subscription.prototype.dispose = function () {
- this.isDisposed = true;
- this.disposeCallback();
- };
- ko.subscribable = function () {
- this._subscriptions = {};
- ko.utils.extend(this, ko.subscribable['fn']);
- ko.exportProperty(this, 'subscribe', this.subscribe);
- ko.exportProperty(this, 'extend', this.extend);
- ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
- }
- var defaultEvent = "change";
- ko.subscribable['fn'] = {
- subscribe: function (callback, callbackTarget, event) {
- event = event || defaultEvent;
- var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
- var subscription = new ko.subscription(this, boundCallback, function () {
- ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
- }.bind(this));
- if (!this._subscriptions[event])
- this._subscriptions[event] = [];
- this._subscriptions[event].push(subscription);
- return subscription;
- },
- "notifySubscribers": function (valueToNotify, event) {
- event = event || defaultEvent;
- if (this._subscriptions[event]) {
- ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
- // In case a subscription was disposed during the arrayForEach cycle, check
- // for isDisposed on each subscription before invoking its callback
- if (subscription && (subscription.isDisposed !== true))
- subscription.callback(valueToNotify);
- });
- }
- },
- getSubscriptionsCount: function () {
- var total = 0;
- for (var eventName in this._subscriptions) {
- if (this._subscriptions.hasOwnProperty(eventName))
- total += this._subscriptions[eventName].length;
- }
- return total;
- },
- extend: applyExtenders
- };
- ko.isSubscribable = function (instance) {
- return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
- };
- ko.exportSymbol('subscribable', ko.subscribable);
- ko.exportSymbol('isSubscribable', ko.isSubscribable);
- ko.dependencyDetection = (function () {
- var _frames = [];
- return {
- begin: function (callback) {
- _frames.push({ callback: callback, distinctDependencies:[] });
- },
- end: function () {
- _frames.pop();
- },
- registerDependency: function (subscribable) {
- if (!ko.isSubscribable(subscribable))
- throw new Error("Only subscribable things can act as dependencies");
- if (_frames.length > 0) {
- var topFrame = _frames[_frames.length - 1];
- if (ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
- return;
- topFrame.distinctDependencies.push(subscribable);
- topFrame.callback(subscribable);
- }
- }
- };
- })();
- var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
- ko.observable = function (initialValue) {
- var _latestValue = initialValue;
- function observable() {
- if (arguments.length > 0) {
- // Write
- // Ignore writes if the value hasn't changed
- if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
- observable.valueWillMutate();
- _latestValue = arguments[0];
- if (DEBUG) observable._latestValue = _latestValue;
- observable.valueHasMutated();
- }
- return this; // Permits chained assignments
- }
- else {
- // Read
- ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
- return _latestValue;
- }
- }
- if (DEBUG) observable._latestValue = _latestValue;
- ko.subscribable.call(observable);
- observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
- observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
- ko.utils.extend(observable, ko.observable['fn']);
- ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
- ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
- return observable;
- }
- ko.observable['fn'] = {
- "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
- var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
- return oldValueIsPrimitive ? (a === b) : false;
- }
- };
- var protoProperty = ko.observable.protoProperty = "__ko_proto__";
- ko.observable['fn'][protoProperty] = ko.observable;
- ko.hasPrototype = function(instance, prototype) {
- if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
- if (instance[protoProperty] === prototype) return true;
- return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
- };
- ko.isObservable = function (instance) {
- return ko.hasPrototype(instance, ko.observable);
- }
- ko.isWriteableObservable = function (instance) {
- // Observable
- if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
- return true;
- // Writeable dependent observable
- if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
- return true;
- // Anything else
- return false;
- }
- ko.exportSymbol('observable', ko.observable);
- ko.exportSymbol('isObservable', ko.isObservable);
- ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
- ko.observableArray = function (initialValues) {
- if (arguments.length == 0) {
- // Zero-parameter constructor initializes to empty array
- initialValues = [];
- }
- if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
- throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
- var result = ko.observable(initialValues);
- ko.utils.extend(result, ko.observableArray['fn']);
- return result;
- }
- ko.observableArray['fn'] = {
- 'remove': function (valueOrPredicate) {
- var underlyingArray = this();
- var removedValues = [];
- var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
- for (var i = 0; i < underlyingArray.length; i++) {
- var value = underlyingArray[i];
- if (predicate(value)) {
- if (removedValues.length === 0) {
- this.valueWillMutate();
- }
- removedValues.push(value);
- underlyingArray.splice(i, 1);
- i--;
- }
- }
- if (removedValues.length) {
- this.valueHasMutated();
- }
- return removedValues;
- },
- 'removeAll': function (arrayOfValues) {
- // If you passed zero args, we remove everything
- if (arrayOfValues === undefined) {
- var underlyingArray = this();
- var allValues = underlyingArray.slice(0);
- this.valueWillMutate();
- underlyingArray.splice(0, underlyingArray.length);
- this.valueHasMutated();
- return allValues;
- }
- // If you passed an arg, we interpret it as an array of entries to remove
- if (!arrayOfValues)
- return [];
- return this['remove'](function (value) {
- return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
- });
- },
- 'destroy': function (valueOrPredicate) {
- var underlyingArray = this();
- var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
- this.valueWillMutate();
- for (var i = underlyingArray.length - 1; i >= 0; i--) {
- var value = underlyingArray[i];
- if (predicate(value))
- underlyingArray[i]["_destroy"] = true;
- }
- this.valueHasMutated();
- },
- 'destroyAll': function (arrayOfValues) {
- // If you passed zero args, we destroy everything
- if (arrayOfValues === undefined)
- return this['destroy'](function() { return true });
- // If you passed an arg, we interpret it as an array of entries to destroy
- if (!arrayOfValues)
- return [];
- return this['destroy'](function (value) {
- return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
- });
- },
- 'indexOf': function (item) {
- var underlyingArray = this();
- return ko.utils.arrayIndexOf(underlyingArray, item);
- },
- 'replace': function(oldItem, newItem) {
- var index = this['indexOf'](oldItem);
- if (index >= 0) {
- this.valueWillMutate();
- this()[index] = newItem;
- this.valueHasMutated();
- }
- }
- }
- // Populate ko.observableArray.fn with read/write functions from native arrays
- ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
- ko.observableArray['fn'][methodName] = function () {
- var underlyingArray = this();
- this.valueWillMutate();
- var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
- this.valueHasMutated();
- return methodCallResult;
- };
- });
- // Populate ko.observableArray.fn with read-only functions from native arrays
- ko.utils.arrayForEach(["slice"], function (methodName) {
- ko.observableArray['fn'][methodName] = function () {
- var underlyingArray = this();
- return underlyingArray[methodName].apply(underlyingArray, arguments);
- };
- });
- ko.exportSymbol('observableArray', ko.observableArray);
- ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
- var _latestValue,
- _hasBeenEvaluated = false,
- _isBeingEvaluated = false,
- readFunction = evaluatorFunctionOrOptions;
- if (readFunction && typeof readFunction == "object") {
- // Single-parameter syntax - everything is on this "options" param
- options = readFunction;
- readFunction = options["read"];
- } else {
- // Multi-parameter syntax - construct the options according to the params passed
- options = options || {};
- if (!readFunction)
- readFunction = options["read"];
- }
- // By here, "options" is always non-null
- if (typeof readFunction != "function")
- throw new Error("Pass a function that returns the value of the ko.computed");
- var writeFunction = options["write"];
- if (!evaluatorFunctionTarget)
- evaluatorFunctionTarget = options["owner"];
- var _subscriptionsToDependencies = [];
- function disposeAllSubscriptionsToDependencies() {
- ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
- subscription.dispose();
- });
- _subscriptionsToDependencies = [];
- }
- var dispose = disposeAllSubscriptionsToDependencies;
- // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values
- // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
- // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node