knockoutjs-rails 1.04 → 1.05
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.
- data/README.md +1 -1
- data/lib/knockoutjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/knockout.js +156 -81
- metadata +3 -3
data/README.md
CHANGED
@@ -20,7 +20,7 @@ Add the following directive to your Javascript manifest file (application.js):
|
|
20
20
|
|
21
21
|
## Versioning
|
22
22
|
|
23
|
-
knockoutjs-rails 1.
|
23
|
+
knockoutjs-rails 1.05 == Knockout.js 1.05
|
24
24
|
|
25
25
|
Every attempt is made to mirror the currently shipping Knockout.js version number wherever possible.
|
26
26
|
The major and minor version numbers will always represent the Knockout.js version, but the patch level
|
@@ -1,4 +1,4 @@
|
|
1
|
-
// Knockout JavaScript library v1.
|
1
|
+
// Knockout JavaScript library v1.05
|
2
2
|
// (c) 2010 Steven Sanderson - http://knockoutjs.com/
|
3
3
|
// License: Ms-Pl (http://www.opensource.org/licenses/ms-pl.html)
|
4
4
|
|
@@ -7,10 +7,10 @@ var ko = window.ko = {};
|
|
7
7
|
|
8
8
|
ko.utils = new (function () {
|
9
9
|
var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
|
10
|
-
|
10
|
+
|
11
11
|
return {
|
12
|
-
|
13
|
-
|
12
|
+
fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
|
13
|
+
|
14
14
|
arrayForEach: function (array, action) {
|
15
15
|
for (var i = 0, j = array.length; i < j; i++)
|
16
16
|
action(array[i]);
|
@@ -64,6 +64,11 @@ ko.utils = new (function () {
|
|
64
64
|
result.push(array[i]);
|
65
65
|
return result;
|
66
66
|
},
|
67
|
+
|
68
|
+
arrayPushAll: function (array, valuesToPush) {
|
69
|
+
for (var i = 0, j = valuesToPush.length; i < j; i++)
|
70
|
+
array.push(valuesToPush[i]);
|
71
|
+
},
|
67
72
|
|
68
73
|
emptyDomNode: function (domNode) {
|
69
74
|
while (domNode.firstChild) {
|
@@ -223,24 +228,24 @@ ko.utils = new (function () {
|
|
223
228
|
},
|
224
229
|
|
225
230
|
makeArray: function(arrayLikeObject) {
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
+
var result = [];
|
232
|
+
for (var i = arrayLikeObject.length - 1; i >= 0; i--){
|
233
|
+
result.push(arrayLikeObject[i]);
|
234
|
+
};
|
235
|
+
return result;
|
231
236
|
},
|
232
237
|
|
233
238
|
getFormFields: function(form, fieldName) {
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
239
|
+
var fields = ko.utils.makeArray(form.getElementsByTagName("INPUT")).concat(ko.utils.makeArray(form.getElementsByTagName("TEXTAREA")));
|
240
|
+
var isMatchingField = (typeof fieldName == 'string')
|
241
|
+
? function(field) { return field.name === fieldName }
|
242
|
+
: function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
|
243
|
+
var matches = [];
|
244
|
+
for (var i = fields.length - 1; i >= 0; i--) {
|
245
|
+
if (isMatchingField(fields[i]))
|
246
|
+
matches.push(fields[i]);
|
247
|
+
};
|
248
|
+
return matches;
|
244
249
|
},
|
245
250
|
|
246
251
|
stringifyJson: function (data) {
|
@@ -250,22 +255,22 @@ ko.utils = new (function () {
|
|
250
255
|
},
|
251
256
|
|
252
257
|
postJson: function (urlOrForm, data, options) {
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
258
|
+
options = options || {};
|
259
|
+
var params = options.params || {};
|
260
|
+
var includeFields = options.includeFields || this.fieldsIncludedWithJsonPost;
|
261
|
+
var url = urlOrForm;
|
262
|
+
|
263
|
+
// If we were given a form, use its 'action' URL and pick out any requested field values
|
264
|
+
if((typeof urlOrForm == 'object') && (urlOrForm.tagName == "FORM")) {
|
265
|
+
var originalForm = urlOrForm;
|
266
|
+
url = originalForm.action;
|
267
|
+
for (var i = includeFields.length - 1; i >= 0; i--) {
|
268
|
+
var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
|
269
|
+
for (var j = fields.length - 1; j >= 0; j--)
|
270
|
+
params[fields[j].name] = fields[j].value;
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
269
274
|
data = ko.utils.unwrapObservable(data);
|
270
275
|
var form = document.createElement("FORM");
|
271
276
|
form.style.display = "none";
|
@@ -614,7 +619,39 @@ ko.dependentObservable = function (evaluatorFunction, evaluatorFunctionTarget, o
|
|
614
619
|
evaluate();
|
615
620
|
return dependentObservable;
|
616
621
|
};
|
617
|
-
ko.dependentObservable.__ko_proto__ = ko.observable
|
622
|
+
ko.dependentObservable.__ko_proto__ = ko.observable;(function () {
|
623
|
+
// Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
|
624
|
+
// are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
|
625
|
+
// that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
|
626
|
+
ko.selectExtensions = {
|
627
|
+
readValue : function(element) {
|
628
|
+
if (element.tagName == 'OPTION') {
|
629
|
+
var valueAttributeValue = element.getAttribute("value");
|
630
|
+
if (valueAttributeValue !== ko.bindingHandlers.options.optionValueDomDataKey)
|
631
|
+
return valueAttributeValue;
|
632
|
+
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
|
633
|
+
} else if (element.tagName == 'SELECT')
|
634
|
+
return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
|
635
|
+
else
|
636
|
+
return element.value;
|
637
|
+
},
|
638
|
+
|
639
|
+
writeValue: function(element, value) {
|
640
|
+
if (element.tagName == 'OPTION') {
|
641
|
+
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
|
642
|
+
element.value = ko.bindingHandlers.options.optionValueDomDataKey;
|
643
|
+
} else if (element.tagName == 'SELECT') {
|
644
|
+
for (var i = element.options.length - 1; i >= 0; i--) {
|
645
|
+
if (ko.selectExtensions.readValue(element.options[i]) == value) {
|
646
|
+
element.selectedIndex = i;
|
647
|
+
break;
|
648
|
+
}
|
649
|
+
}
|
650
|
+
} else
|
651
|
+
element.value = value;
|
652
|
+
}
|
653
|
+
};
|
654
|
+
})();/// <reference path="../utils.js" />
|
618
655
|
|
619
656
|
ko.jsonExpressionRewriting = (function () {
|
620
657
|
var restoreCapturedTokensRegex = /\[ko_token_(\d+)\]/g;
|
@@ -737,13 +774,19 @@ ko.jsonExpressionRewriting = (function () {
|
|
737
774
|
function () {
|
738
775
|
var evaluatedBindings = (typeof bindings == "function") ? bindings() : bindings;
|
739
776
|
var parsedBindings = evaluatedBindings || parseBindingAttribute(node.getAttribute(bindingAttributeName), viewModel);
|
777
|
+
|
778
|
+
// First run all the inits, so bindings can register for notification on changes
|
779
|
+
if (isFirstEvaluation) {
|
780
|
+
for (var bindingKey in parsedBindings) {
|
781
|
+
if (ko.bindingHandlers[bindingKey] && typeof ko.bindingHandlers[bindingKey].init == "function")
|
782
|
+
invokeBindingHandler(ko.bindingHandlers[bindingKey].init, node, parsedBindings[bindingKey], parsedBindings, viewModel);
|
783
|
+
}
|
784
|
+
}
|
785
|
+
|
786
|
+
// ... then run all the updates, which might trigger changes even on the first evaluation
|
740
787
|
for (var bindingKey in parsedBindings) {
|
741
|
-
if (ko.bindingHandlers[bindingKey])
|
742
|
-
if (isFirstEvaluation && typeof ko.bindingHandlers[bindingKey].init == "function")
|
743
|
-
invokeBindingHandler(ko.bindingHandlers[bindingKey].init, node, parsedBindings[bindingKey], parsedBindings, viewModel);
|
744
|
-
if (typeof ko.bindingHandlers[bindingKey].update == "function")
|
788
|
+
if (ko.bindingHandlers[bindingKey] && typeof ko.bindingHandlers[bindingKey].update == "function")
|
745
789
|
invokeBindingHandler(ko.bindingHandlers[bindingKey].update, node, parsedBindings[bindingKey], parsedBindings, viewModel);
|
746
|
-
}
|
747
790
|
}
|
748
791
|
},
|
749
792
|
null,
|
@@ -817,15 +860,18 @@ ko.bindingHandlers.value = {
|
|
817
860
|
init: function (element, value, allBindings) {
|
818
861
|
var eventName = allBindings.valueUpdate || "change";
|
819
862
|
if (ko.isWriteableObservable(value))
|
820
|
-
ko.utils.registerEventHandler(element, eventName, function () {
|
863
|
+
ko.utils.registerEventHandler(element, eventName, function () {
|
864
|
+
value(ko.selectExtensions.readValue(this));
|
865
|
+
});
|
821
866
|
else if (allBindings._ko_property_writers && allBindings._ko_property_writers.value)
|
822
|
-
ko.utils.registerEventHandler(element, eventName, function () {
|
867
|
+
ko.utils.registerEventHandler(element, eventName, function () {
|
868
|
+
allBindings._ko_property_writers.value(ko.selectExtensions.readValue(this));
|
869
|
+
});
|
823
870
|
},
|
824
871
|
update: function (element, value) {
|
825
872
|
var newValue = ko.utils.unwrapObservable(value);
|
826
|
-
|
827
|
-
|
828
|
-
var applyValueAction = function () { element.value = newValue; };
|
873
|
+
if (newValue != ko.selectExtensions.readValue(element)) {
|
874
|
+
var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
|
829
875
|
applyValueAction();
|
830
876
|
|
831
877
|
// Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
|
@@ -840,14 +886,13 @@ ko.bindingHandlers.value = {
|
|
840
886
|
|
841
887
|
ko.bindingHandlers.options = {
|
842
888
|
update: function (element, value, allBindings) {
|
843
|
-
|
844
889
|
if (element.tagName != "SELECT")
|
845
|
-
throw new Error("
|
890
|
+
throw new Error("options binding applies only to SELECT elements");
|
846
891
|
|
847
892
|
var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
|
848
893
|
return node.tagName && node.tagName == "OPTION" && node.selected;
|
849
894
|
}), function (node) {
|
850
|
-
return node
|
895
|
+
return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
|
851
896
|
});
|
852
897
|
|
853
898
|
value = ko.utils.unwrapObservable(value);
|
@@ -857,24 +902,37 @@ ko.bindingHandlers.options = {
|
|
857
902
|
if (value) {
|
858
903
|
if (typeof value.length != "number")
|
859
904
|
value = [value];
|
905
|
+
if (allBindings.optionsCaption) {
|
906
|
+
var option = document.createElement("OPTION");
|
907
|
+
option.innerHTML = allBindings.optionsCaption;
|
908
|
+
ko.selectExtensions.writeValue(option, undefined);
|
909
|
+
element.appendChild(option);
|
910
|
+
}
|
860
911
|
for (var i = 0, j = value.length; i < j; i++) {
|
861
912
|
var option = document.createElement("OPTION");
|
862
|
-
var optionValue = typeof allBindings.
|
863
|
-
|
864
|
-
|
913
|
+
var optionValue = typeof allBindings.optionsValue == "string" ? value[i][allBindings.optionsValue] : value[i];
|
914
|
+
if (typeof optionValue == 'object')
|
915
|
+
ko.selectExtensions.writeValue(option, optionValue);
|
916
|
+
else
|
917
|
+
option.value = optionValue.toString();
|
918
|
+
option.innerHTML = (typeof allBindings.optionsText == "string" ? value[i][allBindings.optionsText] : optionValue).toString();
|
865
919
|
element.appendChild(option);
|
866
920
|
}
|
867
921
|
|
868
922
|
// IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
|
869
923
|
// That's why we first added them without selection. Now it's time to set the selection.
|
870
924
|
var newOptions = element.getElementsByTagName("OPTION");
|
925
|
+
var countSelectionsRetained = 0;
|
871
926
|
for (var i = 0, j = newOptions.length; i < j; i++) {
|
872
|
-
if (ko.utils.arrayIndexOf(previousSelectedValues, newOptions[i]
|
927
|
+
if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
|
873
928
|
ko.utils.setOptionNodeSelectionState(newOptions[i], true);
|
929
|
+
countSelectionsRetained++;
|
930
|
+
}
|
874
931
|
}
|
875
932
|
}
|
876
933
|
}
|
877
934
|
};
|
935
|
+
ko.bindingHandlers.options.optionValueDomDataKey = '__ko.bindingHandlers.options.optionValueDomData__';
|
878
936
|
|
879
937
|
ko.bindingHandlers.selectedOptions = {
|
880
938
|
getSelectedValuesFromSelectNode: function (selectNode) {
|
@@ -883,12 +941,11 @@ ko.bindingHandlers.selectedOptions = {
|
|
883
941
|
for (var i = 0, j = nodes.length; i < j; i++) {
|
884
942
|
var node = nodes[i];
|
885
943
|
if ((node.tagName == "OPTION") && node.selected)
|
886
|
-
result.push(node
|
944
|
+
result.push(ko.selectExtensions.readValue(node));
|
887
945
|
}
|
888
946
|
return result;
|
889
947
|
},
|
890
948
|
init: function (element, value, allBindings) {
|
891
|
-
|
892
949
|
if (ko.isWriteableObservable(value))
|
893
950
|
ko.utils.registerEventHandler(element, "change", function () { value(ko.bindingHandlers.selectedOptions.getSelectedValuesFromSelectNode(this)); });
|
894
951
|
else if (allBindings._ko_property_writers && allBindings._ko_property_writers.value)
|
@@ -904,7 +961,7 @@ ko.bindingHandlers.selectedOptions = {
|
|
904
961
|
for (var i = 0, j = nodes.length; i < j; i++) {
|
905
962
|
var node = nodes[i];
|
906
963
|
if (node.tagName == "OPTION")
|
907
|
-
ko.utils.setOptionNodeSelectionState(node, ko.utils.arrayIndexOf(newValue, node
|
964
|
+
ko.utils.setOptionNodeSelectionState(node, ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0);
|
908
965
|
}
|
909
966
|
}
|
910
967
|
}
|
@@ -1122,10 +1179,10 @@ ko.templateRewriting = (function () {
|
|
1122
1179
|
if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
|
1123
1180
|
unwrappedArray = [unwrappedArray];
|
1124
1181
|
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1182
|
+
// Filter out any entries marked as destroyed
|
1183
|
+
var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
|
1184
|
+
return options.includeDestroyed || !item._destroy;
|
1185
|
+
});
|
1129
1186
|
|
1130
1187
|
ko.utils.setDomNodeChildrenFromArrayMapping(targetNode, filteredArray, function (arrayValue) {
|
1131
1188
|
return executeTemplate(null, "ignoreTargetNode", template, arrayValue, options);
|
@@ -1240,6 +1297,24 @@ ko.templateRewriting = (function () {
|
|
1240
1297
|
// so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
|
1241
1298
|
// previously mapped - retain those nodes, and just insert/delete other ones
|
1242
1299
|
|
1300
|
+
function mapNodeAndRefreshWhenChanged(mapping, valueToMap) {
|
1301
|
+
// Map this array value inside a dependentObservable so we re-map when any dependency changes
|
1302
|
+
var mappedNodes = [];
|
1303
|
+
ko.dependentObservable(function() {
|
1304
|
+
var newMappedNodes = mapping(valueToMap) || [];
|
1305
|
+
|
1306
|
+
// On subsequent evaluations, just replace the previously-inserted DOM nodes
|
1307
|
+
if (mappedNodes.length > 0)
|
1308
|
+
ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);
|
1309
|
+
|
1310
|
+
// Replace the contents of the mappedNodes array, thereby updating the record
|
1311
|
+
// of which nodes would be deleted if valueToMap was itself later removed
|
1312
|
+
mappedNodes.splice(0, mappedNodes.length);
|
1313
|
+
ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
|
1314
|
+
}, null, { disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
|
1315
|
+
return mappedNodes;
|
1316
|
+
}
|
1317
|
+
|
1243
1318
|
ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options) {
|
1244
1319
|
// Compare the provided array against the previous one
|
1245
1320
|
array = array || [];
|
@@ -1275,28 +1350,28 @@ ko.templateRewriting = (function () {
|
|
1275
1350
|
lastMappingResultIndex++;
|
1276
1351
|
break;
|
1277
1352
|
|
1278
|
-
case "added":
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1353
|
+
case "added":
|
1354
|
+
var mappedNodes = mapNodeAndRefreshWhenChanged(mapping, editScript[i].value);
|
1355
|
+
// On the first evaluation, insert the nodes at the current insertion point
|
1356
|
+
newMappingResult.push({ arrayEntry: editScript[i].value, domNodes: mappedNodes });
|
1357
|
+
for (var nodeIndex = 0, nodeIndexMax = mappedNodes.length; nodeIndex < nodeIndexMax; nodeIndex++) {
|
1358
|
+
var node = mappedNodes[nodeIndex];
|
1359
|
+
nodesAdded.push(node);
|
1360
|
+
if (insertAfterNode == null) {
|
1361
|
+
// Insert at beginning
|
1362
|
+
if (domNode.firstChild)
|
1363
|
+
domNode.insertBefore(node, domNode.firstChild);
|
1364
|
+
else
|
1365
|
+
domNode.appendChild(node);
|
1366
|
+
} else {
|
1367
|
+
// Insert after insertion point
|
1368
|
+
if (insertAfterNode.nextSibling)
|
1369
|
+
domNode.insertBefore(node, insertAfterNode.nextSibling);
|
1295
1370
|
else
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1371
|
+
domNode.appendChild(node);
|
1372
|
+
}
|
1373
|
+
insertAfterNode = node;
|
1374
|
+
}
|
1300
1375
|
break;
|
1301
1376
|
}
|
1302
1377
|
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knockoutjs-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.05'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-01-28 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: railties
|
16
|
-
requirement: &
|
16
|
+
requirement: &70366174337380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70366174337380
|
25
25
|
description: Knockout is a JavaScript library that helps you to create rich, responsive
|
26
26
|
display and editor user interfaces with a clean underlying data model
|
27
27
|
email:
|