kea-rails 1.0.4 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/kea/bindings/child_vm.js +1 -1
- data/app/assets/javascripts/kea/components/confirmation_button.js +32 -0
- data/app/assets/javascripts/kea/kea.js +1 -0
- data/app/assets/javascripts/kea/kea_dependencies.js +1 -1
- data/app/helpers/kea/application_helper.rb +17 -1
- data/lib/kea-rails/version.rb +1 -1
- data/vendor/assets/javascripts/{knockout-3.2.0-debug.js → knockout-3.3.0-debug.js} +398 -222
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7114b9b4ade204e3dea3a496fc050fcc98ee6835
|
4
|
+
data.tar.gz: 27deae513503b4b475116bb20b8de56440d4f362
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0f71e1f6bdc2abf06dcb32a88b30087c10b9e6182410ce7da262deec6afd977dbbec2ddab5cefd839581c6de7c76fdef48aba2bba3bb529c244ae16722aa098
|
7
|
+
data.tar.gz: a76dcd363f6f31f0545ce798f78dfd78b0200b85f6b93a7ade1a59e6e839eb3ed68196dcf0a6fdf3fd5af5146fff2bbfb7b7d1a4218525249fef14b492fe90b1
|
@@ -0,0 +1,32 @@
|
|
1
|
+
(function(ko, $) {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
ko.components.register('confirmation-button', {
|
5
|
+
viewModel: function(params) {
|
6
|
+
this.text = ko.observable(params.initialText || '');
|
7
|
+
this.css = params.css || '';
|
8
|
+
},
|
9
|
+
template: '<!-- ko template: { nodes: $componentTemplateNodes } --><!-- /ko -->'
|
10
|
+
});
|
11
|
+
|
12
|
+
})(ko, $);
|
13
|
+
|
14
|
+
(function(ko, $) {
|
15
|
+
"use strict";
|
16
|
+
|
17
|
+
ko.components.register('confirmation-button', {
|
18
|
+
viewModel: {
|
19
|
+
createViewModel: function createViewModel(params, componentInfo) {
|
20
|
+
var ConfirmationButtonVm;
|
21
|
+
|
22
|
+
ConfirmationButtonVm = function ConfirmationButtonVm(params) {
|
23
|
+
|
24
|
+
};
|
25
|
+
|
26
|
+
return new ConfirmationButtonVm(params);
|
27
|
+
}
|
28
|
+
},
|
29
|
+
template: 'x'
|
30
|
+
});
|
31
|
+
|
32
|
+
})(ko, $);
|
@@ -12,7 +12,9 @@ module Kea
|
|
12
12
|
options[:scope] ||= self
|
13
13
|
options[:url_options] ||= url_options
|
14
14
|
|
15
|
-
target.active_model_serializer
|
15
|
+
serializer = options[:serializer] || target.active_model_serializer
|
16
|
+
|
17
|
+
serializer.new(target, options).to_json
|
16
18
|
end
|
17
19
|
|
18
20
|
def cache_json(object, path = nil, options = {})
|
@@ -25,6 +27,20 @@ module Kea
|
|
25
27
|
content_for :json_cache, "window.app.cache['#{path}'] = #{content};\n".html_safe
|
26
28
|
end
|
27
29
|
|
30
|
+
def knockout_template(name, partial: nil, &block)
|
31
|
+
content_for :knockout_templates do
|
32
|
+
if partial
|
33
|
+
content_tag :script, type: "text/html", id: name do
|
34
|
+
render partial: partial
|
35
|
+
end
|
36
|
+
else
|
37
|
+
content_tag :script, type: "text/html", id: name do
|
38
|
+
capture(&block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
28
44
|
def overlay_template(name, partial: nil, &block)
|
29
45
|
content_for :knockout_templates do
|
30
46
|
if partial
|
data/lib/kea-rails/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* Knockout JavaScript library v3.
|
2
|
+
* Knockout JavaScript library v3.3.0
|
3
3
|
* (c) Steven Sanderson - http://knockoutjs.com/
|
4
4
|
* License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
5
5
|
*/
|
@@ -16,18 +16,17 @@ var DEBUG=true;
|
|
16
16
|
JSON = window["JSON"];
|
17
17
|
(function(factory) {
|
18
18
|
// Support three module loading scenarios
|
19
|
-
if (typeof
|
20
|
-
// [1]
|
21
|
-
var target = module['exports'] || exports; // module.exports is for Node.js
|
22
|
-
factory(target, require);
|
23
|
-
} else if (typeof define === 'function' && define['amd']) {
|
24
|
-
// [2] AMD anonymous module
|
19
|
+
if (typeof define === 'function' && define['amd']) {
|
20
|
+
// [1] AMD anonymous module
|
25
21
|
define(['exports', 'require'], factory);
|
22
|
+
} else if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
|
23
|
+
// [2] CommonJS/Node.js
|
24
|
+
factory(module['exports'] || exports); // module.exports is for Node.js
|
26
25
|
} else {
|
27
26
|
// [3] No module loader (plain <script> tag) - put directly in global namespace
|
28
27
|
factory(window['ko'] = {});
|
29
28
|
}
|
30
|
-
}(function(koExports,
|
29
|
+
}(function(koExports, amdRequire){
|
31
30
|
// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
|
32
31
|
// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
|
33
32
|
var ko = typeof koExports !== 'undefined' ? koExports : {};
|
@@ -46,7 +45,7 @@ ko.exportSymbol = function(koPath, object) {
|
|
46
45
|
ko.exportProperty = function(owner, publicName, object) {
|
47
46
|
owner[publicName] = object;
|
48
47
|
};
|
49
|
-
ko.version = "3.
|
48
|
+
ko.version = "3.3.0";
|
50
49
|
|
51
50
|
ko.exportSymbol('version', ko.version);
|
52
51
|
ko.utils = (function () {
|
@@ -113,6 +112,37 @@ ko.utils = (function () {
|
|
113
112
|
return (inputType == "checkbox") || (inputType == "radio");
|
114
113
|
}
|
115
114
|
|
115
|
+
// For details on the pattern for changing node classes
|
116
|
+
// see: https://github.com/knockout/knockout/issues/1597
|
117
|
+
var cssClassNameRegex = /\S+/g;
|
118
|
+
|
119
|
+
function toggleDomNodeCssClass(node, classNames, shouldHaveClass) {
|
120
|
+
var addOrRemoveFn;
|
121
|
+
if (classNames) {
|
122
|
+
if (typeof node.classList === 'object') {
|
123
|
+
addOrRemoveFn = node.classList[shouldHaveClass ? 'add' : 'remove'];
|
124
|
+
ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
|
125
|
+
addOrRemoveFn.call(node.classList, className);
|
126
|
+
});
|
127
|
+
} else if (typeof node.className['baseVal'] === 'string') {
|
128
|
+
// SVG tag .classNames is an SVGAnimatedString instance
|
129
|
+
toggleObjectClassPropertyString(node.className, 'baseVal', classNames, shouldHaveClass);
|
130
|
+
} else {
|
131
|
+
// node.className ought to be a string.
|
132
|
+
toggleObjectClassPropertyString(node, 'className', classNames, shouldHaveClass);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
function toggleObjectClassPropertyString(obj, prop, classNames, shouldHaveClass) {
|
138
|
+
// obj/prop is either a node/'className' or a SVGAnimatedString/'baseVal'.
|
139
|
+
var currentClassNames = obj[prop].match(cssClassNameRegex) || [];
|
140
|
+
ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
|
141
|
+
ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);
|
142
|
+
});
|
143
|
+
obj[prop] = currentClassNames.join(" ");
|
144
|
+
}
|
145
|
+
|
116
146
|
return {
|
117
147
|
fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
|
118
148
|
|
@@ -226,8 +256,9 @@ ko.utils = (function () {
|
|
226
256
|
// Ensure it's a real array, as we're about to reparent the nodes and
|
227
257
|
// we don't want the underlying collection to change while we're doing that.
|
228
258
|
var nodesArray = ko.utils.makeArray(nodes);
|
259
|
+
var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document;
|
229
260
|
|
230
|
-
var container =
|
261
|
+
var container = templateDocument.createElement('div');
|
231
262
|
for (var i = 0, j = nodesArray.length; i < j; i++) {
|
232
263
|
container.appendChild(ko.cleanNode(nodesArray[i]));
|
233
264
|
}
|
@@ -283,7 +314,7 @@ ko.utils = (function () {
|
|
283
314
|
|
284
315
|
// Rule [A]
|
285
316
|
while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)
|
286
|
-
continuousNodeArray.
|
317
|
+
continuousNodeArray.splice(0, 1);
|
287
318
|
|
288
319
|
// Rule [B]
|
289
320
|
if (continuousNodeArray.length > 1) {
|
@@ -412,16 +443,7 @@ ko.utils = (function () {
|
|
412
443
|
return ko.isObservable(value) ? value.peek() : value;
|
413
444
|
},
|
414
445
|
|
415
|
-
toggleDomNodeCssClass:
|
416
|
-
if (classNames) {
|
417
|
-
var cssClassNameRegex = /\S+/g,
|
418
|
-
currentClassNames = node.className.match(cssClassNameRegex) || [];
|
419
|
-
ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
|
420
|
-
ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);
|
421
|
-
});
|
422
|
-
node.className = currentClassNames.join(" ");
|
423
|
-
}
|
424
|
-
},
|
446
|
+
toggleDomNodeCssClass: toggleDomNodeCssClass,
|
425
447
|
|
426
448
|
setTextContent: function(element, textContent) {
|
427
449
|
var value = ko.utils.unwrapObservable(textContent);
|
@@ -595,16 +617,26 @@ ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
|
|
595
617
|
ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
|
596
618
|
ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);
|
597
619
|
ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);
|
620
|
+
ko.exportSymbol('utils.setTextContent', ko.utils.setTextContent);
|
598
621
|
ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly
|
599
622
|
|
600
623
|
if (!Function.prototype['bind']) {
|
601
624
|
// 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)
|
602
625
|
// In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
|
603
626
|
Function.prototype['bind'] = function (object) {
|
604
|
-
var originalFunction = this
|
605
|
-
|
606
|
-
return
|
607
|
-
|
627
|
+
var originalFunction = this;
|
628
|
+
if (arguments.length === 1) {
|
629
|
+
return function () {
|
630
|
+
return originalFunction.apply(object, arguments);
|
631
|
+
};
|
632
|
+
} else {
|
633
|
+
var partialArgs = Array.prototype.slice.call(arguments, 1);
|
634
|
+
return function () {
|
635
|
+
var args = partialArgs.slice(0);
|
636
|
+
args.push.apply(args, arguments);
|
637
|
+
return originalFunction.apply(object, args);
|
638
|
+
};
|
639
|
+
}
|
608
640
|
};
|
609
641
|
}
|
610
642
|
|
@@ -751,7 +783,7 @@ ko.utils.domNodeDisposal = new (function () {
|
|
751
783
|
if (jQueryInstance && (typeof jQueryInstance['cleanData'] == "function"))
|
752
784
|
jQueryInstance['cleanData']([node]);
|
753
785
|
}
|
754
|
-
}
|
786
|
+
};
|
755
787
|
})();
|
756
788
|
ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
|
757
789
|
ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
|
@@ -763,7 +795,10 @@ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeD
|
|
763
795
|
(function () {
|
764
796
|
var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
|
765
797
|
|
766
|
-
function simpleHtmlParse(html) {
|
798
|
+
function simpleHtmlParse(html, documentContext) {
|
799
|
+
documentContext || (documentContext = document);
|
800
|
+
var windowContext = documentContext['parentWindow'] || documentContext['defaultView'] || window;
|
801
|
+
|
767
802
|
// Based on jQuery's "clean" function, but only accounting for table-related elements.
|
768
803
|
// If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
|
769
804
|
|
@@ -773,7 +808,7 @@ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeD
|
|
773
808
|
// (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
|
774
809
|
|
775
810
|
// Trim whitespace, otherwise indexOf won't work as expected
|
776
|
-
var tags = ko.utils.stringTrim(html).toLowerCase(), div =
|
811
|
+
var tags = ko.utils.stringTrim(html).toLowerCase(), div = documentContext.createElement("div");
|
777
812
|
|
778
813
|
// Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
|
779
814
|
var wrap = tags.match(/^<(thead|tbody|tfoot)/) && [1, "<table>", "</table>"] ||
|
@@ -784,8 +819,8 @@ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeD
|
|
784
819
|
// Go to html and back, then peel off extra wrappers
|
785
820
|
// Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
|
786
821
|
var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
|
787
|
-
if (typeof
|
788
|
-
div.appendChild(
|
822
|
+
if (typeof windowContext['innerShiv'] == "function") {
|
823
|
+
div.appendChild(windowContext['innerShiv'](markup));
|
789
824
|
} else {
|
790
825
|
div.innerHTML = markup;
|
791
826
|
}
|
@@ -797,13 +832,13 @@ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeD
|
|
797
832
|
return ko.utils.makeArray(div.lastChild.childNodes);
|
798
833
|
}
|
799
834
|
|
800
|
-
function jQueryHtmlParse(html) {
|
835
|
+
function jQueryHtmlParse(html, documentContext) {
|
801
836
|
// jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
|
802
837
|
if (jQueryInstance['parseHTML']) {
|
803
|
-
return jQueryInstance['parseHTML'](html) || []; // Ensure we always return an array and never null
|
838
|
+
return jQueryInstance['parseHTML'](html, documentContext) || []; // Ensure we always return an array and never null
|
804
839
|
} else {
|
805
840
|
// For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
|
806
|
-
var elems = jQueryInstance['clean']([html]);
|
841
|
+
var elems = jQueryInstance['clean']([html], documentContext);
|
807
842
|
|
808
843
|
// 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.
|
809
844
|
// Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
|
@@ -822,9 +857,9 @@ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeD
|
|
822
857
|
}
|
823
858
|
}
|
824
859
|
|
825
|
-
ko.utils.parseHtmlFragment = function(html) {
|
826
|
-
return jQueryInstance ? jQueryHtmlParse(html) // As below, benefit from jQuery's optimisations where possible
|
827
|
-
: simpleHtmlParse(html); // ... otherwise, this simple logic will do in most common cases.
|
860
|
+
ko.utils.parseHtmlFragment = function(html, documentContext) {
|
861
|
+
return jQueryInstance ? jQueryHtmlParse(html, documentContext) // As below, benefit from jQuery's optimisations where possible
|
862
|
+
: simpleHtmlParse(html, documentContext); // ... otherwise, this simple logic will do in most common cases.
|
828
863
|
};
|
829
864
|
|
830
865
|
ko.utils.setHtml = function(node, html) {
|
@@ -844,7 +879,7 @@ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeD
|
|
844
879
|
jQueryInstance(node)['html'](html);
|
845
880
|
} else {
|
846
881
|
// ... otherwise, use KO's own parsing logic.
|
847
|
-
var parsedNodes = ko.utils.parseHtmlFragment(html);
|
882
|
+
var parsedNodes = ko.utils.parseHtmlFragment(html, node.ownerDocument);
|
848
883
|
for (var i = 0; i < parsedNodes.length; i++)
|
849
884
|
node.appendChild(parsedNodes[i]);
|
850
885
|
}
|
@@ -1011,7 +1046,7 @@ function applyExtenders(requestedExtenders) {
|
|
1011
1046
|
ko.exportSymbol('extenders', ko.extenders);
|
1012
1047
|
|
1013
1048
|
ko.subscription = function (target, callback, disposeCallback) {
|
1014
|
-
this.
|
1049
|
+
this._target = target;
|
1015
1050
|
this.callback = callback;
|
1016
1051
|
this.disposeCallback = disposeCallback;
|
1017
1052
|
this.isDisposed = false;
|
@@ -1025,6 +1060,7 @@ ko.subscription.prototype.dispose = function () {
|
|
1025
1060
|
ko.subscribable = function () {
|
1026
1061
|
ko.utils.setPrototypeOfOrExtend(this, ko.subscribable['fn']);
|
1027
1062
|
this._subscriptions = {};
|
1063
|
+
this._versionNumber = 1;
|
1028
1064
|
}
|
1029
1065
|
|
1030
1066
|
var defaultEvent = "change";
|
@@ -1054,6 +1090,9 @@ var ko_subscribable_fn = {
|
|
1054
1090
|
|
1055
1091
|
"notifySubscribers": function (valueToNotify, event) {
|
1056
1092
|
event = event || defaultEvent;
|
1093
|
+
if (event === defaultEvent) {
|
1094
|
+
this.updateVersion();
|
1095
|
+
}
|
1057
1096
|
if (this.hasSubscriptionsForEvent(event)) {
|
1058
1097
|
try {
|
1059
1098
|
ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)
|
@@ -1069,6 +1108,18 @@ var ko_subscribable_fn = {
|
|
1069
1108
|
}
|
1070
1109
|
},
|
1071
1110
|
|
1111
|
+
getVersion: function () {
|
1112
|
+
return this._versionNumber;
|
1113
|
+
},
|
1114
|
+
|
1115
|
+
hasChanged: function (versionToCheck) {
|
1116
|
+
return this.getVersion() !== versionToCheck;
|
1117
|
+
},
|
1118
|
+
|
1119
|
+
updateVersion: function () {
|
1120
|
+
++this._versionNumber;
|
1121
|
+
},
|
1122
|
+
|
1072
1123
|
limit: function(limitFunction) {
|
1073
1124
|
var self = this, selfIsObservable = ko.isObservable(self),
|
1074
1125
|
isPending, previousValue, pendingValue, beforeChange = 'beforeChange';
|
@@ -1115,12 +1166,16 @@ var ko_subscribable_fn = {
|
|
1115
1166
|
return this._subscriptions[event] && this._subscriptions[event].length;
|
1116
1167
|
},
|
1117
1168
|
|
1118
|
-
getSubscriptionsCount: function () {
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1169
|
+
getSubscriptionsCount: function (event) {
|
1170
|
+
if (event) {
|
1171
|
+
return this._subscriptions[event] && this._subscriptions[event].length || 0;
|
1172
|
+
} else {
|
1173
|
+
var total = 0;
|
1174
|
+
ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {
|
1175
|
+
total += subscriptions.length;
|
1176
|
+
});
|
1177
|
+
return total;
|
1178
|
+
}
|
1124
1179
|
},
|
1125
1180
|
|
1126
1181
|
isDifferent: function(oldValue, newValue) {
|
@@ -1213,6 +1268,8 @@ ko.exportSymbol('computedContext', ko.computedContext);
|
|
1213
1268
|
ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);
|
1214
1269
|
ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);
|
1215
1270
|
ko.exportSymbol('computedContext.isSleeping', ko.computedContext.isSleeping);
|
1271
|
+
|
1272
|
+
ko.exportSymbol('ignoreDependencies', ko.ignoreDependencies = ko.dependencyDetection.ignore);
|
1216
1273
|
ko.observable = function (initialValue) {
|
1217
1274
|
var _latestValue = initialValue;
|
1218
1275
|
|
@@ -1418,15 +1475,27 @@ ko.extenders['trackArrayChanges'] = function(target) {
|
|
1418
1475
|
}
|
1419
1476
|
var trackingChanges = false,
|
1420
1477
|
cachedDiff = null,
|
1478
|
+
arrayChangeSubscription,
|
1421
1479
|
pendingNotifications = 0,
|
1422
|
-
|
1480
|
+
underlyingBeforeSubscriptionAddFunction = target.beforeSubscriptionAdd,
|
1481
|
+
underlyingAfterSubscriptionRemoveFunction = target.afterSubscriptionRemove;
|
1423
1482
|
|
1424
|
-
//
|
1425
|
-
target.
|
1483
|
+
// Watch "subscribe" calls, and for array change events, ensure change tracking is enabled
|
1484
|
+
target.beforeSubscriptionAdd = function (event) {
|
1485
|
+
if (underlyingBeforeSubscriptionAddFunction)
|
1486
|
+
underlyingBeforeSubscriptionAddFunction.call(target, event);
|
1426
1487
|
if (event === arrayChangeEventName) {
|
1427
1488
|
trackChanges();
|
1428
1489
|
}
|
1429
|
-
|
1490
|
+
};
|
1491
|
+
// Watch "dispose" calls, and for array change events, ensure change tracking is disabled when all are disposed
|
1492
|
+
target.afterSubscriptionRemove = function (event) {
|
1493
|
+
if (underlyingAfterSubscriptionRemoveFunction)
|
1494
|
+
underlyingAfterSubscriptionRemoveFunction.call(target, event);
|
1495
|
+
if (event === arrayChangeEventName && !target.hasSubscriptionsForEvent(arrayChangeEventName)) {
|
1496
|
+
arrayChangeSubscription.dispose();
|
1497
|
+
trackingChanges = false;
|
1498
|
+
}
|
1430
1499
|
};
|
1431
1500
|
|
1432
1501
|
function trackChanges() {
|
@@ -1450,22 +1519,23 @@ ko.extenders['trackArrayChanges'] = function(target) {
|
|
1450
1519
|
// change it's possible to produce a diff
|
1451
1520
|
var previousContents = [].concat(target.peek() || []);
|
1452
1521
|
cachedDiff = null;
|
1453
|
-
target.subscribe(function(currentContents) {
|
1522
|
+
arrayChangeSubscription = target.subscribe(function(currentContents) {
|
1454
1523
|
// Make a copy of the current contents and ensure it's an array
|
1455
1524
|
currentContents = [].concat(currentContents || []);
|
1456
1525
|
|
1457
1526
|
// Compute the diff and issue notifications, but only if someone is listening
|
1458
1527
|
if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {
|
1459
1528
|
var changes = getChanges(previousContents, currentContents);
|
1460
|
-
if (changes.length) {
|
1461
|
-
target['notifySubscribers'](changes, arrayChangeEventName);
|
1462
|
-
}
|
1463
1529
|
}
|
1464
1530
|
|
1465
1531
|
// Eliminate references to the old, removed items, so they can be GCed
|
1466
1532
|
previousContents = currentContents;
|
1467
1533
|
cachedDiff = null;
|
1468
1534
|
pendingNotifications = 0;
|
1535
|
+
|
1536
|
+
if (changes && changes.length) {
|
1537
|
+
target['notifySubscribers'](changes, arrayChangeEventName);
|
1538
|
+
}
|
1469
1539
|
});
|
1470
1540
|
}
|
1471
1541
|
|
@@ -1558,44 +1628,58 @@ ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, eva
|
|
1558
1628
|
if (typeof readFunction != "function")
|
1559
1629
|
throw new Error("Pass a function that returns the value of the ko.computed");
|
1560
1630
|
|
1561
|
-
function
|
1562
|
-
if (
|
1563
|
-
|
1564
|
-
++_dependenciesCount;
|
1631
|
+
function addDependencyTracking(id, target, trackingObj) {
|
1632
|
+
if (pure && target === dependentObservable) {
|
1633
|
+
throw Error("A 'pure' computed must not be called recursively");
|
1565
1634
|
}
|
1635
|
+
|
1636
|
+
dependencyTracking[id] = trackingObj;
|
1637
|
+
trackingObj._order = _dependenciesCount++;
|
1638
|
+
trackingObj._version = target.getVersion();
|
1566
1639
|
}
|
1567
1640
|
|
1568
|
-
function
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1641
|
+
function haveDependenciesChanged() {
|
1642
|
+
var id, dependency;
|
1643
|
+
for (id in dependencyTracking) {
|
1644
|
+
if (dependencyTracking.hasOwnProperty(id)) {
|
1645
|
+
dependency = dependencyTracking[id];
|
1646
|
+
if (dependency._target.hasChanged(dependency._version)) {
|
1647
|
+
return true;
|
1648
|
+
}
|
1649
|
+
}
|
1650
|
+
}
|
1573
1651
|
}
|
1574
1652
|
|
1575
1653
|
function disposeComputed() {
|
1576
|
-
|
1654
|
+
if (!isSleeping && dependencyTracking) {
|
1655
|
+
ko.utils.objectForEach(dependencyTracking, function (id, dependency) {
|
1656
|
+
if (dependency.dispose)
|
1657
|
+
dependency.dispose();
|
1658
|
+
});
|
1659
|
+
}
|
1660
|
+
dependencyTracking = null;
|
1577
1661
|
_dependenciesCount = 0;
|
1578
1662
|
_isDisposed = true;
|
1579
1663
|
_needsEvaluation = false;
|
1664
|
+
isSleeping = false;
|
1580
1665
|
}
|
1581
1666
|
|
1582
1667
|
function evaluatePossiblyAsync() {
|
1583
1668
|
var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
|
1584
1669
|
if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
|
1585
1670
|
clearTimeout(evaluationTimeoutInstance);
|
1586
|
-
evaluationTimeoutInstance = setTimeout(
|
1671
|
+
evaluationTimeoutInstance = setTimeout(function () {
|
1672
|
+
evaluateImmediate(true /*notifyChange*/);
|
1673
|
+
}, throttleEvaluationTimeout);
|
1587
1674
|
} else if (dependentObservable._evalRateLimited) {
|
1588
1675
|
dependentObservable._evalRateLimited();
|
1589
1676
|
} else {
|
1590
|
-
evaluateImmediate();
|
1677
|
+
evaluateImmediate(true /*notifyChange*/);
|
1591
1678
|
}
|
1592
1679
|
}
|
1593
1680
|
|
1594
|
-
function evaluateImmediate(
|
1681
|
+
function evaluateImmediate(notifyChange) {
|
1595
1682
|
if (_isBeingEvaluated) {
|
1596
|
-
if (pure) {
|
1597
|
-
throw Error("A 'pure' computed must not be called recursively");
|
1598
|
-
}
|
1599
1683
|
// If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
|
1600
1684
|
// This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
|
1601
1685
|
// certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
|
@@ -1621,82 +1705,71 @@ ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, eva
|
|
1621
1705
|
|
1622
1706
|
_isBeingEvaluated = true;
|
1623
1707
|
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1708
|
+
try {
|
1709
|
+
// Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
|
1710
|
+
// Then, during evaluation, we cross off any that are in fact still being used.
|
1711
|
+
var disposalCandidates = dependencyTracking,
|
1712
|
+
disposalCount = _dependenciesCount,
|
1713
|
+
isInitial = pure ? undefined : !_dependenciesCount; // If we're evaluating when there are no previous dependencies, it must be the first time
|
1714
|
+
|
1715
|
+
ko.dependencyDetection.begin({
|
1716
|
+
callback: function(subscribable, id) {
|
1717
|
+
if (!_isDisposed) {
|
1718
|
+
if (disposalCount && disposalCandidates[id]) {
|
1719
|
+
// Don't want to dispose this subscription, as it's still being used
|
1720
|
+
addDependencyTracking(id, subscribable, disposalCandidates[id]);
|
1721
|
+
delete disposalCandidates[id];
|
1722
|
+
--disposalCount;
|
1723
|
+
} else if (!dependencyTracking[id]) {
|
1724
|
+
// Brand new subscription - add it
|
1725
|
+
addDependencyTracking(id, subscribable, isSleeping ? { _target: subscribable } : subscribable.subscribe(evaluatePossiblyAsync));
|
1633
1726
|
}
|
1634
|
-
}
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1639
|
-
_latestValue = readFunction.call(evaluatorFunctionTarget);
|
1640
|
-
} finally {
|
1641
|
-
ko.dependencyDetection.end();
|
1642
|
-
_isBeingEvaluated = false;
|
1643
|
-
}
|
1644
|
-
} else {
|
1645
|
-
try {
|
1646
|
-
// Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
|
1647
|
-
// Then, during evaluation, we cross off any that are in fact still being used.
|
1648
|
-
var disposalCandidates = _subscriptionsToDependencies, disposalCount = _dependenciesCount;
|
1649
|
-
ko.dependencyDetection.begin({
|
1650
|
-
callback: function(subscribable, id) {
|
1651
|
-
if (!_isDisposed) {
|
1652
|
-
if (disposalCount && disposalCandidates[id]) {
|
1653
|
-
// Don't want to dispose this subscription, as it's still being used
|
1654
|
-
_subscriptionsToDependencies[id] = disposalCandidates[id];
|
1655
|
-
++_dependenciesCount;
|
1656
|
-
delete disposalCandidates[id];
|
1657
|
-
--disposalCount;
|
1658
|
-
} else {
|
1659
|
-
// Brand new subscription - add it
|
1660
|
-
addSubscriptionToDependency(subscribable, id);
|
1661
|
-
}
|
1662
|
-
}
|
1663
|
-
},
|
1664
|
-
computed: dependentObservable,
|
1665
|
-
isInitial: pure ? undefined : !_dependenciesCount // If we're evaluating when there are no previous dependencies, it must be the first time
|
1666
|
-
});
|
1727
|
+
}
|
1728
|
+
},
|
1729
|
+
computed: dependentObservable,
|
1730
|
+
isInitial: isInitial
|
1731
|
+
});
|
1667
1732
|
|
1668
|
-
|
1669
|
-
|
1733
|
+
dependencyTracking = {};
|
1734
|
+
_dependenciesCount = 0;
|
1670
1735
|
|
1671
|
-
|
1672
|
-
|
1736
|
+
try {
|
1737
|
+
var newValue = evaluatorFunctionTarget ? readFunction.call(evaluatorFunctionTarget) : readFunction();
|
1673
1738
|
|
1674
|
-
|
1675
|
-
|
1739
|
+
} finally {
|
1740
|
+
ko.dependencyDetection.end();
|
1676
1741
|
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1742
|
+
// For each subscription no longer being used, remove it from the active subscriptions list and dispose it
|
1743
|
+
if (disposalCount && !isSleeping) {
|
1744
|
+
ko.utils.objectForEach(disposalCandidates, function(id, toDispose) {
|
1745
|
+
if (toDispose.dispose)
|
1680
1746
|
toDispose.dispose();
|
1681
|
-
|
1682
|
-
}
|
1683
|
-
|
1684
|
-
_needsEvaluation = false;
|
1747
|
+
});
|
1685
1748
|
}
|
1686
1749
|
|
1687
|
-
|
1688
|
-
|
1750
|
+
_needsEvaluation = false;
|
1751
|
+
}
|
1689
1752
|
|
1690
|
-
|
1691
|
-
|
1753
|
+
if (dependentObservable.isDifferent(_latestValue, newValue)) {
|
1754
|
+
if (!isSleeping) {
|
1755
|
+
notify(_latestValue, "beforeChange");
|
1756
|
+
}
|
1692
1757
|
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1758
|
+
_latestValue = newValue;
|
1759
|
+
if (DEBUG) dependentObservable._latestValue = _latestValue;
|
1760
|
+
|
1761
|
+
if (isSleeping) {
|
1762
|
+
dependentObservable.updateVersion();
|
1763
|
+
} else if (notifyChange) {
|
1764
|
+
notify(_latestValue);
|
1696
1765
|
}
|
1697
|
-
} finally {
|
1698
|
-
_isBeingEvaluated = false;
|
1699
1766
|
}
|
1767
|
+
|
1768
|
+
if (isInitial) {
|
1769
|
+
notify(_latestValue, "awake");
|
1770
|
+
}
|
1771
|
+
} finally {
|
1772
|
+
_isBeingEvaluated = false;
|
1700
1773
|
}
|
1701
1774
|
|
1702
1775
|
if (!_dependenciesCount)
|
@@ -1715,17 +1788,18 @@ ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, eva
|
|
1715
1788
|
} else {
|
1716
1789
|
// Reading the value
|
1717
1790
|
ko.dependencyDetection.registerDependency(dependentObservable);
|
1718
|
-
if (_needsEvaluation)
|
1719
|
-
evaluateImmediate(
|
1791
|
+
if (_needsEvaluation || (isSleeping && haveDependenciesChanged())) {
|
1792
|
+
evaluateImmediate();
|
1793
|
+
}
|
1720
1794
|
return _latestValue;
|
1721
1795
|
}
|
1722
1796
|
}
|
1723
1797
|
|
1724
1798
|
function peek() {
|
1725
|
-
// Peek won't re-evaluate, except to get the initial value when "deferEvaluation" is set
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1799
|
+
// Peek won't re-evaluate, except while the computed is sleeping or to get the initial value when "deferEvaluation" is set.
|
1800
|
+
if ((_needsEvaluation && !_dependenciesCount) || (isSleeping && haveDependenciesChanged())) {
|
1801
|
+
evaluateImmediate();
|
1802
|
+
}
|
1729
1803
|
return _latestValue;
|
1730
1804
|
}
|
1731
1805
|
|
@@ -1733,13 +1807,17 @@ ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, eva
|
|
1733
1807
|
return _needsEvaluation || _dependenciesCount > 0;
|
1734
1808
|
}
|
1735
1809
|
|
1810
|
+
function notify(value, event) {
|
1811
|
+
dependentObservable["notifySubscribers"](value, event);
|
1812
|
+
}
|
1813
|
+
|
1736
1814
|
// By here, "options" is always non-null
|
1737
1815
|
var writeFunction = options["write"],
|
1738
1816
|
disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
|
1739
1817
|
disposeWhenOption = options["disposeWhen"] || options.disposeWhen,
|
1740
1818
|
disposeWhen = disposeWhenOption,
|
1741
1819
|
dispose = disposeComputed,
|
1742
|
-
|
1820
|
+
dependencyTracking = {},
|
1743
1821
|
_dependenciesCount = 0,
|
1744
1822
|
evaluationTimeoutInstance = null;
|
1745
1823
|
|
@@ -1751,7 +1829,7 @@ ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, eva
|
|
1751
1829
|
|
1752
1830
|
dependentObservable.peek = peek;
|
1753
1831
|
dependentObservable.getDependenciesCount = function () { return _dependenciesCount; };
|
1754
|
-
dependentObservable.hasWriteFunction = typeof
|
1832
|
+
dependentObservable.hasWriteFunction = typeof writeFunction === "function";
|
1755
1833
|
dependentObservable.dispose = function () { dispose(); };
|
1756
1834
|
dependentObservable.isActive = isActive;
|
1757
1835
|
|
@@ -1773,24 +1851,69 @@ ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, eva
|
|
1773
1851
|
if (options['pure']) {
|
1774
1852
|
pure = true;
|
1775
1853
|
isSleeping = true; // Starts off sleeping; will awake on the first subscription
|
1776
|
-
dependentObservable.beforeSubscriptionAdd = function () {
|
1777
|
-
// If asleep, wake up the computed
|
1778
|
-
if (isSleeping) {
|
1854
|
+
dependentObservable.beforeSubscriptionAdd = function (event) {
|
1855
|
+
// If asleep, wake up the computed by subscribing to any dependencies.
|
1856
|
+
if (!_isDisposed && isSleeping && event == 'change') {
|
1779
1857
|
isSleeping = false;
|
1780
|
-
|
1858
|
+
if (_needsEvaluation || haveDependenciesChanged()) {
|
1859
|
+
dependencyTracking = null;
|
1860
|
+
_dependenciesCount = 0;
|
1861
|
+
_needsEvaluation = true;
|
1862
|
+
evaluateImmediate();
|
1863
|
+
} else {
|
1864
|
+
// First put the dependencies in order
|
1865
|
+
var dependeciesOrder = [];
|
1866
|
+
ko.utils.objectForEach(dependencyTracking, function (id, dependency) {
|
1867
|
+
dependeciesOrder[dependency._order] = id;
|
1868
|
+
});
|
1869
|
+
// Next, subscribe to each one
|
1870
|
+
ko.utils.arrayForEach(dependeciesOrder, function(id, order) {
|
1871
|
+
var dependency = dependencyTracking[id],
|
1872
|
+
subscription = dependency._target.subscribe(evaluatePossiblyAsync);
|
1873
|
+
subscription._order = order;
|
1874
|
+
subscription._version = dependency._version;
|
1875
|
+
dependencyTracking[id] = subscription;
|
1876
|
+
});
|
1877
|
+
}
|
1878
|
+
if (!_isDisposed) { // test since evaluating could trigger disposal
|
1879
|
+
notify(_latestValue, "awake");
|
1880
|
+
}
|
1781
1881
|
}
|
1782
|
-
}
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1882
|
+
};
|
1883
|
+
|
1884
|
+
dependentObservable.afterSubscriptionRemove = function (event) {
|
1885
|
+
if (!_isDisposed && event == 'change' && !dependentObservable.hasSubscriptionsForEvent('change')) {
|
1886
|
+
ko.utils.objectForEach(dependencyTracking, function (id, dependency) {
|
1887
|
+
if (dependency.dispose) {
|
1888
|
+
dependencyTracking[id] = {
|
1889
|
+
_target: dependency._target,
|
1890
|
+
_order: dependency._order,
|
1891
|
+
_version: dependency._version
|
1892
|
+
};
|
1893
|
+
dependency.dispose();
|
1894
|
+
}
|
1895
|
+
});
|
1896
|
+
isSleeping = true;
|
1897
|
+
notify(undefined, "asleep");
|
1787
1898
|
}
|
1788
|
-
}
|
1899
|
+
};
|
1900
|
+
|
1901
|
+
// Because a pure computed is not automatically updated while it is sleeping, we can't
|
1902
|
+
// simply return the version number. Instead, we check if any of the dependencies have
|
1903
|
+
// changed and conditionally re-evaluate the computed observable.
|
1904
|
+
dependentObservable._originalGetVersion = dependentObservable.getVersion;
|
1905
|
+
dependentObservable.getVersion = function () {
|
1906
|
+
if (isSleeping && (_needsEvaluation || haveDependenciesChanged())) {
|
1907
|
+
evaluateImmediate();
|
1908
|
+
}
|
1909
|
+
return dependentObservable._originalGetVersion();
|
1910
|
+
};
|
1789
1911
|
} else if (options['deferEvaluation']) {
|
1790
1912
|
// This will force a computed with deferEvaluation to evaluate when the first subscriptions is registered.
|
1791
|
-
dependentObservable.beforeSubscriptionAdd = function () {
|
1792
|
-
|
1793
|
-
|
1913
|
+
dependentObservable.beforeSubscriptionAdd = function (event) {
|
1914
|
+
if (event == 'change' || event == 'beforeChange') {
|
1915
|
+
peek();
|
1916
|
+
}
|
1794
1917
|
}
|
1795
1918
|
}
|
1796
1919
|
|
@@ -2085,7 +2208,7 @@ ko.expressionRewriting = (function () {
|
|
2085
2208
|
if (str.charCodeAt(0) === 123) str = str.slice(1, -1);
|
2086
2209
|
|
2087
2210
|
// Split into tokens
|
2088
|
-
var result = [], toks = str.match(bindingToken), key, values, depth = 0;
|
2211
|
+
var result = [], toks = str.match(bindingToken), key, values = [], depth = 0;
|
2089
2212
|
|
2090
2213
|
if (toks) {
|
2091
2214
|
// Append a comma so that we don't need a separate code block to deal with the last item
|
@@ -2096,15 +2219,17 @@ ko.expressionRewriting = (function () {
|
|
2096
2219
|
// A comma signals the end of a key/value pair if depth is zero
|
2097
2220
|
if (c === 44) { // ","
|
2098
2221
|
if (depth <= 0) {
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
2222
|
+
result.push((key && values.length) ? {key: key, value: values.join('')} : {'unknown': key || values.join('')});
|
2223
|
+
key = depth = 0;
|
2224
|
+
values = [];
|
2102
2225
|
continue;
|
2103
2226
|
}
|
2104
2227
|
// Simply skip the colon that separates the name and value
|
2105
2228
|
} else if (c === 58) { // ":"
|
2106
|
-
if (!values)
|
2229
|
+
if (!depth && !key && values.length === 1) {
|
2230
|
+
key = values.pop();
|
2107
2231
|
continue;
|
2232
|
+
}
|
2108
2233
|
// A set of slashes is initially matched as a regular expression, but could be division
|
2109
2234
|
} else if (c === 47 && i && tok.length > 1) { // "/"
|
2110
2235
|
// Look at the end of the previous token to determine if the slash is actually division
|
@@ -2123,15 +2248,11 @@ ko.expressionRewriting = (function () {
|
|
2123
2248
|
++depth;
|
2124
2249
|
} else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'
|
2125
2250
|
--depth;
|
2126
|
-
// The key
|
2127
|
-
} else if (!key && !values) {
|
2128
|
-
|
2129
|
-
continue;
|
2251
|
+
// The key will be the first token; if it's a string, trim the quotes
|
2252
|
+
} else if (!key && !values.length && (c === 34 || c === 39)) { // '"', "'"
|
2253
|
+
tok = tok.slice(1, -1);
|
2130
2254
|
}
|
2131
|
-
|
2132
|
-
values.push(tok);
|
2133
|
-
else
|
2134
|
-
values = [tok];
|
2255
|
+
values.push(tok);
|
2135
2256
|
}
|
2136
2257
|
}
|
2137
2258
|
return result;
|
@@ -2512,9 +2633,10 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
2512
2633
|
// may consider adding <template> to this list, because such elements' contents are always
|
2513
2634
|
// intended to be bound in a different context from where they appear in the document.
|
2514
2635
|
var bindingDoesNotRecurseIntoElementTypes = {
|
2515
|
-
// Don't want bindings that operate on text nodes to mutate <script> contents,
|
2636
|
+
// Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,
|
2516
2637
|
// because it's unexpected and a potential XSS issue
|
2517
|
-
'script': true
|
2638
|
+
'script': true,
|
2639
|
+
'textarea': true
|
2518
2640
|
};
|
2519
2641
|
|
2520
2642
|
// Use an overridable method for retrieving binding handlers so that a plugins may support dynamically created handlers
|
@@ -2978,8 +3100,15 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
2978
3100
|
var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);
|
2979
3101
|
if (cachedDefinition) {
|
2980
3102
|
// It's already loaded and cached. Reuse the same definition object.
|
2981
|
-
// Note that for API consistency, even cache hits complete asynchronously.
|
2982
|
-
|
3103
|
+
// Note that for API consistency, even cache hits complete asynchronously by default.
|
3104
|
+
// You can bypass this by putting synchronous:true on your component config.
|
3105
|
+
if (cachedDefinition.isSynchronousComponent) {
|
3106
|
+
ko.dependencyDetection.ignore(function() { // See comment in loaderRegistryBehaviors.js for reasoning
|
3107
|
+
callback(cachedDefinition.definition);
|
3108
|
+
});
|
3109
|
+
} else {
|
3110
|
+
setTimeout(function() { callback(cachedDefinition.definition); }, 0);
|
3111
|
+
}
|
2983
3112
|
} else {
|
2984
3113
|
// Join the loading process that is already underway, or start a new one.
|
2985
3114
|
loadComponentAndNotify(componentName, callback);
|
@@ -3003,14 +3132,22 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3003
3132
|
if (!subscribable) {
|
3004
3133
|
// It's not started loading yet. Start loading, and when it's done, move it to loadedDefinitionsCache.
|
3005
3134
|
subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();
|
3006
|
-
|
3007
|
-
|
3135
|
+
subscribable.subscribe(callback);
|
3136
|
+
|
3137
|
+
beginLoadingComponent(componentName, function(definition, config) {
|
3138
|
+
var isSynchronousComponent = !!(config && config['synchronous']);
|
3139
|
+
loadedDefinitionsCache[componentName] = { definition: definition, isSynchronousComponent: isSynchronousComponent };
|
3008
3140
|
delete loadingSubscribablesCache[componentName];
|
3009
3141
|
|
3010
3142
|
// For API consistency, all loads complete asynchronously. However we want to avoid
|
3011
3143
|
// adding an extra setTimeout if it's unnecessary (i.e., the completion is already
|
3012
3144
|
// async) since setTimeout(..., 0) still takes about 16ms or more on most browsers.
|
3013
|
-
|
3145
|
+
//
|
3146
|
+
// You can bypass the 'always synchronous' feature by putting the synchronous:true
|
3147
|
+
// flag on your component configuration when you register it.
|
3148
|
+
if (completedAsync || isSynchronousComponent) {
|
3149
|
+
// Note that notifySubscribers ignores any dependencies read within the callback.
|
3150
|
+
// See comment in loaderRegistryBehaviors.js for reasoning
|
3014
3151
|
subscribable['notifySubscribers'](definition);
|
3015
3152
|
} else {
|
3016
3153
|
setTimeout(function() {
|
@@ -3019,8 +3156,9 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3019
3156
|
}
|
3020
3157
|
});
|
3021
3158
|
completedAsync = true;
|
3159
|
+
} else {
|
3160
|
+
subscribable.subscribe(callback);
|
3022
3161
|
}
|
3023
|
-
subscribable.subscribe(callback);
|
3024
3162
|
}
|
3025
3163
|
|
3026
3164
|
function beginLoadingComponent(componentName, callback) {
|
@@ -3028,14 +3166,14 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3028
3166
|
if (config) {
|
3029
3167
|
// We have a config, so now load its definition
|
3030
3168
|
getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {
|
3031
|
-
callback(definition);
|
3169
|
+
callback(definition, config);
|
3032
3170
|
});
|
3033
3171
|
} else {
|
3034
3172
|
// The component has no config - it's unknown to all the loaders.
|
3035
3173
|
// Note that this is not an error (e.g., a module loading error) - that would abort the
|
3036
3174
|
// process and this callback would not run. For this callback to run, all loaders must
|
3037
3175
|
// have confirmed they don't know about this component.
|
3038
|
-
callback(null);
|
3176
|
+
callback(null, null);
|
3039
3177
|
}
|
3040
3178
|
});
|
3041
3179
|
}
|
@@ -3291,8 +3429,8 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3291
3429
|
function possiblyGetConfigFromAmd(errorCallback, config, callback) {
|
3292
3430
|
if (typeof config['require'] === 'string') {
|
3293
3431
|
// The config is the value of an AMD module
|
3294
|
-
if (
|
3295
|
-
(
|
3432
|
+
if (amdRequire || window['require']) {
|
3433
|
+
(amdRequire || window['require'])([config['require']], callback);
|
3296
3434
|
} else {
|
3297
3435
|
errorCallback('Uses require, but no AMD loader is present');
|
3298
3436
|
}
|
@@ -3364,18 +3502,26 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3364
3502
|
return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });
|
3365
3503
|
}),
|
3366
3504
|
result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {
|
3505
|
+
var paramValue = paramValueComputed.peek();
|
3367
3506
|
// Does the evaluation of the parameter value unwrap any observables?
|
3368
3507
|
if (!paramValueComputed.isActive()) {
|
3369
3508
|
// No it doesn't, so there's no need for any computed wrapper. Just pass through the supplied value directly.
|
3370
3509
|
// Example: "someVal: firstName, age: 123" (whether or not firstName is an observable/computed)
|
3371
|
-
return
|
3510
|
+
return paramValue;
|
3372
3511
|
} else {
|
3373
3512
|
// Yes it does. Supply a computed property that unwraps both the outer (binding expression)
|
3374
3513
|
// level of observability, and any inner (resulting model value) level of observability.
|
3375
|
-
// This means the component doesn't have to worry about multiple unwrapping.
|
3376
|
-
|
3377
|
-
|
3378
|
-
|
3514
|
+
// This means the component doesn't have to worry about multiple unwrapping. If the value is a
|
3515
|
+
// writable observable, the computed will also be writable and pass the value on to the observable.
|
3516
|
+
return ko.computed({
|
3517
|
+
'read': function() {
|
3518
|
+
return ko.utils.unwrapObservable(paramValueComputed());
|
3519
|
+
},
|
3520
|
+
'write': ko.isWriteableObservable(paramValue) && function(value) {
|
3521
|
+
paramValueComputed()(value);
|
3522
|
+
},
|
3523
|
+
disposeWhenNodeIsRemoved: elem
|
3524
|
+
});
|
3379
3525
|
}
|
3380
3526
|
});
|
3381
3527
|
|
@@ -3438,7 +3584,8 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3438
3584
|
|
3439
3585
|
// Any in-flight loading operation is no longer relevant, so make sure we ignore its completion
|
3440
3586
|
currentLoadingOperationId = null;
|
3441
|
-
}
|
3587
|
+
},
|
3588
|
+
originalChildNodes = ko.utils.makeArray(ko.virtualElements.childNodes(element));
|
3442
3589
|
|
3443
3590
|
ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);
|
3444
3591
|
|
@@ -3472,8 +3619,11 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3472
3619
|
throw new Error('Unknown component \'' + componentName + '\'');
|
3473
3620
|
}
|
3474
3621
|
cloneTemplateIntoElement(componentName, componentDefinition, element);
|
3475
|
-
var componentViewModel = createViewModel(componentDefinition, element, componentParams),
|
3476
|
-
childBindingContext = bindingContext['createChildContext'](componentViewModel)
|
3622
|
+
var componentViewModel = createViewModel(componentDefinition, element, originalChildNodes, componentParams),
|
3623
|
+
childBindingContext = bindingContext['createChildContext'](componentViewModel, /* dataItemAlias */ undefined, function(ctx) {
|
3624
|
+
ctx['$component'] = componentViewModel;
|
3625
|
+
ctx['$componentTemplateNodes'] = originalChildNodes;
|
3626
|
+
});
|
3477
3627
|
currentViewModel = componentViewModel;
|
3478
3628
|
ko.applyBindingsToDescendants(childBindingContext, element);
|
3479
3629
|
});
|
@@ -3495,10 +3645,10 @@ ko.exportSymbol('bindingProvider', ko.bindingProvider);
|
|
3495
3645
|
ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);
|
3496
3646
|
}
|
3497
3647
|
|
3498
|
-
function createViewModel(componentDefinition, element, componentParams) {
|
3648
|
+
function createViewModel(componentDefinition, element, originalChildNodes, componentParams) {
|
3499
3649
|
var componentViewModelFactory = componentDefinition['createViewModel'];
|
3500
3650
|
return componentViewModelFactory
|
3501
|
-
? componentViewModelFactory.call(componentDefinition, componentParams, { element: element })
|
3651
|
+
? componentViewModelFactory.call(componentDefinition, componentParams, { 'element': element, 'templateNodes': originalChildNodes })
|
3502
3652
|
: componentParams; // Template-only component
|
3503
3653
|
}
|
3504
3654
|
|
@@ -3651,7 +3801,7 @@ ko.bindingHandlers['checkedValue'] = {
|
|
3651
3801
|
ko.bindingHandlers['css'] = {
|
3652
3802
|
'update': function (element, valueAccessor) {
|
3653
3803
|
var value = ko.utils.unwrapObservable(valueAccessor());
|
3654
|
-
if (typeof value == "object") {
|
3804
|
+
if (value !== null && typeof value == "object") {
|
3655
3805
|
ko.utils.objectForEach(value, function(className, shouldHaveClass) {
|
3656
3806
|
shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
|
3657
3807
|
ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
|
@@ -3893,19 +4043,23 @@ ko.bindingHandlers['options'] = {
|
|
3893
4043
|
return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });
|
3894
4044
|
}
|
3895
4045
|
|
3896
|
-
var selectWasPreviouslyEmpty = element.length == 0
|
3897
|
-
|
3898
|
-
|
3899
|
-
|
3900
|
-
|
3901
|
-
|
3902
|
-
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
3906
|
-
|
3907
|
-
|
3908
|
-
|
4046
|
+
var selectWasPreviouslyEmpty = element.length == 0,
|
4047
|
+
multiple = element.multiple,
|
4048
|
+
previousScrollTop = (!selectWasPreviouslyEmpty && multiple) ? element.scrollTop : null,
|
4049
|
+
unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),
|
4050
|
+
valueAllowUnset = allBindings.get('valueAllowUnset') && allBindings['has']('value'),
|
4051
|
+
includeDestroyed = allBindings.get('optionsIncludeDestroyed'),
|
4052
|
+
arrayToDomNodeChildrenOptions = {},
|
4053
|
+
captionValue,
|
4054
|
+
filteredArray,
|
4055
|
+
previousSelectedValues = [];
|
4056
|
+
|
4057
|
+
if (!valueAllowUnset) {
|
4058
|
+
if (multiple) {
|
4059
|
+
previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);
|
4060
|
+
} else if (element.selectedIndex >= 0) {
|
4061
|
+
previousSelectedValues.push(ko.selectExtensions.readValue(element.options[element.selectedIndex]));
|
4062
|
+
}
|
3909
4063
|
}
|
3910
4064
|
|
3911
4065
|
if (unwrappedArray) {
|
@@ -3946,7 +4100,7 @@ ko.bindingHandlers['options'] = {
|
|
3946
4100
|
var itemUpdate = false;
|
3947
4101
|
function optionForArrayItem(arrayEntry, index, oldOptions) {
|
3948
4102
|
if (oldOptions.length) {
|
3949
|
-
previousSelectedValues = oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];
|
4103
|
+
previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];
|
3950
4104
|
itemUpdate = true;
|
3951
4105
|
}
|
3952
4106
|
var option = element.ownerDocument.createElement("option");
|
@@ -3973,20 +4127,25 @@ ko.bindingHandlers['options'] = {
|
|
3973
4127
|
};
|
3974
4128
|
|
3975
4129
|
function setSelectionCallback(arrayEntry, newOptions) {
|
3976
|
-
|
3977
|
-
|
3978
|
-
|
4130
|
+
if (itemUpdate && valueAllowUnset) {
|
4131
|
+
// The model value is authoritative, so make sure its value is the one selected
|
4132
|
+
// There is no need to use dependencyDetection.ignore since setDomNodeChildrenFromArrayMapping does so already.
|
4133
|
+
ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
|
4134
|
+
} else if (previousSelectedValues.length) {
|
4135
|
+
// IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
|
4136
|
+
// That's why we first added them without selection. Now it's time to set the selection.
|
3979
4137
|
var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;
|
3980
4138
|
ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);
|
3981
4139
|
|
3982
4140
|
// If this option was changed from being selected during a single-item update, notify the change
|
3983
|
-
if (itemUpdate && !isSelected)
|
4141
|
+
if (itemUpdate && !isSelected) {
|
3984
4142
|
ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
|
4143
|
+
}
|
3985
4144
|
}
|
3986
4145
|
}
|
3987
4146
|
|
3988
4147
|
var callback = setSelectionCallback;
|
3989
|
-
if (allBindings['has']('optionsAfterRender')) {
|
4148
|
+
if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == "function") {
|
3990
4149
|
callback = function(arrayEntry, newOptions) {
|
3991
4150
|
setSelectionCallback(arrayEntry, newOptions);
|
3992
4151
|
ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);
|
@@ -3996,13 +4155,13 @@ ko.bindingHandlers['options'] = {
|
|
3996
4155
|
ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);
|
3997
4156
|
|
3998
4157
|
ko.dependencyDetection.ignore(function () {
|
3999
|
-
if (
|
4158
|
+
if (valueAllowUnset) {
|
4000
4159
|
// The model value is authoritative, so make sure its value is the one selected
|
4001
4160
|
ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
|
4002
4161
|
} else {
|
4003
4162
|
// Determine if the selection has changed as a result of updating the options list
|
4004
4163
|
var selectionChanged;
|
4005
|
-
if (
|
4164
|
+
if (multiple) {
|
4006
4165
|
// For a multiple-select box, compare the new selection count to the previous one
|
4007
4166
|
// But if nothing was selected before, the selection can't have changed
|
4008
4167
|
selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;
|
@@ -4417,6 +4576,7 @@ makeEventHandlerShortcut('click');
|
|
4417
4576
|
// // - you might also want to make bindingContext.$parent, bindingContext.$parents,
|
4418
4577
|
// // and bindingContext.$root available in the template too
|
4419
4578
|
// // - options gives you access to any other properties set on "data-bind: { template: options }"
|
4579
|
+
// // - templateDocument is the document object of the template
|
4420
4580
|
// //
|
4421
4581
|
// // Return value: an array of DOM nodes
|
4422
4582
|
// }
|
@@ -4434,7 +4594,7 @@ makeEventHandlerShortcut('click');
|
|
4434
4594
|
|
4435
4595
|
ko.templateEngine = function () { };
|
4436
4596
|
|
4437
|
-
ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
|
4597
|
+
ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
|
4438
4598
|
throw new Error("Override renderTemplateSource");
|
4439
4599
|
};
|
4440
4600
|
|
@@ -4459,7 +4619,7 @@ ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateD
|
|
4459
4619
|
|
4460
4620
|
ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
|
4461
4621
|
var templateSource = this['makeTemplateSource'](template, templateDocument);
|
4462
|
-
return this['renderTemplateSource'](templateSource, bindingContext, options);
|
4622
|
+
return this['renderTemplateSource'](templateSource, bindingContext, options, templateDocument);
|
4463
4623
|
};
|
4464
4624
|
|
4465
4625
|
ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
|
@@ -4479,7 +4639,7 @@ ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCal
|
|
4479
4639
|
ko.exportSymbol('templateEngine', ko.templateEngine);
|
4480
4640
|
|
4481
4641
|
ko.templateRewriting = (function () {
|
4482
|
-
var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
|
4642
|
+
var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
|
4483
4643
|
var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
|
4484
4644
|
|
4485
4645
|
function validateDataBindValuesForRewriting(keyValueArray) {
|
@@ -4554,10 +4714,10 @@ ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextS
|
|
4554
4714
|
// with the rendered template output.
|
4555
4715
|
// You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
|
4556
4716
|
// Template sources need to have the following functions:
|
4557
|
-
// text()
|
4558
|
-
// text(value)
|
4559
|
-
// data(key)
|
4560
|
-
// data(key, value)
|
4717
|
+
// text() - returns the template text from your storage location
|
4718
|
+
// text(value) - writes the supplied template text to your storage location
|
4719
|
+
// data(key) - reads values stored using data(key, value) - see below
|
4720
|
+
// data(key, value) - associates "value" with this template and the key "key". Is used to store information like "isRewritten".
|
4561
4721
|
//
|
4562
4722
|
// Optionally, template sources can also have the following functions:
|
4563
4723
|
// nodes() - returns a DOM element containing the nodes of this template, where available
|
@@ -4720,7 +4880,7 @@ ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextS
|
|
4720
4880
|
function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
|
4721
4881
|
options = options || {};
|
4722
4882
|
var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
|
4723
|
-
var templateDocument = firstTargetNode
|
4883
|
+
var templateDocument = (firstTargetNode || template || {}).ownerDocument;
|
4724
4884
|
var templateEngineToUse = (options['templateEngine'] || _templateEngine);
|
4725
4885
|
ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
|
4726
4886
|
var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
|
@@ -4826,6 +4986,10 @@ ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextS
|
|
4826
4986
|
activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
|
4827
4987
|
if (options['afterRender'])
|
4828
4988
|
options['afterRender'](addedNodesArray, arrayValue);
|
4989
|
+
|
4990
|
+
// release the "cache" variable, so that it can be collected by
|
4991
|
+
// the GC when its value isn't used from within the bindings anymore.
|
4992
|
+
arrayItemContext = null;
|
4829
4993
|
};
|
4830
4994
|
|
4831
4995
|
return ko.dependentObservable(function () {
|
@@ -4860,6 +5024,17 @@ ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextS
|
|
4860
5024
|
if (typeof bindingValue == "string" || bindingValue['name']) {
|
4861
5025
|
// It's a named template - clear the element
|
4862
5026
|
ko.virtualElements.emptyNode(element);
|
5027
|
+
} else if ('nodes' in bindingValue) {
|
5028
|
+
// We've been given an array of DOM nodes. Save them as the template source.
|
5029
|
+
// There is no known use case for the node array being an observable array (if the output
|
5030
|
+
// varies, put that behavior *into* your template - that's what templates are for), and
|
5031
|
+
// the implementation would be a mess, so assert that it's not observable.
|
5032
|
+
var nodes = bindingValue['nodes'] || [];
|
5033
|
+
if (ko.isObservable(nodes)) {
|
5034
|
+
throw new Error('The "nodes" option must be a plain, non-observable array.');
|
5035
|
+
}
|
5036
|
+
var container = ko.utils.moveCleanedNodesToContainerElement(nodes); // This also removes the nodes from their current parent
|
5037
|
+
new ko.templateSources.anonymousTemplate(element)['nodes'](container);
|
4863
5038
|
} else {
|
4864
5039
|
// It's an anonymous template - store the element contents, then clear the element
|
4865
5040
|
var templateNodes = ko.virtualElements.childNodes(element),
|
@@ -5194,7 +5369,7 @@ ko.nativeTemplateEngine = function () {
|
|
5194
5369
|
|
5195
5370
|
ko.nativeTemplateEngine.prototype = new ko.templateEngine();
|
5196
5371
|
ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;
|
5197
|
-
ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
|
5372
|
+
ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
|
5198
5373
|
var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
|
5199
5374
|
templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
|
5200
5375
|
templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
|
@@ -5203,7 +5378,7 @@ ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSo
|
|
5203
5378
|
return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
|
5204
5379
|
} else {
|
5205
5380
|
var templateText = templateSource['text']();
|
5206
|
-
return ko.utils.parseHtmlFragment(templateText);
|
5381
|
+
return ko.utils.parseHtmlFragment(templateText, templateDocument);
|
5207
5382
|
}
|
5208
5383
|
};
|
5209
5384
|
|
@@ -5240,7 +5415,8 @@ ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
|
|
5240
5415
|
return jQueryInstance['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
|
5241
5416
|
}
|
5242
5417
|
|
5243
|
-
this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
|
5418
|
+
this['renderTemplateSource'] = function(templateSource, bindingContext, options, templateDocument) {
|
5419
|
+
templateDocument = templateDocument || document;
|
5244
5420
|
options = options || {};
|
5245
5421
|
ensureHasReferencedJQueryTemplates();
|
5246
5422
|
|
@@ -5259,7 +5435,7 @@ ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
|
|
5259
5435
|
var jQueryTemplateOptions = jQueryInstance['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
|
5260
5436
|
|
5261
5437
|
var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
|
5262
|
-
resultNodes['appendTo'](
|
5438
|
+
resultNodes['appendTo'](templateDocument.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
|
5263
5439
|
|
5264
5440
|
jQueryInstance['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
|
5265
5441
|
return resultNodes;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kea-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan-Christian Foeh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- app/assets/javascripts/kea/bindings/submit_button.js
|
43
43
|
- app/assets/javascripts/kea/bindings/validation_state.js
|
44
44
|
- app/assets/javascripts/kea/bindings/wait_for_vm.js
|
45
|
+
- app/assets/javascripts/kea/components/confirmation_button.js
|
45
46
|
- app/assets/javascripts/kea/extenders/equals.js
|
46
47
|
- app/assets/javascripts/kea/extenders/external_validator.js
|
47
48
|
- app/assets/javascripts/kea/extenders/min_length.js
|
@@ -203,7 +204,7 @@ files:
|
|
203
204
|
- vendor/assets/components/veiljs/veil.js
|
204
205
|
- vendor/assets/javascripts/fuse.js
|
205
206
|
- vendor/assets/javascripts/jquery-ui.js
|
206
|
-
- vendor/assets/javascripts/knockout-3.
|
207
|
+
- vendor/assets/javascripts/knockout-3.3.0-debug.js
|
207
208
|
- vendor/assets/javascripts/moment.js
|
208
209
|
- vendor/assets/javascripts/pikaday.js
|
209
210
|
- vendor/assets/stylesheets/pikaday.css
|