|
62 | 62 |
|
63 | 63 | var config = valueAccessor();
|
64 | 64 | config = $.extend({}, config, defaultConfig);
|
65 |
| - |
| 65 | + var dropzone = $(element); |
66 | 66 | var target = config.target; // Expected to be a ko.observableArray
|
67 | 67 | $(element).fileupload({
|
68 | 68 | url:config.url,
|
69 | 69 | autoUpload:true,
|
70 |
| - dataType:'json' |
| 70 | + dataType:'json', |
| 71 | + dropZone: dropzone |
71 | 72 | }).on('fileuploadadd', function(e, data) {
|
72 | 73 | complete(false);
|
73 | 74 | progress(1);
|
|
679 | 680 | var options = _.defaults(valueAccessor() || {}, defaults);
|
680 | 681 |
|
681 | 682 | $(element).select2(options).change(function(e) {
|
682 |
| - model($(element).val()); |
| 683 | + if (ko.isWritableObservable(model)) { // Don't try and write the value to a computed. |
| 684 | + model($(element).val()); |
| 685 | + } |
| 686 | + |
683 | 687 | });
|
684 | 688 |
|
685 | 689 | if (options.preserveColumnWidth) {
|
|
824 | 828 | return validationString;
|
825 | 829 | };
|
826 | 830 |
|
| 831 | + /** |
| 832 | + * Applies an attribute to the supplied element that controls the validation error displayed |
| 833 | + * if a particular validation rule triggers |
| 834 | + */ |
| 835 | + function addJQueryValidationEngineErrorMessageForRule(rule, message, element){ |
| 836 | + // This comes from the private _validityProp method in the validation engine. |
| 837 | + // The purpose of reproducing it here is to allow the correct error message attribute to |
| 838 | + // be applied to the element |
| 839 | + var validationEngineErrorMessageAttributeLookup = { |
| 840 | + "required": "value-missing", |
| 841 | + "custom": "custom-error", |
| 842 | + "groupRequired": "value-missing", |
| 843 | + "ajax": "custom-error", |
| 844 | + "minSize": "range-underflow", |
| 845 | + "maxSize": "range-overflow", |
| 846 | + "min": "range-underflow", |
| 847 | + "max": "range-overflow", |
| 848 | + "past": "type-mismatch", |
| 849 | + "future": "type-mismatch", |
| 850 | + "dateRange": "type-mismatch", |
| 851 | + "dateTimeRange": "type-mismatch", |
| 852 | + "maxCheckbox": "range-overflow", |
| 853 | + "minCheckbox": "range-underflow", |
| 854 | + "equals": "pattern-mismatch", |
| 855 | + "funcCall": "custom-error", |
| 856 | + "funcCallRequired": "custom-error", |
| 857 | + "creditCard": "pattern-mismatch", |
| 858 | + "condRequired": "value-missing" |
| 859 | + }; |
| 860 | + |
| 861 | + var errorAttribute = 'data-errormessage'; |
| 862 | + var errorAttributeSuffix = validationEngineErrorMessageAttributeLookup[rule]; |
| 863 | + if (errorAttributeSuffix) { |
| 864 | + errorAttribute += '-' + errorAttributeSuffix; |
| 865 | + } |
| 866 | + $(element).attr(errorAttribute, message); |
| 867 | + }; |
| 868 | + |
827 | 869 | /**
|
828 | 870 | * Adds or removes the jqueryValidationEngine validation attributes 'data-validation-engine' and 'data-errormessage'
|
829 | 871 | * to/from the supplied element.
|
|
870 | 912 | var modelItem = valueAccessor();
|
871 | 913 |
|
872 | 914 | var validationAttributes = ko.pureComputed(function() {
|
873 |
| - return createValidationString(modelItem, viewModel); |
| 915 | + var validationString = createValidationString(modelItem, viewModel); |
| 916 | + _.each(modelItem || [], function(ruleConfig) { |
| 917 | + if (ruleConfig.message) { |
| 918 | + addJQueryValidationEngineErrorMessageForRule(ruleConfig.rule, ruleConfig.message, element); |
| 919 | + } |
| 920 | + }); |
| 921 | + return validationString; |
874 | 922 | });
|
875 | 923 | validationAttributes.subscribe(function(value) {
|
876 | 924 | updateJQueryValidationEngineAttributes(element, value);
|
|
1003 | 1051 | element.removeAttribute("disabled");
|
1004 | 1052 | else if ((!value) && (!element.disabled)) {
|
1005 | 1053 | element.disabled = true;
|
1006 |
| - var value = allBindings.get('value'); |
1007 |
| - if (ko.isObservable(value)) { |
1008 |
| - value(undefined); |
| 1054 | + var possibleValueBindings = ['value', 'datepicker']; |
| 1055 | + for (var i=0; i<possibleValueBindings.length; i++) { |
| 1056 | + var value = allBindings.get(possibleValueBindings[i]); |
| 1057 | + if (ko.isObservable(value)) { |
| 1058 | + value(undefined); |
| 1059 | + } |
1009 | 1060 | }
|
1010 | 1061 | }
|
1011 | 1062 |
|
|
1160 | 1211 | }
|
1161 | 1212 | };
|
1162 | 1213 |
|
| 1214 | + ko.extenders.dataLoader = function(target, options) { |
| 1215 | + |
| 1216 | + var dataLoader = new ecodata.forms.dataLoader(target.context, target.config); |
| 1217 | + var dataLoaderConfig = target.get('computed'); |
| 1218 | + if (!dataLoaderConfig) { |
| 1219 | + throw "This extender can only be used with the metadata extender and expects a computed property to be defined"; |
| 1220 | + } |
| 1221 | + var dependencyTracker = ko.computed(function () { |
| 1222 | + return dataLoader.prepop(dataLoaderConfig).done( function(data) { |
| 1223 | + target(data); |
| 1224 | + }); |
| 1225 | + }); // This is a computed rather than a pureComputed as it has a side effect. |
| 1226 | + return target; |
| 1227 | + }; |
| 1228 | + |
| 1229 | + ko.bindingHandlers['triggerPrePopulate'] = { |
| 1230 | + 'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) { |
| 1231 | + var dataModelItem = valueAccessor(); |
| 1232 | + var behaviours = dataModelItem.get('behaviour'); |
| 1233 | + for (var i = 0; i < behaviours.length; i++) { |
| 1234 | + var behaviour = behaviours[i]; |
| 1235 | + |
| 1236 | + if (behaviour.type == 'pre_populate') { |
| 1237 | + var config = behaviour.config; |
| 1238 | + var dataLoaderContext = dataModelItem.context; |
| 1239 | + |
| 1240 | + var dataLoader = new ecodata.forms.dataLoader(dataLoaderContext, dataModelItem.config); |
| 1241 | + |
| 1242 | + function doLoad(propTarget, value) { |
| 1243 | + |
| 1244 | + if (_.isFunction(propTarget.loadData)) { |
| 1245 | + propTarget.loadData(value); |
| 1246 | + } else if (_.isFunction(propTarget.load)) { |
| 1247 | + propTarget.load(value); |
| 1248 | + } else if (ko.isObservable(propTarget)) { |
| 1249 | + propTarget(value); |
| 1250 | + } else { |
| 1251 | + console.log("Warning: target for pre-populate is invalid"); |
| 1252 | + } |
| 1253 | + } |
| 1254 | + var dependencyTracker = ko.computed(function () { |
| 1255 | + var initialised = (dataModelItem.context.lifecycleState && dataModelItem.context.lifecycleState.state == 'initialised'); |
| 1256 | + |
| 1257 | + dataLoader.prepop(config).done(function (data) { |
| 1258 | + |
| 1259 | + if (config.waitForInitialisation && !initialised) { |
| 1260 | + console.log("Not applying any updates during initialisation") |
| 1261 | + return; |
| 1262 | + } |
| 1263 | + |
| 1264 | + data = data || {}; |
| 1265 | + var configTarget = config.target; |
| 1266 | + var target; |
| 1267 | + if (!configTarget) { |
| 1268 | + target = viewModel; |
| 1269 | + } |
| 1270 | + else { |
| 1271 | + target = dataModelItem.findNearestByName(configTarget.name, bindingContext); |
| 1272 | + } |
| 1273 | + if (!target) { |
| 1274 | + throw "Unable to locate target for pre-population: "+target; |
| 1275 | + } |
| 1276 | + if (configTarget.type == "singleValue") { |
| 1277 | + // This needs to be done to load data into the feature data type due to the awkward |
| 1278 | + // way the loadData method uses the feature id from the reporting site and the |
| 1279 | + // direct observable accepts geojson. |
| 1280 | + target(data); |
| 1281 | + } |
| 1282 | + else if (configTarget.type == "singleLoad") { |
| 1283 | + doLoad(target, data); |
| 1284 | + } |
| 1285 | + else { |
| 1286 | + target = target.data || target; |
| 1287 | + for (var prop in data) { |
| 1288 | + if (target.hasOwnProperty(prop)) { |
| 1289 | + var propTarget = target[prop]; |
| 1290 | + doLoad(propTarget, data[prop]); |
| 1291 | + } |
| 1292 | + } |
| 1293 | + } |
| 1294 | + |
| 1295 | + }); // This is a computed rather than a pureComputed as it has a side effect. |
| 1296 | + }); |
| 1297 | + } |
| 1298 | + } |
| 1299 | + |
| 1300 | + } |
| 1301 | + }; |
| 1302 | + |
| 1303 | + ko.bindingHandlers['disableClick'] = { |
| 1304 | + 'update': function (element, valueAccessor) { |
| 1305 | + var value = ko.utils.unwrapObservable(valueAccessor()); |
| 1306 | + if (value) { |
| 1307 | + this.eventHandler = $(element).on('mousedown.disableClick keydown.disableClick touchstart.disableClick', function(e) { |
| 1308 | + e.preventDefault(); |
| 1309 | + return false; |
| 1310 | + }); |
| 1311 | + } |
| 1312 | + else { |
| 1313 | + if (this.eventHandler) { |
| 1314 | + $(element).off('mousedown.disableClick keydown.disableClick touchstart.disableClick'); |
| 1315 | + } |
| 1316 | + } |
| 1317 | + |
| 1318 | + } |
| 1319 | + }; |
| 1320 | + |
1163 | 1321 | })();
|
1164 | 1322 |
|
0 commit comments