knockoutjs-rails 1.04 → 1.05
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|