kea-rails 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|