ganglia_js_charts 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1852 @@
1
+ // Knockout JavaScript library v1.1.2
2
+ // (c) 2010 Steven Sanderson - http://knockoutjs.com/
3
+ // License: Ms-Pl (http://www.opensource.org/licenses/ms-pl.html)
4
+
5
+ var ko = window["ko"] = {};
6
+ // Google Closure Compiler helpers (used only to make the minified file smaller)
7
+ ko.exportSymbol = function(publicPath, object) {
8
+ var tokens = publicPath.split(".");
9
+ var target = window;
10
+ for (var i = 0; i < tokens.length - 1; i++)
11
+ target = target[tokens[i]];
12
+ target[tokens[tokens.length - 1]] = object;
13
+ };
14
+ ko.exportProperty = function(owner, publicName, object) {
15
+ owner[publicName] = object;
16
+ };
17
+ ko.utils = new (function () {
18
+ var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
19
+ var isIe6 = /MSIE 6/i.test(navigator.userAgent);
20
+ var isIe7 = /MSIE 7/i.test(navigator.userAgent);
21
+
22
+ return {
23
+ fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
24
+
25
+ arrayForEach: function (array, action) {
26
+ for (var i = 0, j = array.length; i < j; i++)
27
+ action(array[i]);
28
+ },
29
+
30
+ arrayIndexOf: function (array, item) {
31
+ if (typeof array.indexOf == "function")
32
+ return array.indexOf(item);
33
+ for (var i = 0, j = array.length; i < j; i++)
34
+ if (array[i] == item)
35
+ return i;
36
+ return -1;
37
+ },
38
+
39
+ arrayFirst: function (array, predicate, predicateOwner) {
40
+ for (var i = 0, j = array.length; i < j; i++)
41
+ if (predicate.call(predicateOwner, array[i]))
42
+ return array[i];
43
+ return null;
44
+ },
45
+
46
+ arrayRemoveItem: function (array, itemToRemove) {
47
+ var index = ko.utils.arrayIndexOf(array, itemToRemove);
48
+ if (index >= 0)
49
+ array.splice(index, 1);
50
+ },
51
+
52
+ arrayGetDistinctValues: function (array) {
53
+ array = array || [];
54
+ var result = [];
55
+ for (var i = 0, j = array.length; i < j; i++) {
56
+ if (ko.utils.arrayIndexOf(result, array[i]) < 0)
57
+ result.push(array[i]);
58
+ }
59
+ return result;
60
+ },
61
+
62
+ arrayMap: function (array, mapping) {
63
+ array = array || [];
64
+ var result = [];
65
+ for (var i = 0, j = array.length; i < j; i++)
66
+ result.push(mapping(array[i]));
67
+ return result;
68
+ },
69
+
70
+ arrayFilter: function (array, predicate) {
71
+ array = array || [];
72
+ var result = [];
73
+ for (var i = 0, j = array.length; i < j; i++)
74
+ if (predicate(array[i]))
75
+ result.push(array[i]);
76
+ return result;
77
+ },
78
+
79
+ arrayPushAll: function (array, valuesToPush) {
80
+ for (var i = 0, j = valuesToPush.length; i < j; i++)
81
+ array.push(valuesToPush[i]);
82
+ },
83
+
84
+ emptyDomNode: function (domNode) {
85
+ while (domNode.firstChild) {
86
+ ko.utils.domData.cleanNodeAndDescendants(domNode.firstChild);
87
+ domNode.removeChild(domNode.firstChild);
88
+ }
89
+ },
90
+
91
+ setDomNodeChildren: function (domNode, childNodes) {
92
+ ko.utils.emptyDomNode(domNode);
93
+ if (childNodes) {
94
+ ko.utils.arrayForEach(childNodes, function (childNode) {
95
+ domNode.appendChild(childNode);
96
+ });
97
+ }
98
+ },
99
+
100
+ replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
101
+ var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
102
+ if (nodesToReplaceArray.length > 0) {
103
+ var insertionPoint = nodesToReplaceArray[0];
104
+ var parent = insertionPoint.parentNode;
105
+ for (var i = 0, j = newNodesArray.length; i < j; i++)
106
+ parent.insertBefore(newNodesArray[i], insertionPoint);
107
+ for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
108
+ ko.utils.domData.cleanNodeAndDescendants(nodesToReplaceArray[i]);
109
+ parent.removeChild(nodesToReplaceArray[i]);
110
+ }
111
+ }
112
+ },
113
+
114
+ setOptionNodeSelectionState: function (optionNode, isSelected) {
115
+ // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
116
+ if (navigator.userAgent.indexOf("MSIE 6") >= 0)
117
+ optionNode.setAttribute("selected", isSelected);
118
+ else
119
+ optionNode.selected = isSelected;
120
+ },
121
+
122
+ getElementsHavingAttribute: function (rootNode, attributeName) {
123
+ if ((!rootNode) || (rootNode.nodeType != 1)) return [];
124
+ var results = [];
125
+ if (rootNode.getAttribute(attributeName) !== null)
126
+ results.push(rootNode);
127
+ var descendants = rootNode.getElementsByTagName("*");
128
+ for (var i = 0, j = descendants.length; i < j; i++)
129
+ if (descendants[i].getAttribute(attributeName) !== null)
130
+ results.push(descendants[i]);
131
+ return results;
132
+ },
133
+
134
+ stringTrim: function (string) {
135
+ return (string || "").replace(stringTrimRegex, "");
136
+ },
137
+
138
+ stringTokenize: function (string, delimiter) {
139
+ var result = [];
140
+ var tokens = (string || "").split(delimiter);
141
+ for (var i = 0, j = tokens.length; i < j; i++) {
142
+ var trimmed = ko.utils.stringTrim(tokens[i]);
143
+ if (trimmed !== "")
144
+ result.push(trimmed);
145
+ }
146
+ return result;
147
+ },
148
+
149
+ stringStartsWith: function (string, startsWith) {
150
+ string = string || "";
151
+ if (startsWith.length > string.length)
152
+ return false;
153
+ return string.substring(0, startsWith.length) === startsWith;
154
+ },
155
+
156
+ evalWithinScope: function (expression, scope) {
157
+ if (scope === undefined)
158
+ return (new Function("return " + expression))();
159
+ with (scope) { return eval("(" + expression + ")"); }
160
+ },
161
+
162
+ domNodeIsContainedBy: function (node, containedByNode) {
163
+ if (containedByNode.compareDocumentPosition)
164
+ return (containedByNode.compareDocumentPosition(node) & 16) == 16;
165
+ while (node != null) {
166
+ if (node == containedByNode)
167
+ return true;
168
+ node = node.parentNode;
169
+ }
170
+ return false;
171
+ },
172
+
173
+ domNodeIsAttachedToDocument: function (node) {
174
+ return ko.utils.domNodeIsContainedBy(node, document);
175
+ },
176
+
177
+ registerEventHandler: function (element, eventType, handler) {
178
+ if (typeof jQuery != "undefined")
179
+ jQuery(element)['bind'](eventType, handler);
180
+ else if (typeof element.addEventListener == "function")
181
+ element.addEventListener(eventType, handler, false);
182
+ else if (typeof element.attachEvent != "undefined")
183
+ element.attachEvent("on" + eventType, function (event) {
184
+ handler.call(element, event);
185
+ });
186
+ else
187
+ throw new Error("Browser doesn't support addEventListener or attachEvent");
188
+ },
189
+
190
+ triggerEvent: function (element, eventType) {
191
+ if (!(element && element.nodeType))
192
+ throw new Error("element must be a DOM node when calling triggerEvent");
193
+
194
+ if (typeof document.createEvent == "function") {
195
+ if (typeof element.dispatchEvent == "function") {
196
+ var eventCategory = (eventType == "click" ? "MouseEvents" : "HTMLEvents"); // Might need to account for other event names at some point
197
+ var event = document.createEvent(eventCategory);
198
+ event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
199
+ element.dispatchEvent(event);
200
+ }
201
+ else
202
+ throw new Error("The supplied element doesn't support dispatchEvent");
203
+ } else if (typeof element.fireEvent != "undefined") {
204
+ // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
205
+ // so to make it consistent, we'll do it manually here
206
+ if (eventType == "click") {
207
+ if ((element.tagName == "INPUT") && ((element.type.toLowerCase() == "checkbox") || (element.type.toLowerCase() == "radio")))
208
+ element.checked = element.checked !== true;
209
+ }
210
+ element.fireEvent("on" + eventType);
211
+ }
212
+ else
213
+ throw new Error("Browser doesn't support triggering events");
214
+ },
215
+
216
+ unwrapObservable: function (value) {
217
+ return ko.isObservable(value) ? value() : value;
218
+ },
219
+
220
+ domNodeHasCssClass: function (node, className) {
221
+ var currentClassNames = (node.className || "").split(/\s+/);
222
+ return ko.utils.arrayIndexOf(currentClassNames, className) >= 0;
223
+ },
224
+
225
+ toggleDomNodeCssClass: function (node, className, shouldHaveClass) {
226
+ var hasClass = ko.utils.domNodeHasCssClass(node, className);
227
+ if (shouldHaveClass && !hasClass) {
228
+ node.className = (node.className || "") + " " + className;
229
+ } else if (hasClass && !shouldHaveClass) {
230
+ var currentClassNames = (node.className || "").split(/\s+/);
231
+ var newClassName = "";
232
+ for (var i = 0; i < currentClassNames.length; i++)
233
+ if (currentClassNames[i] != className)
234
+ newClassName += currentClassNames[i] + " ";
235
+ node.className = ko.utils.stringTrim(newClassName);
236
+ }
237
+ },
238
+
239
+ range: function (min, max) {
240
+ min = ko.utils.unwrapObservable(min);
241
+ max = ko.utils.unwrapObservable(max);
242
+ var result = [];
243
+ for (var i = min; i <= max; i++)
244
+ result.push(i);
245
+ return result;
246
+ },
247
+
248
+ makeArray: function(arrayLikeObject) {
249
+ var result = [];
250
+ for (var i = arrayLikeObject.length - 1; i >= 0; i--){
251
+ result.push(arrayLikeObject[i]);
252
+ };
253
+ return result;
254
+ },
255
+
256
+ isIe6 : isIe6,
257
+ isIe7 : isIe7,
258
+
259
+ getFormFields: function(form, fieldName) {
260
+ var fields = ko.utils.makeArray(form.getElementsByTagName("INPUT")).concat(ko.utils.makeArray(form.getElementsByTagName("TEXTAREA")));
261
+ var isMatchingField = (typeof fieldName == 'string')
262
+ ? function(field) { return field.name === fieldName }
263
+ : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
264
+ var matches = [];
265
+ for (var i = fields.length - 1; i >= 0; i--) {
266
+ if (isMatchingField(fields[i]))
267
+ matches.push(fields[i]);
268
+ };
269
+ return matches;
270
+ },
271
+
272
+ parseJson: function (jsonString) {
273
+ if (typeof jsonString == "string") {
274
+ jsonString = ko.utils.stringTrim(jsonString);
275
+ if (jsonString) {
276
+ if (window.JSON && window.JSON.parse) // Use native parsing where available
277
+ return window.JSON.parse(jsonString);
278
+ return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
279
+ }
280
+ }
281
+ return null;
282
+ },
283
+
284
+ stringifyJson: function (data) {
285
+ if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
286
+ 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");
287
+ return JSON.stringify(ko.utils.unwrapObservable(data));
288
+ },
289
+
290
+ postJson: function (urlOrForm, data, options) {
291
+ options = options || {};
292
+ var params = options['params'] || {};
293
+ var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
294
+ var url = urlOrForm;
295
+
296
+ // If we were given a form, use its 'action' URL and pick out any requested field values
297
+ if((typeof urlOrForm == 'object') && (urlOrForm.tagName == "FORM")) {
298
+ var originalForm = urlOrForm;
299
+ url = originalForm.action;
300
+ for (var i = includeFields.length - 1; i >= 0; i--) {
301
+ var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
302
+ for (var j = fields.length - 1; j >= 0; j--)
303
+ params[fields[j].name] = fields[j].value;
304
+ }
305
+ }
306
+
307
+ data = ko.utils.unwrapObservable(data);
308
+ var form = document.createElement("FORM");
309
+ form.style.display = "none";
310
+ form.action = url;
311
+ form.method = "post";
312
+ for (var key in data) {
313
+ var input = document.createElement("INPUT");
314
+ input.name = key;
315
+ input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
316
+ form.appendChild(input);
317
+ }
318
+ for (var key in params) {
319
+ var input = document.createElement("INPUT");
320
+ input.name = key;
321
+ input.value = params[key];
322
+ form.appendChild(input);
323
+ }
324
+ document.body.appendChild(form);
325
+ options['submitter'] ? options['submitter'](form) : form.submit();
326
+ setTimeout(function () { form.parentNode.removeChild(form); }, 0);
327
+ },
328
+
329
+ domData: {
330
+ uniqueId: 0,
331
+ dataStoreKeyExpandoPropertyName: "__ko__" + (new Date).getTime(),
332
+ dataStore: {},
333
+ get: function (node, key) {
334
+ var allDataForNode = ko.utils.domData.getAll(node, false);
335
+ return allDataForNode === undefined ? undefined : allDataForNode[key];
336
+ },
337
+ set: function (node, key, value) {
338
+ var allDataForNode = ko.utils.domData.getAll(node, true);
339
+ allDataForNode[key] = value;
340
+ },
341
+ getAll: function (node, createIfNotFound) {
342
+ var dataStoreKey = node[ko.utils.domData.dataStoreKeyExpandoPropertyName];
343
+ if (!dataStoreKey) {
344
+ if (!createIfNotFound)
345
+ return undefined;
346
+ dataStoreKey = node[ko.utils.domData.dataStoreKeyExpandoPropertyName] = "ko" + ko.utils.domData.uniqueId++;
347
+ ko.utils.domData[dataStoreKey] = {};
348
+ }
349
+ return ko.utils.domData[dataStoreKey];
350
+ },
351
+ cleanNode: function (node) {
352
+ var dataStoreKey = node[ko.utils.domData.dataStoreKeyExpandoPropertyName];
353
+ if (dataStoreKey) {
354
+ delete ko.utils.domData[dataStoreKey];
355
+ node[ko.utils.domData.dataStoreKeyExpandoPropertyName] = null;
356
+ }
357
+ },
358
+ cleanNodeAndDescendants: function (node) {
359
+ if ((node.nodeType != 1) && (node.nodeType != 9))
360
+ return;
361
+ ko.utils.domData.cleanNode(node);
362
+ var descendants = node.getElementsByTagName("*");
363
+ for (var i = 0, j = descendants.length; i < j; i++)
364
+ ko.utils.domData.cleanNode(descendants[i]);
365
+ }
366
+ }
367
+ }
368
+ })();
369
+
370
+ ko.exportSymbol('ko.utils', ko.utils);
371
+ ko.exportSymbol('ko.utils.arrayForEach', ko.utils.arrayForEach);
372
+ ko.exportSymbol('ko.utils.arrayFirst', ko.utils.arrayFirst);
373
+ ko.exportSymbol('ko.utils.arrayFilter', ko.utils.arrayFilter);
374
+ ko.exportSymbol('ko.utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
375
+ ko.exportSymbol('ko.utils.arrayIndexOf', ko.utils.arrayIndexOf);
376
+ ko.exportSymbol('ko.utils.arrayMap', ko.utils.arrayMap);
377
+ ko.exportSymbol('ko.utils.arrayPushAll', ko.utils.arrayPushAll);
378
+ ko.exportSymbol('ko.utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
379
+ ko.exportSymbol('ko.utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
380
+ ko.exportSymbol('ko.utils.getFormFields', ko.utils.getFormFields);
381
+ ko.exportSymbol('ko.utils.postJson', ko.utils.postJson);
382
+ ko.exportSymbol('ko.utils.parseJson', ko.utils.parseJson);
383
+ ko.exportSymbol('ko.utils.stringifyJson', ko.utils.stringifyJson);
384
+ ko.exportSymbol('ko.utils.range', ko.utils.range);
385
+ ko.exportSymbol('ko.utils.triggerEvent', ko.utils.triggerEvent);
386
+ ko.exportSymbol('ko.utils.unwrapObservable', ko.utils.unwrapObservable);
387
+
388
+ if (!Function.prototype['bind']) {
389
+ // 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)
390
+ // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
391
+ Function.prototype['bind'] = function (object) {
392
+ var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
393
+ return function () {
394
+ return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
395
+ };
396
+ };
397
+ }
398
+ ko.memoization = (function () {
399
+ var memos = {};
400
+
401
+ function randomMax8HexChars() {
402
+ return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
403
+ }
404
+ function generateRandomId() {
405
+ return randomMax8HexChars() + randomMax8HexChars();
406
+ }
407
+ function findMemoNodes(rootNode, appendToArray) {
408
+ if (!rootNode)
409
+ return;
410
+ if (rootNode.nodeType == 8) {
411
+ var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
412
+ if (memoId != null)
413
+ appendToArray.push({ domNode: rootNode, memoId: memoId });
414
+ } else if (rootNode.nodeType == 1) {
415
+ for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
416
+ findMemoNodes(childNodes[i], appendToArray);
417
+ }
418
+ }
419
+
420
+ return {
421
+ memoize: function (callback) {
422
+ if (typeof callback != "function")
423
+ throw new Error("You can only pass a function to ko.memoization.memoize()");
424
+ var memoId = generateRandomId();
425
+ memos[memoId] = callback;
426
+ return "<!--[ko_memo:" + memoId + "]-->";
427
+ },
428
+
429
+ unmemoize: function (memoId, callbackParams) {
430
+ var callback = memos[memoId];
431
+ if (callback === undefined)
432
+ throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
433
+ try {
434
+ callback.apply(null, callbackParams || []);
435
+ return true;
436
+ }
437
+ finally { delete memos[memoId]; }
438
+ },
439
+
440
+ unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
441
+ var memos = [];
442
+ findMemoNodes(domNode, memos);
443
+ for (var i = 0, j = memos.length; i < j; i++) {
444
+ var node = memos[i].domNode;
445
+ var combinedParams = [node];
446
+ if (extraCallbackParamsArray)
447
+ ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
448
+ ko.memoization.unmemoize(memos[i].memoId, combinedParams);
449
+ node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
450
+ if (node.parentNode)
451
+ 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)
452
+ }
453
+ },
454
+
455
+ parseMemoText: function (memoText) {
456
+ var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
457
+ return match ? match[1] : null;
458
+ }
459
+ };
460
+ })();
461
+
462
+ ko.exportSymbol('ko.memoization', ko.memoization);
463
+ ko.exportSymbol('ko.memoization.memoize', ko.memoization.memoize);
464
+ ko.exportSymbol('ko.memoization.unmemoize', ko.memoization.unmemoize);
465
+ ko.exportSymbol('ko.memoization.parseMemoText', ko.memoization.parseMemoText);
466
+ ko.exportSymbol('ko.memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
467
+
468
+ ko.subscription = function (callback, disposeCallback) {
469
+ this.callback = callback;
470
+ this.dispose = disposeCallback;
471
+
472
+ ko.exportProperty(this, 'dispose', this.dispose);
473
+ };
474
+
475
+ ko.subscribable = function () {
476
+ var _subscriptions = [];
477
+
478
+ this.subscribe = function (callback, callbackTarget) {
479
+ var boundCallback = callbackTarget ? function () { callback.call(callbackTarget) } : callback;
480
+
481
+ var subscription = new ko.subscription(boundCallback, function () {
482
+ ko.utils.arrayRemoveItem(_subscriptions, subscription);
483
+ });
484
+ _subscriptions.push(subscription);
485
+ return subscription;
486
+ };
487
+
488
+ this.notifySubscribers = function (valueToNotify) {
489
+ ko.utils.arrayForEach(_subscriptions.slice(0), function (subscription) {
490
+ if (subscription)
491
+ subscription.callback(valueToNotify);
492
+ });
493
+ };
494
+
495
+ this.getSubscriptionsCount = function () {
496
+ return _subscriptions.length;
497
+ };
498
+
499
+ ko.exportProperty(this, 'subscribe', this.subscribe);
500
+ ko.exportProperty(this, 'notifySubscribers', this.notifySubscribers);
501
+ ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
502
+ }
503
+
504
+ ko.isSubscribable = function (instance) {
505
+ return typeof instance.subscribe == "function" && typeof instance.notifySubscribers == "function";
506
+ };
507
+
508
+ ko.exportSymbol('ko.subscribable', ko.subscribable);
509
+ ko.exportSymbol('ko.isSubscribable', ko.isSubscribable);
510
+
511
+ ko.dependencyDetection = (function () {
512
+ var _detectedDependencies = [];
513
+
514
+ return {
515
+ begin: function () {
516
+ _detectedDependencies.push([]);
517
+ },
518
+
519
+ end: function () {
520
+ return _detectedDependencies.pop();
521
+ },
522
+
523
+ registerDependency: function (subscribable) {
524
+ if (!ko.isSubscribable(subscribable))
525
+ throw "Only subscribable things can act as dependencies";
526
+ if (_detectedDependencies.length > 0) {
527
+ _detectedDependencies[_detectedDependencies.length - 1].push(subscribable);
528
+ }
529
+ }
530
+ };
531
+ })();
532
+ ko.observable = function (initialValue) {
533
+ var _latestValue = initialValue;
534
+
535
+ function observable() {
536
+ if (arguments.length > 0) {
537
+ // Write
538
+ _latestValue = arguments[0];
539
+ observable.notifySubscribers(_latestValue);
540
+ return this; // Permits chained assignments
541
+ }
542
+ else {
543
+ // Read
544
+ ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
545
+ return _latestValue;
546
+ }
547
+ }
548
+ observable.__ko_proto__ = ko.observable;
549
+ observable.valueHasMutated = function () { observable.notifySubscribers(_latestValue); }
550
+
551
+ ko.subscribable.call(observable);
552
+
553
+ ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
554
+
555
+ return observable;
556
+ }
557
+ ko.isObservable = function (instance) {
558
+ if ((instance === null) || (instance === undefined) || (instance.__ko_proto__ === undefined)) return false;
559
+ if (instance.__ko_proto__ === ko.observable) return true;
560
+ return ko.isObservable(instance.__ko_proto__); // Walk the prototype chain
561
+ }
562
+ ko.isWriteableObservable = function (instance) {
563
+ // Observable
564
+ if ((typeof instance == "function") && instance.__ko_proto__ === ko.observable)
565
+ return true;
566
+ // Writeable dependent observable
567
+ if ((typeof instance == "function") && (instance.__ko_proto__ === ko.dependentObservable) && (instance.hasWriteFunction))
568
+ return true;
569
+ // Anything else
570
+ return false;
571
+ }
572
+
573
+
574
+ ko.exportSymbol('ko.observable', ko.observable);
575
+ ko.exportSymbol('ko.isObservable', ko.isObservable);
576
+ ko.exportSymbol('ko.isWriteableObservable', ko.isWriteableObservable);
577
+
578
+ ko.observableArray = function (initialValues) {
579
+ var result = new ko.observable(initialValues);
580
+
581
+ ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
582
+ result[methodName] = function () {
583
+ var underlyingArray = result();
584
+ var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
585
+ result.valueHasMutated();
586
+ return methodCallResult;
587
+ };
588
+ });
589
+
590
+ ko.utils.arrayForEach(["slice"], function (methodName) {
591
+ result[methodName] = function () {
592
+ var underlyingArray = result();
593
+ return underlyingArray[methodName].apply(underlyingArray, arguments);
594
+ };
595
+ });
596
+
597
+ result.remove = function (valueOrPredicate) {
598
+ var underlyingArray = result();
599
+ var remainingValues = [];
600
+ var removedValues = [];
601
+ var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
602
+ for (var i = 0, j = underlyingArray.length; i < j; i++) {
603
+ var value = underlyingArray[i];
604
+ if (!predicate(value))
605
+ remainingValues.push(value);
606
+ else
607
+ removedValues.push(value);
608
+ }
609
+ result(remainingValues);
610
+ return removedValues;
611
+ };
612
+
613
+ result.removeAll = function (arrayOfValues) {
614
+ if (!arrayOfValues)
615
+ return [];
616
+ return result.remove(function (value) {
617
+ return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
618
+ });
619
+ };
620
+
621
+ result.destroy = function (valueOrPredicate) {
622
+ var underlyingArray = result();
623
+ var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
624
+ for (var i = underlyingArray.length - 1; i >= 0; i--) {
625
+ var value = underlyingArray[i];
626
+ if (predicate(value))
627
+ underlyingArray[i]["_destroy"] = true;
628
+ }
629
+ result.valueHasMutated();
630
+ };
631
+
632
+ result.destroyAll = function (arrayOfValues) {
633
+ if (!arrayOfValues)
634
+ return [];
635
+ return result.destroy(function (value) {
636
+ return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
637
+ });
638
+ };
639
+
640
+ result.indexOf = function (item) {
641
+ var underlyingArray = result();
642
+ return ko.utils.arrayIndexOf(underlyingArray, item);
643
+ };
644
+
645
+ result.replace = function(oldItem, newItem) {
646
+ var index = result.indexOf(oldItem);
647
+ if (index >= 0) {
648
+ result()[index] = newItem;
649
+ result.valueHasMutated();
650
+ }
651
+ };
652
+
653
+ ko.exportProperty(result, "remove", result.remove);
654
+ ko.exportProperty(result, "removeAll", result.removeAll);
655
+ ko.exportProperty(result, "destroy", result.destroy);
656
+ ko.exportProperty(result, "destroyAll", result.destroyAll);
657
+ ko.exportProperty(result, "indexOf", result.indexOf);
658
+
659
+ return result;
660
+ }
661
+
662
+ ko.exportSymbol('ko.observableArray', ko.observableArray);
663
+
664
+ ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
665
+ if (evaluatorFunctionOrOptions && typeof evaluatorFunctionOrOptions == "object") {
666
+ // Single-parameter syntax - everything is on this "options" param
667
+ options = evaluatorFunctionOrOptions;
668
+ } else {
669
+ // Multi-parameter syntax - construct the options according to the params passed
670
+ options = options || {};
671
+ options["read"] = evaluatorFunctionOrOptions || options["read"];
672
+ options["owner"] = evaluatorFunctionTarget || options["owner"];
673
+ }
674
+ // By here, "options" is always non-null
675
+
676
+ if (typeof options["read"] != "function")
677
+ throw "Pass a function that returns the value of the dependentObservable";
678
+
679
+ var _subscriptionsToDependencies = [];
680
+ function disposeAllSubscriptionsToDependencies() {
681
+ ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
682
+ subscription.dispose();
683
+ });
684
+ _subscriptionsToDependencies = [];
685
+ }
686
+
687
+ function replaceSubscriptionsToDependencies(newDependencies) {
688
+ disposeAllSubscriptionsToDependencies();
689
+ ko.utils.arrayForEach(newDependencies, function (dependency) {
690
+ _subscriptionsToDependencies.push(dependency.subscribe(evaluate));
691
+ });
692
+ };
693
+
694
+ var _latestValue, _hasBeenEvaluated = false;
695
+ function evaluate() {
696
+ // Don't dispose on first evaluation, because the "disposeWhen" callback might
697
+ // e.g., dispose when the associated DOM element isn't in the doc, and it's not
698
+ // going to be in the doc until *after* the first evaluation
699
+ if ((_hasBeenEvaluated) && typeof options["disposeWhen"] == "function") {
700
+ if (options["disposeWhen"]()) {
701
+ dependentObservable.dispose();
702
+ return;
703
+ }
704
+ }
705
+
706
+ try {
707
+ ko.dependencyDetection.begin();
708
+ _latestValue = options["owner"] ? options["read"].call(options["owner"]) : options["read"]();
709
+ } finally {
710
+ var distinctDependencies = ko.utils.arrayGetDistinctValues(ko.dependencyDetection.end());
711
+ replaceSubscriptionsToDependencies(distinctDependencies);
712
+ }
713
+
714
+ dependentObservable.notifySubscribers(_latestValue);
715
+ _hasBeenEvaluated = true;
716
+ }
717
+
718
+ function dependentObservable() {
719
+ if (arguments.length > 0) {
720
+ if (typeof options["write"] === "function") {
721
+ // Writing a value
722
+ var valueToWrite = arguments[0];
723
+ options["owner"] ? options["write"].call(options["owner"], valueToWrite) : options["write"](valueToWrite);
724
+ } else {
725
+ throw "Cannot write a value to a dependentObservable unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.";
726
+ }
727
+ } else {
728
+ // Reading the value
729
+ if (!_hasBeenEvaluated)
730
+ evaluate();
731
+ ko.dependencyDetection.registerDependency(dependentObservable);
732
+ return _latestValue;
733
+ }
734
+ }
735
+ dependentObservable.__ko_proto__ = ko.dependentObservable;
736
+ dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; }
737
+ dependentObservable.hasWriteFunction = typeof options["write"] === "function";
738
+ dependentObservable.dispose = function () {
739
+ disposeAllSubscriptionsToDependencies();
740
+ };
741
+
742
+ ko.subscribable.call(dependentObservable);
743
+ if (options['deferEvaluation'] !== true)
744
+ evaluate();
745
+
746
+ ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
747
+ ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
748
+
749
+ return dependentObservable;
750
+ };
751
+ ko.dependentObservable.__ko_proto__ = ko.observable;
752
+
753
+ ko.exportSymbol('ko.dependentObservable', ko.dependentObservable);
754
+
755
+ (function() {
756
+ var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
757
+
758
+ ko.toJS = function(rootObject) {
759
+ if (arguments.length == 0)
760
+ throw new Error("When calling ko.toJS, pass the object you want to convert.");
761
+
762
+ // We just unwrap everything at every level in the object graph
763
+ return mapJsObjectGraph(rootObject, function(valueToMap) {
764
+ // Loop because an observable's value might in turn be another observable wrapper
765
+ for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
766
+ valueToMap = valueToMap();
767
+ return valueToMap;
768
+ });
769
+ };
770
+
771
+ ko.toJSON = function(rootObject) {
772
+ var plainJavaScriptObject = ko.toJS(rootObject);
773
+ return ko.utils.stringifyJson(plainJavaScriptObject);
774
+ };
775
+
776
+ function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
777
+ visitedObjects = visitedObjects || new objectLookup();
778
+
779
+ rootObject = mapInputCallback(rootObject);
780
+ var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined);
781
+ if (!canHaveProperties)
782
+ return rootObject;
783
+
784
+ var outputProperties = rootObject instanceof Array ? [] : {};
785
+ visitedObjects.save(rootObject, outputProperties);
786
+
787
+ visitPropertiesOrArrayEntries(rootObject, function(indexer) {
788
+ var propertyValue = mapInputCallback(rootObject[indexer]);
789
+
790
+ switch (typeof propertyValue) {
791
+ case "boolean":
792
+ case "number":
793
+ case "string":
794
+ case "function":
795
+ outputProperties[indexer] = propertyValue;
796
+ break;
797
+ case "object":
798
+ case "undefined":
799
+ var previouslyMappedValue = visitedObjects.get(propertyValue);
800
+ outputProperties[indexer] = (previouslyMappedValue !== undefined)
801
+ ? previouslyMappedValue
802
+ : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
803
+ break;
804
+ }
805
+ });
806
+
807
+ return outputProperties;
808
+ }
809
+
810
+ function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
811
+ if (rootObject instanceof Array) {
812
+ for (var i = 0; i < rootObject.length; i++)
813
+ visitorCallback(i);
814
+ } else {
815
+ for (var propertyName in rootObject)
816
+ visitorCallback(propertyName);
817
+ }
818
+ };
819
+
820
+ function objectLookup() {
821
+ var keys = [];
822
+ var values = [];
823
+ this.save = function(key, value) {
824
+ var existingIndex = ko.utils.arrayIndexOf(keys, key);
825
+ if (existingIndex >= 0)
826
+ values[existingIndex] = value;
827
+ else {
828
+ keys.push(key);
829
+ values.push(value);
830
+ }
831
+ };
832
+ this.get = function(key) {
833
+ var existingIndex = ko.utils.arrayIndexOf(keys, key);
834
+ return (existingIndex >= 0) ? values[existingIndex] : undefined;
835
+ };
836
+ };
837
+ })();
838
+
839
+ ko.exportSymbol('ko.toJS', ko.toJS);
840
+ ko.exportSymbol('ko.toJSON', ko.toJSON);(function () {
841
+ // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
842
+ // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
843
+ // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
844
+ ko.selectExtensions = {
845
+ readValue : function(element) {
846
+ if (element.tagName == 'OPTION') {
847
+ if (element['__ko__hasDomDataOptionValue__'] === true)
848
+ return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
849
+ return element.getAttribute("value");
850
+ } else if (element.tagName == 'SELECT')
851
+ return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
852
+ else
853
+ return element.value;
854
+ },
855
+
856
+ writeValue: function(element, value) {
857
+ if (element.tagName == 'OPTION') {
858
+ switch(typeof value) {
859
+ case "string":
860
+ case "number":
861
+ ko.utils.domData.cleanNode(element);
862
+ if ('__ko__hasDomDataOptionValue__' in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
863
+ delete element['__ko__hasDomDataOptionValue__'];
864
+ }
865
+ element.value = value;
866
+ break;
867
+ default:
868
+ // Store arbitrary object using DomData
869
+ ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
870
+ element['__ko__hasDomDataOptionValue__'] = true;
871
+ element.value = "";
872
+ break;
873
+ }
874
+ } else if (element.tagName == 'SELECT') {
875
+ for (var i = element.options.length - 1; i >= 0; i--) {
876
+ if (ko.selectExtensions.readValue(element.options[i]) == value) {
877
+ element.selectedIndex = i;
878
+ break;
879
+ }
880
+ }
881
+ } else {
882
+ if ((value === null) || (value === undefined))
883
+ value = "";
884
+ element.value = value;
885
+ }
886
+ }
887
+ };
888
+ })();
889
+
890
+ ko.exportSymbol('ko.selectExtensions', ko.selectExtensions);
891
+ ko.exportSymbol('ko.selectExtensions.readValue', ko.selectExtensions.readValue);
892
+ ko.exportSymbol('ko.selectExtensions.writeValue', ko.selectExtensions.writeValue);
893
+
894
+ ko.jsonExpressionRewriting = (function () {
895
+ var restoreCapturedTokensRegex = /\[ko_token_(\d+)\]/g;
896
+ var javaScriptAssignmentTarget = /^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i;
897
+ var javaScriptReservedWords = ["true", "false"];
898
+
899
+ function restoreTokens(string, tokens) {
900
+ return string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
901
+ return tokens[tokenIndex];
902
+ });
903
+ }
904
+
905
+ function isWriteableValue(expression) {
906
+ if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
907
+ return false;
908
+ return expression.match(javaScriptAssignmentTarget) !== null;
909
+ }
910
+
911
+ return {
912
+ parseJson: function (jsonString) {
913
+ jsonString = ko.utils.stringTrim(jsonString);
914
+ if (jsonString.length < 3)
915
+ return {};
916
+
917
+ // We're going to split on commas, so first extract any blocks that may contain commas other than those at the top level
918
+ var tokens = [];
919
+ var tokenStart = null, tokenEndChar;
920
+ for (var position = jsonString.charAt(0) == "{" ? 1 : 0; position < jsonString.length; position++) {
921
+ var c = jsonString.charAt(position);
922
+ if (tokenStart === null) {
923
+ switch (c) {
924
+ case '"':
925
+ case "'":
926
+ case "/":
927
+ tokenStart = position;
928
+ tokenEndChar = c;
929
+ break;
930
+ case "{":
931
+ tokenStart = position;
932
+ tokenEndChar = "}";
933
+ break;
934
+ case "[":
935
+ tokenStart = position;
936
+ tokenEndChar = "]";
937
+ break;
938
+ }
939
+ } else if (c == tokenEndChar) {
940
+ var token = jsonString.substring(tokenStart, position + 1);
941
+ tokens.push(token);
942
+ var replacement = "[ko_token_" + (tokens.length - 1) + "]";
943
+ jsonString = jsonString.substring(0, tokenStart) + replacement + jsonString.substring(position + 1);
944
+ position -= (token.length - replacement.length);
945
+ tokenStart = null;
946
+ }
947
+ }
948
+
949
+ // Now we can safely split on commas to get the key/value pairs
950
+ var result = {};
951
+ var keyValuePairs = jsonString.split(",");
952
+ for (var i = 0, j = keyValuePairs.length; i < j; i++) {
953
+ var pair = keyValuePairs[i];
954
+ var colonPos = pair.indexOf(":");
955
+ if ((colonPos > 0) && (colonPos < pair.length - 1)) {
956
+ var key = ko.utils.stringTrim(pair.substring(0, colonPos));
957
+ var value = ko.utils.stringTrim(pair.substring(colonPos + 1));
958
+ if (key.charAt(0) == "{")
959
+ key = key.substring(1);
960
+ if (value.charAt(value.length - 1) == "}")
961
+ value = value.substring(0, value.length - 1);
962
+ key = ko.utils.stringTrim(restoreTokens(key, tokens));
963
+ value = ko.utils.stringTrim(restoreTokens(value, tokens));
964
+ result[key] = value;
965
+ }
966
+ }
967
+ return result;
968
+ },
969
+
970
+ insertPropertyAccessorsIntoJson: function (jsonString) {
971
+ var parsed = ko.jsonExpressionRewriting.parseJson(jsonString);
972
+ var propertyAccessorTokens = [];
973
+ for (var key in parsed) {
974
+ var value = parsed[key];
975
+ if (isWriteableValue(value)) {
976
+ if (propertyAccessorTokens.length > 0)
977
+ propertyAccessorTokens.push(", ");
978
+ propertyAccessorTokens.push(key + " : function(__ko_value) { " + value + " = __ko_value; }");
979
+ }
980
+ }
981
+
982
+ if (propertyAccessorTokens.length > 0) {
983
+ var allPropertyAccessors = propertyAccessorTokens.join("");
984
+ jsonString = jsonString + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
985
+ }
986
+
987
+ return jsonString;
988
+ }
989
+ };
990
+ })();
991
+
992
+ ko.exportSymbol('ko.jsonExpressionRewriting', ko.jsonExpressionRewriting);
993
+ ko.exportSymbol('ko.jsonExpressionRewriting.parseJson', ko.jsonExpressionRewriting.parseJson);
994
+ ko.exportSymbol('ko.jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.jsonExpressionRewriting.insertPropertyAccessorsIntoJson);
995
+
996
+ (function () {
997
+ var bindingAttributeName = "data-bind";
998
+ ko.bindingHandlers = {};
999
+
1000
+ function parseBindingAttribute(attributeText, viewModel) {
1001
+ try {
1002
+ var json = " { " + ko.jsonExpressionRewriting.insertPropertyAccessorsIntoJson(attributeText) + " } ";
1003
+ return ko.utils.evalWithinScope(json, viewModel === null ? window : viewModel);
1004
+ } catch (ex) {
1005
+ throw new Error("Unable to parse binding attribute.\nMessage: " + ex + ";\nAttribute value: " + attributeText);
1006
+ }
1007
+ }
1008
+
1009
+ function invokeBindingHandler(handler, element, dataValue, allBindings, viewModel) {
1010
+ handler(element, dataValue, allBindings, viewModel);
1011
+ }
1012
+
1013
+ ko.applyBindingsToNode = function (node, bindings, viewModel) {
1014
+ var isFirstEvaluation = true;
1015
+
1016
+ // Each time the dependentObservable is evaluated (after data changes),
1017
+ // the binding attribute is reparsed so that it can pick out the correct
1018
+ // model properties in the context of the changed data.
1019
+ // DOM event callbacks need to be able to access this changed data,
1020
+ // so we need a single parsedBindings variable (shared by all callbacks
1021
+ // associated with this node's bindings) that all the closures can access.
1022
+ var parsedBindings;
1023
+ function makeValueAccessor(bindingKey) {
1024
+ return function () { return parsedBindings[bindingKey] }
1025
+ }
1026
+ function parsedBindingsAccessor() {
1027
+ return parsedBindings;
1028
+ }
1029
+
1030
+ new ko.dependentObservable(
1031
+ function () {
1032
+ var evaluatedBindings = (typeof bindings == "function") ? bindings() : bindings;
1033
+ parsedBindings = evaluatedBindings || parseBindingAttribute(node.getAttribute(bindingAttributeName), viewModel);
1034
+
1035
+ // First run all the inits, so bindings can register for notification on changes
1036
+ if (isFirstEvaluation) {
1037
+ for (var bindingKey in parsedBindings) {
1038
+ if (ko.bindingHandlers[bindingKey] && typeof ko.bindingHandlers[bindingKey]["init"] == "function")
1039
+ invokeBindingHandler(ko.bindingHandlers[bindingKey]["init"], node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel);
1040
+ }
1041
+ }
1042
+
1043
+ // ... then run all the updates, which might trigger changes even on the first evaluation
1044
+ for (var bindingKey in parsedBindings) {
1045
+ if (ko.bindingHandlers[bindingKey] && typeof ko.bindingHandlers[bindingKey]["update"] == "function")
1046
+ invokeBindingHandler(ko.bindingHandlers[bindingKey]["update"], node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel);
1047
+ }
1048
+ },
1049
+ null,
1050
+ { 'disposeWhen' : function () { return !ko.utils.domNodeIsAttachedToDocument(node); } }
1051
+ );
1052
+ isFirstEvaluation = false;
1053
+ };
1054
+
1055
+ ko.applyBindings = function (viewModel, rootNode) {
1056
+ if (rootNode && (rootNode.nodeType == undefined))
1057
+ throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node (note: this is a breaking change since KO version 1.05)");
1058
+ rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
1059
+
1060
+ var elemsWithBindingAttribute = ko.utils.getElementsHavingAttribute(rootNode, bindingAttributeName);
1061
+ ko.utils.arrayForEach(elemsWithBindingAttribute, function (element) {
1062
+ ko.applyBindingsToNode(element, null, viewModel);
1063
+ });
1064
+ };
1065
+
1066
+ ko.exportSymbol('ko.bindingHandlers', ko.bindingHandlers);
1067
+ ko.exportSymbol('ko.applyBindings', ko.applyBindings);
1068
+ })();
1069
+ ko.bindingHandlers['click'] = {
1070
+ 'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
1071
+ ko.utils.registerEventHandler(element, "click", function (event) {
1072
+ var handlerReturnValue;
1073
+ var value = valueAccessor();
1074
+ try { handlerReturnValue = value.call(viewModel); }
1075
+ finally {
1076
+ if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
1077
+ if (event.preventDefault)
1078
+ event.preventDefault();
1079
+ else
1080
+ event.returnValue = false;
1081
+ }
1082
+ }
1083
+ });
1084
+ }
1085
+ };
1086
+
1087
+ ko.bindingHandlers['submit'] = {
1088
+ 'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
1089
+ if (typeof valueAccessor() != "function")
1090
+ throw new Error("The value for a submit binding must be a function to invoke on submit");
1091
+ ko.utils.registerEventHandler(element, "submit", function (event) {
1092
+ var handlerReturnValue;
1093
+ var value = valueAccessor();
1094
+ try { handlerReturnValue = value.call(viewModel, element); }
1095
+ finally {
1096
+ if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
1097
+ if (event.preventDefault)
1098
+ event.preventDefault();
1099
+ else
1100
+ event.returnValue = false;
1101
+ }
1102
+ }
1103
+ });
1104
+ }
1105
+ };
1106
+
1107
+ ko.bindingHandlers['visible'] = {
1108
+ 'update': function (element, valueAccessor) {
1109
+ var value = ko.utils.unwrapObservable(valueAccessor());
1110
+ var isCurrentlyVisible = !(element.style.display == "none");
1111
+ if (value && !isCurrentlyVisible)
1112
+ element.style.display = "";
1113
+ else if ((!value) && isCurrentlyVisible)
1114
+ element.style.display = "none";
1115
+ }
1116
+ }
1117
+
1118
+ ko.bindingHandlers['enable'] = {
1119
+ 'update': function (element, valueAccessor) {
1120
+ var value = ko.utils.unwrapObservable(valueAccessor());
1121
+ if (value && element.disabled)
1122
+ element.removeAttribute("disabled");
1123
+ else if ((!value) && (!element.disabled))
1124
+ element.disabled = true;
1125
+ }
1126
+ };
1127
+
1128
+ ko.bindingHandlers['disable'] = {
1129
+ 'update': function (element, valueAccessor) {
1130
+ ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
1131
+ }
1132
+ };
1133
+
1134
+ ko.bindingHandlers['value'] = {
1135
+ 'init': function (element, valueAccessor, allBindingsAccessor) {
1136
+ var eventName = allBindingsAccessor()["valueUpdate"] || "change";
1137
+
1138
+ // The syntax "after<eventname>" means "run the handler asynchronously after the event"
1139
+ // This is useful, for example, to catch "keydown" events after the browser has updated the control
1140
+ // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
1141
+ var handleEventAsynchronously = false;
1142
+ if (ko.utils.stringStartsWith(eventName, "after")) {
1143
+ handleEventAsynchronously = true;
1144
+ eventName = eventName.substring("after".length);
1145
+ }
1146
+ var runEventHandler = handleEventAsynchronously ? function(handler) { setTimeout(handler, 0) }
1147
+ : function(handler) { handler() };
1148
+
1149
+ ko.utils.registerEventHandler(element, eventName, function () {
1150
+ runEventHandler(function() {
1151
+ var modelValue = valueAccessor();
1152
+ var elementValue = ko.selectExtensions.readValue(element);
1153
+ if (ko.isWriteableObservable(modelValue))
1154
+ modelValue(elementValue);
1155
+ else {
1156
+ var allBindings = allBindingsAccessor();
1157
+ if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['value'])
1158
+ allBindings['_ko_property_writers']['value'](elementValue);
1159
+ }
1160
+ });
1161
+ });
1162
+ },
1163
+ 'update': function (element, valueAccessor) {
1164
+ var newValue = ko.utils.unwrapObservable(valueAccessor());
1165
+ var elementValue = ko.selectExtensions.readValue(element);
1166
+ var valueHasChanged = (newValue != elementValue);
1167
+
1168
+ // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
1169
+ // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
1170
+ if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
1171
+ valueHasChanged = true;
1172
+
1173
+ if (valueHasChanged) {
1174
+ var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
1175
+ applyValueAction();
1176
+
1177
+ // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
1178
+ // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
1179
+ // to apply the value as well.
1180
+ var alsoApplyAsynchronously = element.tagName == "SELECT";
1181
+ if (alsoApplyAsynchronously)
1182
+ setTimeout(applyValueAction, 0);
1183
+ }
1184
+
1185
+ // For SELECT nodes, you're not allowed to have a model value that disagrees with the UI selection, so if there is a
1186
+ // difference, treat it as a change that should be written back to the model
1187
+ if (element.tagName == "SELECT") {
1188
+ elementValue = ko.selectExtensions.readValue(element);
1189
+ if(elementValue !== newValue)
1190
+ ko.utils.triggerEvent(element, "change");
1191
+ }
1192
+ }
1193
+ };
1194
+
1195
+ ko.bindingHandlers['options'] = {
1196
+ 'update': function (element, valueAccessor, allBindingsAccessor) {
1197
+ if (element.tagName != "SELECT")
1198
+ throw new Error("options binding applies only to SELECT elements");
1199
+
1200
+ var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
1201
+ return node.tagName && node.tagName == "OPTION" && node.selected;
1202
+ }), function (node) {
1203
+ return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
1204
+ });
1205
+ var previousScrollTop = element.scrollTop;
1206
+
1207
+ var value = ko.utils.unwrapObservable(valueAccessor());
1208
+ var selectedValue = element.value;
1209
+ ko.utils.emptyDomNode(element);
1210
+
1211
+ if (value) {
1212
+ var allBindings = allBindingsAccessor();
1213
+ if (typeof value.length != "number")
1214
+ value = [value];
1215
+ if (allBindings['optionsCaption']) {
1216
+ var option = document.createElement("OPTION");
1217
+ option.innerHTML = allBindings['optionsCaption'];
1218
+ ko.selectExtensions.writeValue(option, undefined);
1219
+ element.appendChild(option);
1220
+ }
1221
+ for (var i = 0, j = value.length; i < j; i++) {
1222
+ var option = document.createElement("OPTION");
1223
+ var optionValue = typeof allBindings['optionsValue'] == "string" ? value[i][allBindings['optionsValue']] : value[i];
1224
+ var optionText = typeof allBindings['optionsText'] == "string" ? value[i][allBindings['optionsText']] : optionValue;
1225
+ optionValue = ko.utils.unwrapObservable(optionValue);
1226
+ optionText = ko.utils.unwrapObservable(optionText);
1227
+ ko.selectExtensions.writeValue(option, optionValue);
1228
+ option.innerHTML = optionText.toString();
1229
+ element.appendChild(option);
1230
+ }
1231
+
1232
+ // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
1233
+ // That's why we first added them without selection. Now it's time to set the selection.
1234
+ var newOptions = element.getElementsByTagName("OPTION");
1235
+ var countSelectionsRetained = 0;
1236
+ for (var i = 0, j = newOptions.length; i < j; i++) {
1237
+ if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
1238
+ ko.utils.setOptionNodeSelectionState(newOptions[i], true);
1239
+ countSelectionsRetained++;
1240
+ }
1241
+ }
1242
+
1243
+ if (previousScrollTop)
1244
+ element.scrollTop = previousScrollTop;
1245
+ }
1246
+ }
1247
+ };
1248
+ ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.bindingHandlers.options.optionValueDomData__';
1249
+
1250
+ ko.bindingHandlers['selectedOptions'] = {
1251
+ getSelectedValuesFromSelectNode: function (selectNode) {
1252
+ var result = [];
1253
+ var nodes = selectNode.childNodes;
1254
+ for (var i = 0, j = nodes.length; i < j; i++) {
1255
+ var node = nodes[i];
1256
+ if ((node.tagName == "OPTION") && node.selected)
1257
+ result.push(ko.selectExtensions.readValue(node));
1258
+ }
1259
+ return result;
1260
+ },
1261
+ 'init': function (element, valueAccessor, allBindingsAccessor) {
1262
+ ko.utils.registerEventHandler(element, "change", function () {
1263
+ var value = valueAccessor();
1264
+ if (ko.isWriteableObservable(value))
1265
+ value(ko.bindingHandlers['selectedOptions'].getSelectedValuesFromSelectNode(this));
1266
+ else {
1267
+ var allBindings = allBindingsAccessor();
1268
+ if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['value'])
1269
+ allBindings['_ko_property_writers']['value'](ko.bindingHandlers['selectedOptions'].getSelectedValuesFromSelectNode(this));
1270
+ }
1271
+ });
1272
+ },
1273
+ 'update': function (element, valueAccessor) {
1274
+ if (element.tagName != "SELECT")
1275
+ throw new Error("values binding applies only to SELECT elements");
1276
+
1277
+ var newValue = ko.utils.unwrapObservable(valueAccessor());
1278
+ if (newValue && typeof newValue.length == "number") {
1279
+ var nodes = element.childNodes;
1280
+ for (var i = 0, j = nodes.length; i < j; i++) {
1281
+ var node = nodes[i];
1282
+ if (node.tagName == "OPTION")
1283
+ ko.utils.setOptionNodeSelectionState(node, ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0);
1284
+ }
1285
+ }
1286
+ }
1287
+ };
1288
+
1289
+ ko.bindingHandlers['text'] = {
1290
+ 'update': function (element, valueAccessor) {
1291
+ var value = ko.utils.unwrapObservable(valueAccessor());
1292
+ if ((value === null) || (value === undefined))
1293
+ value = "";
1294
+ typeof element.innerText == "string" ? element.innerText = value
1295
+ : element.textContent = value;
1296
+ }
1297
+ };
1298
+
1299
+ ko.bindingHandlers['css'] = {
1300
+ 'update': function (element, valueAccessor) {
1301
+ var value = ko.utils.unwrapObservable(valueAccessor() || {});
1302
+ for (var className in value) {
1303
+ if (typeof className == "string") {
1304
+ var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
1305
+ ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
1306
+ }
1307
+ }
1308
+ }
1309
+ };
1310
+
1311
+ ko.bindingHandlers['style'] = {
1312
+ 'update': function (element, valueAccessor) {
1313
+ var value = ko.utils.unwrapObservable(valueAccessor() || {});
1314
+ for (var styleName in value) {
1315
+ if (typeof styleName == "string") {
1316
+ var styleValue = ko.utils.unwrapObservable(value[styleName]);
1317
+ element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
1318
+ }
1319
+ }
1320
+ }
1321
+ };
1322
+
1323
+ ko.bindingHandlers['uniqueName'] = {
1324
+ 'init': function (element, valueAccessor) {
1325
+ if (valueAccessor()) {
1326
+ element.name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
1327
+
1328
+ // Workaround IE 6 issue - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
1329
+ if (ko.utils.isIe6)
1330
+ element.mergeAttributes(document.createElement("<INPUT name='" + element.name + "'/>"), false);
1331
+ }
1332
+ }
1333
+ };
1334
+ ko.bindingHandlers['uniqueName'].currentIndex = 0;
1335
+
1336
+ ko.bindingHandlers['checked'] = {
1337
+ 'init': function (element, valueAccessor, allBindingsAccessor) {
1338
+ var updateHandler = function() {
1339
+ var valueToWrite;
1340
+ if (element.type == "checkbox") {
1341
+ valueToWrite = element.checked;
1342
+ } else if ((element.type == "radio") && (element.checked)) {
1343
+ valueToWrite = element.value;
1344
+ } else {
1345
+ return; // "checked" binding only responds to checkboxes and selected radio buttons
1346
+ }
1347
+
1348
+ var modelValue = valueAccessor();
1349
+ if (ko.isWriteableObservable(modelValue)) {
1350
+ if (modelValue() !== valueToWrite) { // Suppress repeated events when there's nothing new to notify (some browsers raise them)
1351
+ modelValue(valueToWrite);
1352
+ }
1353
+ } else {
1354
+ var allBindings = allBindingsAccessor();
1355
+ if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['checked']) {
1356
+ allBindings['_ko_property_writers']['checked'](valueToWrite);
1357
+ }
1358
+ }
1359
+ };
1360
+ ko.utils.registerEventHandler(element, "change", updateHandler);
1361
+ ko.utils.registerEventHandler(element, "click", updateHandler);
1362
+
1363
+ // IE 6 won't allow radio buttons to be selected unless they have a name
1364
+ if ((element.type == "radio") && !element.name)
1365
+ ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
1366
+ },
1367
+ 'update': function (element, valueAccessor) {
1368
+ var value = ko.utils.unwrapObservable(valueAccessor());
1369
+
1370
+ if (element.type == "checkbox") {
1371
+ element.checked = value;
1372
+
1373
+ // Workaround for IE 6 bug - it fails to apply checked state to dynamically-created checkboxes if you merely say "element.checked = true"
1374
+ if (value && ko.utils.isIe6)
1375
+ element.mergeAttributes(document.createElement("<INPUT type='checkbox' checked='checked' />"), false);
1376
+ } else if (element.type == "radio") {
1377
+ element.checked = (element.value == value);
1378
+
1379
+ // Workaround for IE 6/7 bug - it fails to apply checked state to dynamically-created radio buttons if you merely say "element.checked = true"
1380
+ if ((element.value == value) && (ko.utils.isIe6 || ko.utils.isIe7))
1381
+ element.mergeAttributes(document.createElement("<INPUT type='radio' checked='checked' />"), false);
1382
+ }
1383
+ }
1384
+ };
1385
+ ko.templateEngine = function () {
1386
+ this['renderTemplate'] = function (templateName, data, options) {
1387
+ throw "Override renderTemplate in your ko.templateEngine subclass";
1388
+ },
1389
+ this['isTemplateRewritten'] = function (templateName) {
1390
+ throw "Override isTemplateRewritten in your ko.templateEngine subclass";
1391
+ },
1392
+ this['rewriteTemplate'] = function (templateName, rewriterCallback) {
1393
+ throw "Override rewriteTemplate in your ko.templateEngine subclass";
1394
+ },
1395
+ this['createJavaScriptEvaluatorBlock'] = function (script) {
1396
+ throw "Override createJavaScriptEvaluatorBlock in your ko.templateEngine subclass";
1397
+ }
1398
+ };
1399
+
1400
+ ko.exportSymbol('ko.templateEngine', ko.templateEngine);
1401
+
1402
+ ko.templateRewriting = (function () {
1403
+ var memoizeBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/g;
1404
+
1405
+ return {
1406
+ ensureTemplateIsRewritten: function (template, templateEngine) {
1407
+ if (!templateEngine['isTemplateRewritten'](template))
1408
+ templateEngine['rewriteTemplate'](template, function (htmlString) {
1409
+ return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
1410
+ });
1411
+ },
1412
+
1413
+ memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
1414
+ return htmlString.replace(memoizeBindingAttributeSyntaxRegex, function () {
1415
+ var tagToRetain = arguments[1];
1416
+ var dataBindAttributeValue = arguments[6];
1417
+
1418
+ dataBindAttributeValue = ko.jsonExpressionRewriting.insertPropertyAccessorsIntoJson(dataBindAttributeValue);
1419
+
1420
+ // For no obvious reason, Opera fails to evaluate dataBindAttributeValue unless it's wrapped in an additional anonymous function,
1421
+ // even though Opera's built-in debugger can evaluate it anyway. No other browser requires this extra indirection.
1422
+ var applyBindingsToNextSiblingScript = "ko.templateRewriting.applyMemoizedBindingsToNextSibling(function() { \
1423
+ return (function() { return { " + dataBindAttributeValue + " } })() \
1424
+ })";
1425
+ return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
1426
+ });
1427
+ },
1428
+
1429
+ applyMemoizedBindingsToNextSibling: function (bindings) {
1430
+ return ko.memoization.memoize(function (domNode, viewModel) {
1431
+ if (domNode.nextSibling)
1432
+ ko.applyBindingsToNode(domNode.nextSibling, bindings, viewModel);
1433
+ });
1434
+ }
1435
+ }
1436
+ })();
1437
+
1438
+ ko.exportSymbol('ko.templateRewriting', ko.templateRewriting);
1439
+ ko.exportSymbol('ko.templateRewriting.applyMemoizedBindingsToNextSibling', ko.templateRewriting.applyMemoizedBindingsToNextSibling); // Exported only because it has to be referenced by string lookup from within rewritten template
1440
+
1441
+ (function () {
1442
+ var _templateEngine;
1443
+ ko.setTemplateEngine = function (templateEngine) {
1444
+ if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
1445
+ throw "templateEngine must inherit from ko.templateEngine";
1446
+ _templateEngine = templateEngine;
1447
+ }
1448
+
1449
+ function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
1450
+ return nodeOrNodeArray.nodeType ? nodeOrNodeArray
1451
+ : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
1452
+ : null;
1453
+ }
1454
+
1455
+ function executeTemplate(targetNodeOrNodeArray, renderMode, template, data, options) {
1456
+ var dataForTemplate = ko.utils.unwrapObservable(data);
1457
+
1458
+ options = options || {};
1459
+ var templateEngineToUse = (options['templateEngine'] || _templateEngine);
1460
+ ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse);
1461
+ var renderedNodesArray = templateEngineToUse['renderTemplate'](template, dataForTemplate, options);
1462
+
1463
+ // Loosely check result is an array of DOM nodes
1464
+ if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
1465
+ throw "Template engine must return an array of DOM nodes";
1466
+
1467
+ if (renderedNodesArray)
1468
+ ko.utils.arrayForEach(renderedNodesArray, function (renderedNode) {
1469
+ ko.memoization.unmemoizeDomNodeAndDescendants(renderedNode, [data]);
1470
+ });
1471
+
1472
+ switch (renderMode) {
1473
+ case "replaceChildren": ko.utils.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray); break;
1474
+ case "replaceNode": ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray); break;
1475
+ case "ignoreTargetNode": break;
1476
+ default: throw new Error("Unknown renderMode: " + renderMode);
1477
+ }
1478
+
1479
+ if (options['afterRender'])
1480
+ options['afterRender'](renderedNodesArray, data);
1481
+
1482
+ return renderedNodesArray;
1483
+ }
1484
+
1485
+ ko.renderTemplate = function (template, data, options, targetNodeOrNodeArray, renderMode) {
1486
+ options = options || {};
1487
+ if ((options['templateEngine'] || _templateEngine) == undefined)
1488
+ throw "Set a template engine before calling renderTemplate";
1489
+ renderMode = renderMode || "replaceChildren";
1490
+
1491
+ if (targetNodeOrNodeArray) {
1492
+ var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
1493
+ var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); };
1494
+ return new ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
1495
+ function () {
1496
+ var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, template, data, options);
1497
+ if (renderMode == "replaceNode") {
1498
+ targetNodeOrNodeArray = renderedNodesArray;
1499
+ firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
1500
+ }
1501
+ },
1502
+ null,
1503
+ { 'disposeWhen': whenToDispose }
1504
+ );
1505
+ } else {
1506
+ // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
1507
+ return ko.memoization.memoize(function (domNode) {
1508
+ ko.renderTemplate(template, data, options, domNode, "replaceNode");
1509
+ });
1510
+ }
1511
+ };
1512
+
1513
+ ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode) {
1514
+ var whenToDispose = function () { return !ko.utils.domNodeIsAttachedToDocument(targetNode); };
1515
+
1516
+ new ko.dependentObservable(function () {
1517
+ var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
1518
+ if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
1519
+ unwrappedArray = [unwrappedArray];
1520
+
1521
+ // Filter out any entries marked as destroyed
1522
+ var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
1523
+ return options['includeDestroyed'] || !item['_destroy'];
1524
+ });
1525
+
1526
+ ko.utils.setDomNodeChildrenFromArrayMapping(targetNode, filteredArray, function (arrayValue) {
1527
+ return executeTemplate(null, "ignoreTargetNode", template, arrayValue, options);
1528
+ }, options);
1529
+ }, null, { 'disposeWhen': whenToDispose });
1530
+ };
1531
+
1532
+ ko.bindingHandlers['template'] = {
1533
+ 'update': function (element, valueAccessor, allBindingsAccessor, viewModel) {
1534
+ var bindingValue = ko.utils.unwrapObservable(valueAccessor());
1535
+ var templateName = typeof bindingValue == "string" ? bindingValue : bindingValue.name;
1536
+
1537
+ if (typeof bindingValue['foreach'] != "undefined") {
1538
+ // Render once for each data point
1539
+ ko.renderTemplateForEach(templateName, bindingValue['foreach'] || [], { 'afterAdd': bindingValue['afterAdd'], 'beforeRemove': bindingValue['beforeRemove'], 'includeDestroyed': bindingValue['includeDestroyed'], 'afterRender': bindingValue['afterRender'] }, element);
1540
+ }
1541
+ else {
1542
+ // Render once for this single data point (or use the viewModel if no data was provided)
1543
+ var templateData = bindingValue['data'];
1544
+ ko.renderTemplate(templateName, typeof templateData == "undefined" ? viewModel : templateData, { 'afterRender': bindingValue['afterRender'] }, element);
1545
+ }
1546
+ }
1547
+ };
1548
+ })();
1549
+
1550
+ ko.exportSymbol('ko.setTemplateEngine', ko.setTemplateEngine);
1551
+ ko.exportSymbol('ko.renderTemplate', ko.renderTemplate);
1552
+
1553
+ (function () {
1554
+ // Simple calculation based on Levenshtein distance.
1555
+ function calculateEditDistanceMatrix(oldArray, newArray, maxAllowedDistance) {
1556
+ var distances = [];
1557
+ for (var i = 0; i <= newArray.length; i++)
1558
+ distances[i] = [];
1559
+
1560
+ // Top row - transform old array into empty array via deletions
1561
+ for (var i = 0, j = Math.min(oldArray.length, maxAllowedDistance); i <= j; i++)
1562
+ distances[0][i] = i;
1563
+
1564
+ // Left row - transform empty array into new array via additions
1565
+ for (var i = 1, j = Math.min(newArray.length, maxAllowedDistance); i <= j; i++) {
1566
+ distances[i][0] = i;
1567
+ }
1568
+
1569
+ // Fill out the body of the array
1570
+ var oldIndex, oldIndexMax = oldArray.length, newIndex, newIndexMax = newArray.length;
1571
+ var distanceViaAddition, distanceViaDeletion;
1572
+ for (oldIndex = 1; oldIndex <= oldIndexMax; oldIndex++) {
1573
+ var newIndexMinForRow = Math.max(1, oldIndex - maxAllowedDistance);
1574
+ var newIndexMaxForRow = Math.min(newIndexMax, oldIndex + maxAllowedDistance);
1575
+ for (newIndex = newIndexMinForRow; newIndex <= newIndexMaxForRow; newIndex++) {
1576
+ if (oldArray[oldIndex - 1] === newArray[newIndex - 1])
1577
+ distances[newIndex][oldIndex] = distances[newIndex - 1][oldIndex - 1];
1578
+ else {
1579
+ var northDistance = distances[newIndex - 1][oldIndex] === undefined ? Number.MAX_VALUE : distances[newIndex - 1][oldIndex] + 1;
1580
+ var westDistance = distances[newIndex][oldIndex - 1] === undefined ? Number.MAX_VALUE : distances[newIndex][oldIndex - 1] + 1;
1581
+ distances[newIndex][oldIndex] = Math.min(northDistance, westDistance);
1582
+ }
1583
+ }
1584
+ }
1585
+
1586
+ return distances;
1587
+ }
1588
+
1589
+ function findEditScriptFromEditDistanceMatrix(editDistanceMatrix, oldArray, newArray) {
1590
+ var oldIndex = oldArray.length;
1591
+ var newIndex = newArray.length;
1592
+ var editScript = [];
1593
+ var maxDistance = editDistanceMatrix[newIndex][oldIndex];
1594
+ if (maxDistance === undefined)
1595
+ return null; // maxAllowedDistance must be too small
1596
+ while ((oldIndex > 0) || (newIndex > 0)) {
1597
+ var me = editDistanceMatrix[newIndex][oldIndex];
1598
+ var distanceViaAdd = (newIndex > 0) ? editDistanceMatrix[newIndex - 1][oldIndex] : maxDistance + 1;
1599
+ var distanceViaDelete = (oldIndex > 0) ? editDistanceMatrix[newIndex][oldIndex - 1] : maxDistance + 1;
1600
+ var distanceViaRetain = (newIndex > 0) && (oldIndex > 0) ? editDistanceMatrix[newIndex - 1][oldIndex - 1] : maxDistance + 1;
1601
+ if ((distanceViaAdd === undefined) || (distanceViaAdd < me - 1)) distanceViaAdd = maxDistance + 1;
1602
+ if ((distanceViaDelete === undefined) || (distanceViaDelete < me - 1)) distanceViaDelete = maxDistance + 1;
1603
+ if (distanceViaRetain < me - 1) distanceViaRetain = maxDistance + 1;
1604
+
1605
+ if ((distanceViaAdd <= distanceViaDelete) && (distanceViaAdd < distanceViaRetain)) {
1606
+ editScript.push({ status: "added", value: newArray[newIndex - 1] });
1607
+ newIndex--;
1608
+ } else if ((distanceViaDelete < distanceViaAdd) && (distanceViaDelete < distanceViaRetain)) {
1609
+ editScript.push({ status: "deleted", value: oldArray[oldIndex - 1] });
1610
+ oldIndex--;
1611
+ } else {
1612
+ editScript.push({ status: "retained", value: oldArray[oldIndex - 1] });
1613
+ newIndex--;
1614
+ oldIndex--;
1615
+ }
1616
+ }
1617
+ return editScript.reverse();
1618
+ }
1619
+
1620
+ ko.utils.compareArrays = function (oldArray, newArray, maxEditsToConsider) {
1621
+ if (maxEditsToConsider === undefined) {
1622
+ return ko.utils.compareArrays(oldArray, newArray, 1) // First consider likely case where there is at most one edit (very fast)
1623
+ || ko.utils.compareArrays(oldArray, newArray, 10) // If that fails, account for a fair number of changes while still being fast
1624
+ || ko.utils.compareArrays(oldArray, newArray, Number.MAX_VALUE); // Ultimately give the right answer, even though it may take a long time
1625
+ } else {
1626
+ oldArray = oldArray || [];
1627
+ newArray = newArray || [];
1628
+ var editDistanceMatrix = calculateEditDistanceMatrix(oldArray, newArray, maxEditsToConsider);
1629
+ return findEditScriptFromEditDistanceMatrix(editDistanceMatrix, oldArray, newArray);
1630
+ }
1631
+ };
1632
+ })();
1633
+
1634
+ ko.exportSymbol('ko.utils.compareArrays', ko.utils.compareArrays);
1635
+
1636
+ (function () {
1637
+ // Objective:
1638
+ // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
1639
+ // map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
1640
+ // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
1641
+ // so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
1642
+ // previously mapped - retain those nodes, and just insert/delete other ones
1643
+
1644
+ function mapNodeAndRefreshWhenChanged(mapping, valueToMap) {
1645
+ // Map this array value inside a dependentObservable so we re-map when any dependency changes
1646
+ var mappedNodes = [];
1647
+ ko.dependentObservable(function() {
1648
+ var newMappedNodes = mapping(valueToMap) || [];
1649
+
1650
+ // On subsequent evaluations, just replace the previously-inserted DOM nodes
1651
+ if (mappedNodes.length > 0)
1652
+ ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);
1653
+
1654
+ // Replace the contents of the mappedNodes array, thereby updating the record
1655
+ // of which nodes would be deleted if valueToMap was itself later removed
1656
+ mappedNodes.splice(0, mappedNodes.length);
1657
+ ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
1658
+ }, null, { 'disposeWhen': function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
1659
+ return mappedNodes;
1660
+ }
1661
+
1662
+ ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options) {
1663
+ // Compare the provided array against the previous one
1664
+ array = array || [];
1665
+ options = options || {};
1666
+ var isFirstExecution = ko.utils.domData.get(domNode, "setDomNodeChildrenFromArrayMapping_lastMappingResult") === undefined;
1667
+ var lastMappingResult = ko.utils.domData.get(domNode, "setDomNodeChildrenFromArrayMapping_lastMappingResult") || [];
1668
+ var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
1669
+ var editScript = ko.utils.compareArrays(lastArray, array);
1670
+
1671
+ // Build the new mapping result
1672
+ var newMappingResult = [];
1673
+ var lastMappingResultIndex = 0;
1674
+ var nodesToDelete = [];
1675
+ var nodesAdded = [];
1676
+ var insertAfterNode = null;
1677
+ for (var i = 0, j = editScript.length; i < j; i++) {
1678
+ switch (editScript[i].status) {
1679
+ case "retained":
1680
+ // Just keep the information - don't touch the nodes
1681
+ var dataToRetain = lastMappingResult[lastMappingResultIndex];
1682
+ newMappingResult.push(dataToRetain);
1683
+ if (dataToRetain.domNodes.length > 0)
1684
+ insertAfterNode = dataToRetain.domNodes[dataToRetain.domNodes.length - 1];
1685
+ lastMappingResultIndex++;
1686
+ break;
1687
+
1688
+ case "deleted":
1689
+ // Queue these nodes for later removal
1690
+ ko.utils.arrayForEach(lastMappingResult[lastMappingResultIndex].domNodes, function (node) {
1691
+ nodesToDelete.push({
1692
+ element: node,
1693
+ index: i,
1694
+ value: editScript[i].value
1695
+ });
1696
+ insertAfterNode = node;
1697
+ });
1698
+ lastMappingResultIndex++;
1699
+ break;
1700
+
1701
+ case "added":
1702
+ var mappedNodes = mapNodeAndRefreshWhenChanged(mapping, editScript[i].value);
1703
+ // On the first evaluation, insert the nodes at the current insertion point
1704
+ newMappingResult.push({ arrayEntry: editScript[i].value, domNodes: mappedNodes });
1705
+ for (var nodeIndex = 0, nodeIndexMax = mappedNodes.length; nodeIndex < nodeIndexMax; nodeIndex++) {
1706
+ var node = mappedNodes[nodeIndex];
1707
+ nodesAdded.push({
1708
+ element: node,
1709
+ index: i,
1710
+ value: editScript[i].value
1711
+ });
1712
+ if (insertAfterNode == null) {
1713
+ // Insert at beginning
1714
+ if (domNode.firstChild)
1715
+ domNode.insertBefore(node, domNode.firstChild);
1716
+ else
1717
+ domNode.appendChild(node);
1718
+ } else {
1719
+ // Insert after insertion point
1720
+ if (insertAfterNode.nextSibling)
1721
+ domNode.insertBefore(node, insertAfterNode.nextSibling);
1722
+ else
1723
+ domNode.appendChild(node);
1724
+ }
1725
+ insertAfterNode = node;
1726
+ }
1727
+ break;
1728
+ }
1729
+ }
1730
+
1731
+ ko.utils.arrayForEach(nodesToDelete, function (node) { ko.utils.domData.cleanNodeAndDescendants(node.element); });
1732
+
1733
+ var invokedBeforeRemoveCallback = false;
1734
+ if (!isFirstExecution) {
1735
+ if (options['afterAdd']) {
1736
+ for (var i = 0; i < nodesAdded.length; i++)
1737
+ options['afterAdd'](nodesAdded[i].element, nodesAdded[i].index, nodesAdded[i].value);
1738
+ }
1739
+ if (options['beforeRemove']) {
1740
+ for (var i = 0; i < nodesToDelete.length; i++)
1741
+ options['beforeRemove'](nodesToDelete[i].element, nodesToDelete[i].index, nodesToDelete[i].value);
1742
+ invokedBeforeRemoveCallback = true;
1743
+ }
1744
+ }
1745
+ if (!invokedBeforeRemoveCallback)
1746
+ ko.utils.arrayForEach(nodesToDelete, function (node) {
1747
+ if (node.element.parentNode)
1748
+ node.element.parentNode.removeChild(node.element);
1749
+ });
1750
+
1751
+ // Store a copy of the array items we just considered so we can difference it next time
1752
+ ko.utils.domData.set(domNode, "setDomNodeChildrenFromArrayMapping_lastMappingResult", newMappingResult);
1753
+ }
1754
+ })();
1755
+
1756
+ ko.exportSymbol('ko.utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
1757
+
1758
+ ko.jqueryTmplTemplateEngine = function () {
1759
+ // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
1760
+ // doesn't expose a version number, so we have to infer it.
1761
+ this.jQueryTmplVersion = (function() {
1762
+ if ((typeof(jQuery) == "undefined") || !jQuery['tmpl'])
1763
+ return 0;
1764
+ if (jQuery['tmpl']['tag'])
1765
+ return 2; // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
1766
+ return 1;
1767
+ })();
1768
+
1769
+ function getTemplateNode(template) {
1770
+ var templateNode = document.getElementById(template);
1771
+ if (templateNode == null)
1772
+ throw new Error("Cannot find template with ID=" + template);
1773
+ return templateNode;
1774
+ }
1775
+
1776
+ // These two only needed for jquery-tmpl v1
1777
+ var aposMarker = "__ko_apos__";
1778
+ var aposRegex = new RegExp(aposMarker, "g");
1779
+
1780
+ this['renderTemplate'] = function (template, data, options) {
1781
+ if (this.jQueryTmplVersion == 0)
1782
+ throw new Error("jquery.tmpl not detected.\nTo use KO's default template engine, reference jQuery and jquery.tmpl. See Knockout installation documentation for more details.");
1783
+
1784
+ if (this.jQueryTmplVersion == 1) {
1785
+ // jquery.tmpl v1 doesn't like it if the template returns just text content or nothing - it only likes you to return DOM nodes.
1786
+ // To make things more flexible, we can wrap the whole template in a <script> node so that jquery.tmpl just processes it as
1787
+ // text and doesn't try to parse the output. Then, since jquery.tmpl has jQuery as a dependency anyway, we can use jQuery to
1788
+ // parse that text into a document fragment using jQuery.clean().
1789
+ var templateTextInWrapper = "<script type=\"text/html\">" + getTemplateNode(template).text + "</script>";
1790
+ var renderedMarkupInWrapper = jQuery['tmpl'](templateTextInWrapper, data);
1791
+ var renderedMarkup = renderedMarkupInWrapper[0].text.replace(aposRegex, "'");;
1792
+ return jQuery['clean']([renderedMarkup], document);
1793
+ }
1794
+
1795
+ // It's easier with jquery.tmpl v2 and later - it handles any DOM structure
1796
+ data = [data]; // Prewrap the data in an array to stop jquery-tmpl from trying to unwrap any arrays
1797
+ var templateText = getTemplateNode(template).text;
1798
+ return jQuery['tmpl'](templateText, data);
1799
+ },
1800
+
1801
+ this['isTemplateRewritten'] = function (template) {
1802
+ return getTemplateNode(template).isRewritten === true;
1803
+ },
1804
+
1805
+ this['rewriteTemplate'] = function (template, rewriterCallback) {
1806
+ var templateNode = getTemplateNode(template);
1807
+ var rewritten = rewriterCallback(templateNode.text);
1808
+
1809
+ if (this.jQueryTmplVersion == 1) {
1810
+ // jquery.tmpl v1 falls over if you use single-quotes, so replace these with a temporary marker for template rendering,
1811
+ // and then replace back after the template was rendered. This is slightly complicated by the fact that we must not interfere
1812
+ // with any code blocks - only replace apos characters outside code blocks.
1813
+ rewritten = ko.utils.stringTrim(rewritten);
1814
+ rewritten = rewritten.replace(/([\s\S]*?)(\${[\s\S]*?}|{{[\=a-z][\s\S]*?}}|$)/g, function(match) {
1815
+ // Called for each non-code-block followed by a code block (or end of template)
1816
+ var nonCodeSnippet = arguments[1];
1817
+ var codeSnippet = arguments[2];
1818
+ return nonCodeSnippet.replace(/\'/g, aposMarker) + codeSnippet;
1819
+ });
1820
+ }
1821
+
1822
+ templateNode.text = rewritten;
1823
+ templateNode.isRewritten = true;
1824
+ },
1825
+
1826
+ this['createJavaScriptEvaluatorBlock'] = function (script) {
1827
+ if (this.jQueryTmplVersion == 1)
1828
+ return "{{= " + script + "}}";
1829
+
1830
+ // From v2, jquery-tmpl does some parameter parsing that fails on nontrivial expressions.
1831
+ // Prevent it from messing with the code by wrapping it in a further function.
1832
+ return "{{ko_code ((function() { return " + script + " })()) }}";
1833
+ },
1834
+
1835
+ this.addTemplate = function (templateName, templateMarkup) {
1836
+ document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
1837
+ }
1838
+ ko.exportProperty(this, 'addTemplate', this.addTemplate);
1839
+
1840
+ if (this.jQueryTmplVersion > 1) {
1841
+ jQuery['tmpl']['tag']['ko_code'] = {
1842
+ open: "_.push($1 || '');"
1843
+ };
1844
+ }
1845
+ };
1846
+
1847
+ ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
1848
+
1849
+ // Use this one by default
1850
+ ko.setTemplateEngine(new ko.jqueryTmplTemplateEngine());
1851
+
1852
+ ko.exportSymbol('ko.jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);