forms-angular 0.12.0-beta.19 → 0.12.0-beta.190
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.
- package/dist/client/forms-angular-bs-common.less +44 -4
- package/dist/client/forms-angular-bs2-specific.less +1 -1
- package/dist/client/forms-angular-bs3-specific.less +1 -1
- package/dist/client/forms-angular-with-bs2.css +2 -2
- package/dist/client/forms-angular-with-bs3.css +3 -3
- package/dist/client/forms-angular-with-bs3.less +1 -1
- package/dist/client/forms-angular.js +1328 -674
- package/dist/client/forms-angular.min.js +1 -1
- package/dist/client/index.d.ts +124 -49
- package/dist/server/data_form.js +1437 -951
- package/dist/server/index.d.ts +109 -0
- package/package.json +40 -41
- package/CHANGELOG.md +0 -255
|
@@ -9,13 +9,13 @@ var fng;
|
|
|
9
9
|
restrict: 'AE',
|
|
10
10
|
replace: true,
|
|
11
11
|
template: '<li ng-show="items.length > 0" class="mcdd" uib-dropdown>' +
|
|
12
|
-
' <a uib-dropdown-toggle>' +
|
|
12
|
+
' <a href="#" uib-dropdown-toggle>' +
|
|
13
13
|
' {{contextMenu}} <b class="caret"></b>' +
|
|
14
14
|
' </a>' +
|
|
15
15
|
' <ul class="uib-dropdown-menu dropdown-menu">' +
|
|
16
16
|
' <li ng-repeat="choice in items" ng-hide="isHidden($index)" ng-class="dropdownClass($index)">' +
|
|
17
|
-
' <a ng-show="choice.text" class="dropdown-option" ng-href="{{choice.url}}" ng-click="doClick($index, $event)">' +
|
|
18
|
-
' {{choice.text}}' +
|
|
17
|
+
' <a ng-show="choice.text || choice.textFunc" class="dropdown-option" ng-href="{{choice.url || choice.urlFunc()}}" ng-click="doClick($index, $event)">' +
|
|
18
|
+
' {{ choice.text || choice.textFunc() }}' +
|
|
19
19
|
' </a>' +
|
|
20
20
|
' </li>' +
|
|
21
21
|
' </ul>' +
|
|
@@ -31,16 +31,11 @@ var fng;
|
|
|
31
31
|
var directives;
|
|
32
32
|
(function (directives) {
|
|
33
33
|
/*@ngInject*/
|
|
34
|
-
|
|
34
|
+
errorDisplay.$inject = ["cssFrameworkService"];
|
|
35
|
+
function errorDisplay(cssFrameworkService) {
|
|
35
36
|
return {
|
|
36
37
|
restrict: 'E',
|
|
37
|
-
|
|
38
|
-
' <div class="alert alert-error col-lg-offset-3 offset3 col-lg-6 col-xs-12 span6 alert-warning alert-dismissable">' +
|
|
39
|
-
' <button type="button" class="close" ng-click="dismissError()">×</button>' +
|
|
40
|
-
' <h4>{{alertTitle}}</h4>' +
|
|
41
|
-
' <div ng-bind-html="errorMessage"></div>' +
|
|
42
|
-
' </div>' +
|
|
43
|
-
'</div>'
|
|
38
|
+
templateUrl: 'error-display-' + cssFrameworkService.framework() + '.html'
|
|
44
39
|
};
|
|
45
40
|
}
|
|
46
41
|
directives.errorDisplay = errorDisplay;
|
|
@@ -48,6 +43,44 @@ var fng;
|
|
|
48
43
|
})(fng || (fng = {}));
|
|
49
44
|
/// <reference path="../../../../node_modules/@types/angular/index.d.ts" />
|
|
50
45
|
var fng;
|
|
46
|
+
(function (fng) {
|
|
47
|
+
var controllers;
|
|
48
|
+
(function (controllers) {
|
|
49
|
+
/*@ngInject*/
|
|
50
|
+
LinkCtrl.$inject = ["$scope"];
|
|
51
|
+
function LinkCtrl($scope) {
|
|
52
|
+
/**
|
|
53
|
+
* In the event that the link is part of a form that belongs to a (ui-bootstrap) modal,
|
|
54
|
+
* close the modal
|
|
55
|
+
*/
|
|
56
|
+
$scope.checkNotModal = function () {
|
|
57
|
+
var elm = $scope.element[0];
|
|
58
|
+
var parentNode;
|
|
59
|
+
var finished = false;
|
|
60
|
+
var fakeEvt = {
|
|
61
|
+
preventDefault: angular.noop,
|
|
62
|
+
stopPropagation: angular.noop,
|
|
63
|
+
target: 1,
|
|
64
|
+
currentTarget: 1
|
|
65
|
+
};
|
|
66
|
+
do {
|
|
67
|
+
parentNode = elm.parentNode;
|
|
68
|
+
if (!parentNode) {
|
|
69
|
+
finished = true;
|
|
70
|
+
}
|
|
71
|
+
else if (typeof parentNode.getAttribute === "function" && parentNode.getAttribute('uib-modal-window')) {
|
|
72
|
+
angular.element(elm).scope().close(fakeEvt);
|
|
73
|
+
finished = true;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
elm = parentNode;
|
|
77
|
+
}
|
|
78
|
+
} while (!finished);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
controllers.LinkCtrl = LinkCtrl;
|
|
82
|
+
})(controllers = fng.controllers || (fng.controllers = {}));
|
|
83
|
+
})(fng || (fng = {}));
|
|
51
84
|
(function (fng) {
|
|
52
85
|
var directives;
|
|
53
86
|
(function (directives) {
|
|
@@ -58,38 +91,124 @@ var fng;
|
|
|
58
91
|
restrict: 'E',
|
|
59
92
|
scope: { dataSrc: '&model' },
|
|
60
93
|
link: function (scope, element, attrs) {
|
|
61
|
-
var ref =
|
|
94
|
+
var ref = attrs['ref'];
|
|
95
|
+
var isLabel = attrs['text'] && (unescape(attrs['text']) !== attrs['text']);
|
|
62
96
|
var form = attrs['form'];
|
|
97
|
+
var linktab = attrs['linktab'];
|
|
63
98
|
scope['readonly'] = attrs['readonly'];
|
|
99
|
+
scope['element'] = element;
|
|
64
100
|
form = form ? form + '/' : '';
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
101
|
+
linktab = linktab ? '/' + linktab : '';
|
|
102
|
+
if (isLabel) {
|
|
103
|
+
var workScope = scope;
|
|
104
|
+
var workString = '';
|
|
105
|
+
while (typeof workScope['baseSchema'] !== "function" && workScope.$parent) {
|
|
106
|
+
if (typeof workScope['$index'] !== "undefined") {
|
|
107
|
+
throw new Error('No support for $index at this level - ' + workString);
|
|
108
|
+
}
|
|
109
|
+
workScope = workScope.$parent;
|
|
110
|
+
workString = workString + '$parent.';
|
|
111
|
+
}
|
|
112
|
+
var attrib = attrs['fld'];
|
|
113
|
+
var watchExpression;
|
|
114
|
+
var splitAttrib = attrib.split('.');
|
|
115
|
+
if (scope.$parent.subDoc && (scope.$parent.subDoc[attrib] || scope.$parent.subDoc[splitAttrib[splitAttrib.length - 1]])) {
|
|
116
|
+
// Support for use in directives in arrays
|
|
117
|
+
if (scope.$parent.subDoc[attrib]) {
|
|
118
|
+
watchExpression = workString + 'subDoc.' + attrib;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
watchExpression = workString + 'subDoc.' + splitAttrib[splitAttrib.length - 1];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
if (typeof workScope['$index'] !== "undefined") {
|
|
126
|
+
attrib = splitAttrib.pop();
|
|
127
|
+
attrib = splitAttrib.join('.') + '[' + workScope['$index'] + '].' + attrib;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
attrib = '.' + attrib;
|
|
131
|
+
}
|
|
132
|
+
watchExpression = workString + 'record' + attrib;
|
|
133
|
+
}
|
|
134
|
+
scope.$watch(watchExpression, function (newVal) {
|
|
135
|
+
if (newVal) {
|
|
136
|
+
if (/^[a-f0-9]{24}/.test(newVal.toString())) {
|
|
137
|
+
newVal = newVal.slice(0, 24);
|
|
138
|
+
}
|
|
139
|
+
else if (newVal.id && /^[a-f0-9]{24}/.test(newVal.id)) {
|
|
140
|
+
newVal = newVal.id.slice(0, 24);
|
|
141
|
+
}
|
|
142
|
+
else if (scope.$parent["f_" + attrs['fld'] + "Options"]) {
|
|
143
|
+
// extract from lookups
|
|
144
|
+
var i = scope.$parent["f_" + attrs['fld'] + "Options"].indexOf(newVal);
|
|
145
|
+
if (i > -1) {
|
|
146
|
+
newVal = scope.$parent["f_" + attrs['fld'] + "_ids"][i];
|
|
80
147
|
}
|
|
81
148
|
else {
|
|
82
|
-
|
|
149
|
+
newVal = undefined;
|
|
83
150
|
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
newVal = undefined;
|
|
154
|
+
}
|
|
155
|
+
if (newVal) {
|
|
156
|
+
scope['link'] = routingService.buildUrl(ref + '/' + form + (newVal.id || newVal) + '/edit' + linktab);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
scope['link'] = undefined;
|
|
160
|
+
}
|
|
87
161
|
}
|
|
88
|
-
|
|
89
|
-
|
|
162
|
+
else {
|
|
163
|
+
scope['link'] = undefined;
|
|
164
|
+
}
|
|
165
|
+
}, true);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
if (attrs['text'] && attrs['text'].length > 0) {
|
|
169
|
+
scope['text'] = attrs['text'];
|
|
170
|
+
}
|
|
171
|
+
var index = scope['$parent']['$index'];
|
|
172
|
+
scope.$watch('dataSrc()', function (newVal) {
|
|
173
|
+
if (newVal) {
|
|
174
|
+
if (typeof index !== 'undefined' && angular.isArray(newVal)) {
|
|
175
|
+
newVal = newVal[index];
|
|
176
|
+
}
|
|
177
|
+
scope['link'] = routingService.buildUrl(ref + '/' + form + newVal + '/edit' + linktab);
|
|
178
|
+
if (!scope['text']) {
|
|
179
|
+
SubmissionsService.getListAttributes(ref, newVal).then(function (response) {
|
|
180
|
+
var data = response.data;
|
|
181
|
+
if (data.success === false) {
|
|
182
|
+
scope['text'] = data.err;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
scope['text'] = data.list;
|
|
186
|
+
}
|
|
187
|
+
}, function (response) {
|
|
188
|
+
scope['text'] = 'Error ' + response.status + ': ' + response.data;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}, true);
|
|
193
|
+
}
|
|
90
194
|
},
|
|
195
|
+
controller: "LinkCtrl",
|
|
91
196
|
template: function (element, attrs) {
|
|
92
|
-
|
|
197
|
+
function handleAnchor(contents) {
|
|
198
|
+
return "<a ng-click=\"checkNotModal()\" ng-href=\"{{ link || '#' }}\" class=\"fng-link\">".concat(contents, "</a>");
|
|
199
|
+
}
|
|
200
|
+
var retVal;
|
|
201
|
+
if (attrs.readonly) {
|
|
202
|
+
retVal = '<span class="fng-link">{{text}}</span>';
|
|
203
|
+
}
|
|
204
|
+
else if (attrs['text'] && unescape(attrs['text']) !== attrs['text']) {
|
|
205
|
+
retVal = handleAnchor(unescape(attrs['text']));
|
|
206
|
+
// retVal = '<a href="{{ link }}" class="fng-link">{{text}}</a>';
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
retVal = handleAnchor('{{text}}');
|
|
210
|
+
}
|
|
211
|
+
return retVal;
|
|
93
212
|
}
|
|
94
213
|
};
|
|
95
214
|
}
|
|
@@ -146,7 +265,7 @@ var fng;
|
|
|
146
265
|
// <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
|
|
147
266
|
// </div>
|
|
148
267
|
//
|
|
149
|
-
// Inline
|
|
268
|
+
// Inline or stacked
|
|
150
269
|
// <div class="form-group">
|
|
151
270
|
// <label class="sr-only" for="exampleInputEmail2">Email address</label>
|
|
152
271
|
// <input type="email" class="form-control" id="exampleInputEmail2" placeholder="Enter email">
|
|
@@ -165,7 +284,7 @@ var fng;
|
|
|
165
284
|
// <input type="text" placeholder="Type something…">
|
|
166
285
|
// <span class="help-block">Example block-level help text here.</span>
|
|
167
286
|
//
|
|
168
|
-
// Inline
|
|
287
|
+
// Inline or Stacked
|
|
169
288
|
// <input type="text" class="input-small" placeholder="Email">
|
|
170
289
|
var subkeys = [];
|
|
171
290
|
var tabsSetup = tabsSetupState.N;
|
|
@@ -206,7 +325,7 @@ var fng;
|
|
|
206
325
|
var lastPart = compoundName.slice(root.length + 1);
|
|
207
326
|
if (options.index) {
|
|
208
327
|
modelString += root + '[' + options.index + '].' + lastPart;
|
|
209
|
-
idString = 'f_' + modelString.slice(modelBase.length).replace(/(\.|\[
|
|
328
|
+
idString = 'f_' + modelString.slice(modelBase.length).replace(/(\.|\[|]\.)/g, '-');
|
|
210
329
|
}
|
|
211
330
|
else {
|
|
212
331
|
modelString += root;
|
|
@@ -228,18 +347,33 @@ var fng;
|
|
|
228
347
|
var allInputsVars = formMarkupHelper.allInputsVars(scope, fieldInfo, options, modelString, idString, nameString);
|
|
229
348
|
var common = allInputsVars.common;
|
|
230
349
|
var value;
|
|
231
|
-
var requiredStr = (isRequired || fieldInfo.required) ? ' required' : '';
|
|
232
350
|
isRequired = isRequired || fieldInfo.required;
|
|
233
|
-
var requiredStr = isRequired ? ' required' : '';
|
|
351
|
+
var requiredStr = isRequired ? ' required ' : '';
|
|
234
352
|
var enumInstruction;
|
|
353
|
+
function handleReadOnlyDisabled(readonly) {
|
|
354
|
+
var retVal = '';
|
|
355
|
+
if (readonly) {
|
|
356
|
+
// despite the option being "readonly", we should use disabled and ng-disabled rather than their readonly
|
|
357
|
+
// equivalents (which give controls the appearance of being read-only, but don't actually prevent user
|
|
358
|
+
// interaction)
|
|
359
|
+
if (typeof readonly === "boolean") {
|
|
360
|
+
retVal = " disabled ";
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
retVal = " ng-disabled=\"".concat(readonly, "\" ");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return retVal;
|
|
367
|
+
}
|
|
235
368
|
switch (fieldInfo.type) {
|
|
236
369
|
case 'select':
|
|
237
370
|
if (fieldInfo.select2) {
|
|
238
371
|
value = '<input placeholder="fng-select2 has been removed" readonly>';
|
|
239
372
|
}
|
|
240
373
|
else {
|
|
241
|
-
common += (fieldInfo.readonly
|
|
374
|
+
common += handleReadOnlyDisabled(fieldInfo.readonly);
|
|
242
375
|
common += fieldInfo.add ? (' ' + fieldInfo.add + ' ') : '';
|
|
376
|
+
common += " aria-label=\"".concat(fieldInfo.label && fieldInfo.label !== "" ? fieldInfo.label : fieldInfo.name, "\" ");
|
|
243
377
|
value = '<select ' + common + 'class="' + allInputsVars.formControl.trim() + allInputsVars.compactClass + allInputsVars.sizeClassBS2 + '" ' + requiredStr + '>';
|
|
244
378
|
if (!isRequired) {
|
|
245
379
|
value += '<option></option>';
|
|
@@ -268,25 +402,31 @@ var fng;
|
|
|
268
402
|
}
|
|
269
403
|
break;
|
|
270
404
|
case 'link':
|
|
271
|
-
|
|
272
|
-
fieldInfo.ref = { type: 'lookup', collection: fieldInfo.ref };
|
|
273
|
-
console.warn("Support for string type \"ref\" property is deprecated - use ref:" + JSON.stringify(fieldInfo.ref));
|
|
274
|
-
}
|
|
275
|
-
value = '<fng-link model="' + modelString + '" ref="' + JSON.stringify(fieldInfo.ref).replace(/"/g, '"') + '"';
|
|
405
|
+
value = '<fng-link model="' + modelString + '" ref="' + fieldInfo.ref + '"';
|
|
276
406
|
if (fieldInfo.form) {
|
|
277
407
|
value += ' form="' + fieldInfo.form + '"';
|
|
278
408
|
}
|
|
279
|
-
if (fieldInfo.
|
|
280
|
-
value += '
|
|
409
|
+
if (fieldInfo.linktab) {
|
|
410
|
+
value += ' linktab="' + fieldInfo.linktab + '"';
|
|
411
|
+
}
|
|
412
|
+
if (fieldInfo.linktext) {
|
|
413
|
+
value += ' text="' + fieldInfo.linktext + '"';
|
|
281
414
|
}
|
|
282
415
|
if (fieldInfo.readonly) {
|
|
283
|
-
|
|
416
|
+
if (typeof fieldInfo.readonly === "boolean") {
|
|
417
|
+
value += " readonly=\"true\"";
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
value += " ng-readonly=\"".concat(fieldInfo.readonly, "\"");
|
|
421
|
+
}
|
|
284
422
|
}
|
|
285
423
|
value += '></fng-link>';
|
|
286
424
|
break;
|
|
287
425
|
case 'radio':
|
|
288
426
|
value = '';
|
|
289
|
-
common += requiredStr
|
|
427
|
+
common += requiredStr;
|
|
428
|
+
common += handleReadOnlyDisabled(fieldInfo.readonly);
|
|
429
|
+
common += fieldInfo.add ? (' ' + fieldInfo.add + ' ') : '';
|
|
290
430
|
var separateLines = options.formstyle === 'vertical' || (options.formstyle !== 'inline' && !fieldInfo.inlineRadio);
|
|
291
431
|
if (angular.isArray(fieldInfo.options)) {
|
|
292
432
|
if (options.subschema) {
|
|
@@ -296,8 +436,7 @@ var fng;
|
|
|
296
436
|
var thisCommon_1;
|
|
297
437
|
angular.forEach(fieldInfo.options, function (optValue, idx) {
|
|
298
438
|
thisCommon_1 = common.replace('id="', 'id="' + idx + '-');
|
|
299
|
-
value +=
|
|
300
|
-
value += ' value="' + optValue + '">' + optValue;
|
|
439
|
+
value += "<input ".concat(thisCommon_1, " type=\"radio\" aria-label=\"").concat(optValue, "\" value=\"").concat(optValue, "\">").concat(optValue);
|
|
301
440
|
if (separateLines) {
|
|
302
441
|
value += '<br />';
|
|
303
442
|
}
|
|
@@ -312,18 +451,16 @@ var fng;
|
|
|
312
451
|
}
|
|
313
452
|
enumInstruction = generateEnumInstructions();
|
|
314
453
|
value += '<' + tagType + ' ng-repeat="option in ' + enumInstruction.repeat + '">';
|
|
315
|
-
value +=
|
|
316
|
-
value += enumInstruction.label || enumInstruction.value;
|
|
317
|
-
value += ' }} </' + tagType + '> ';
|
|
454
|
+
value += "<input ".concat(common.replace('id="', 'id="{{$index}}-'), " type=\"radio\" aria-label=\"").concat(enumInstruction.value, "\" value=\"{{ ").concat(enumInstruction.value, " }}\"> {{ ").concat(enumInstruction.label || enumInstruction.value, " }} </").concat(tagType, "> ");
|
|
318
455
|
}
|
|
319
456
|
break;
|
|
320
457
|
case 'checkbox':
|
|
321
|
-
common += requiredStr
|
|
458
|
+
common += requiredStr;
|
|
459
|
+
common += handleReadOnlyDisabled(fieldInfo.readonly);
|
|
460
|
+
common += fieldInfo.add ? (' ' + fieldInfo.add + ' ') : '';
|
|
461
|
+
value = formMarkupHelper.generateSimpleInput(common, fieldInfo, options);
|
|
322
462
|
if (cssFrameworkService.framework() === 'bs3') {
|
|
323
|
-
value = '<div class="checkbox"
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
value = formMarkupHelper.generateSimpleInput(common, fieldInfo, options);
|
|
463
|
+
value = '<div class="checkbox">' + value + '</div>';
|
|
327
464
|
}
|
|
328
465
|
break;
|
|
329
466
|
default:
|
|
@@ -344,7 +481,7 @@ var fng;
|
|
|
344
481
|
allInputsVars.sizeClassBS3 = 'col-xs-12';
|
|
345
482
|
}
|
|
346
483
|
}
|
|
347
|
-
value = '<textarea ' + common + '
|
|
484
|
+
value = '<textarea ' + common + '></textarea>';
|
|
348
485
|
}
|
|
349
486
|
else {
|
|
350
487
|
value = formMarkupHelper.generateSimpleInput(common, fieldInfo, options);
|
|
@@ -364,6 +501,9 @@ var fng;
|
|
|
364
501
|
case 'inline':
|
|
365
502
|
result = 'form-inline';
|
|
366
503
|
break;
|
|
504
|
+
case 'stacked':
|
|
505
|
+
result = 'form-stacked';
|
|
506
|
+
break;
|
|
367
507
|
case 'horizontalCompact':
|
|
368
508
|
result = 'form-horizontal compact';
|
|
369
509
|
break;
|
|
@@ -391,7 +531,7 @@ var fng;
|
|
|
391
531
|
if (tabNo >= 0) {
|
|
392
532
|
// TODO Figure out tab history updates (check for other tab-history-todos)
|
|
393
533
|
// result.before = '<uib-tab deselect="tabDeselect($event, $selectedIndex)" select="updateQueryForTab(\'' + info.title + '\')" heading="' + info.title + '"'
|
|
394
|
-
result.before = '<uib-tab select="updateQueryForTab(\'' + info.title + '\')" heading="' + info.title + '"';
|
|
534
|
+
result.before = '<uib-tab deselect="tabDeselect($event, $selectedIndex)" select="updateQueryForTab(\'' + info.title + '\')" heading="' + info.title + '"';
|
|
395
535
|
if (tabNo > 0) {
|
|
396
536
|
result.before += 'active="tabs[' + tabNo + '].active"';
|
|
397
537
|
}
|
|
@@ -452,6 +592,41 @@ var fng;
|
|
|
452
592
|
}
|
|
453
593
|
return result;
|
|
454
594
|
};
|
|
595
|
+
var generateInlineHeaders = function (instructionsArray, options, model, evenWhenEmpty) {
|
|
596
|
+
// "column" headers for nested schemas that use formStyle: "inline" will only line up with their respective
|
|
597
|
+
// controls when widths are applied to both the cg_f_xxxx and col_label_xxxx element using css.
|
|
598
|
+
// Likely, the widths will need to be the same, so consider using the following:
|
|
599
|
+
// div[id$="_f_<collection>_<field>"] {
|
|
600
|
+
// width: 100px;
|
|
601
|
+
// }
|
|
602
|
+
// one column can grow to the remaining available width thus:
|
|
603
|
+
// div[id$="_f_<collection>_<field>"] {
|
|
604
|
+
// flex-grow: 1;
|
|
605
|
+
// }
|
|
606
|
+
var hideWhenEmpty = evenWhenEmpty ? "" : "ng-hide=\"!".concat(model, " || ").concat(model, ".length === 0\"");
|
|
607
|
+
var res = "<div class=\"inline-col-headers\" style=\"display:flex\" ".concat(hideWhenEmpty, ">");
|
|
608
|
+
for (var _i = 0, instructionsArray_1 = instructionsArray; _i < instructionsArray_1.length; _i++) {
|
|
609
|
+
var info = instructionsArray_1[_i];
|
|
610
|
+
// need to call this now to ensure the id is set. will probably be (harmlessly) called again later.
|
|
611
|
+
inferMissingProperties(info, options);
|
|
612
|
+
res += '<div ';
|
|
613
|
+
info.showWhen = info.showWhen || info.showwhen; // deal with use within a directive
|
|
614
|
+
if (info.showWhen) {
|
|
615
|
+
if (typeof info.showWhen === 'string') {
|
|
616
|
+
res += 'ng-show="' + info.showWhen + '"';
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
res += 'ng-show="' + formMarkupHelper.generateNgShow(info.showWhen, model) + '"';
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (info.id && typeof info.id.replace === "function") {
|
|
623
|
+
res += ' id="col_label_' + info.id.replace(/\./g, '-') + '"';
|
|
624
|
+
}
|
|
625
|
+
res += " class=\"inline-col-header\"><label for=\"".concat(info.id, "\" class=\"control-label\">").concat(info.label, "</label></div>");
|
|
626
|
+
}
|
|
627
|
+
res += "</div>";
|
|
628
|
+
return res;
|
|
629
|
+
};
|
|
455
630
|
var handleField = function (info, options) {
|
|
456
631
|
var fieldChrome = formMarkupHelper.fieldChrome(scope, info, options);
|
|
457
632
|
var template = fieldChrome.template;
|
|
@@ -474,7 +649,8 @@ var fng;
|
|
|
474
649
|
formstyle: options.formstyle,
|
|
475
650
|
subkey: schemaDefName + '_subkey',
|
|
476
651
|
subkeyno: arraySel,
|
|
477
|
-
subschemaroot: info.name
|
|
652
|
+
subschemaroot: info.name,
|
|
653
|
+
suppressNestingWarning: info.suppressNestingWarning
|
|
478
654
|
});
|
|
479
655
|
template += topAndTail.after;
|
|
480
656
|
}
|
|
@@ -482,7 +658,9 @@ var fng;
|
|
|
482
658
|
}
|
|
483
659
|
else {
|
|
484
660
|
if (options.subschema) {
|
|
485
|
-
|
|
661
|
+
if (!options.suppressNestingWarning) {
|
|
662
|
+
console.log('Attempts at supporting deep nesting have been removed - will hopefully be re-introduced at a later date');
|
|
663
|
+
}
|
|
486
664
|
}
|
|
487
665
|
else {
|
|
488
666
|
var model = (options.model || 'record') + '.' + info.name;
|
|
@@ -504,20 +682,24 @@ var fng;
|
|
|
504
682
|
}
|
|
505
683
|
}
|
|
506
684
|
/* Array body */
|
|
507
|
-
|
|
685
|
+
if (info.formStyle === "inline" && info.inlineHeaders) {
|
|
686
|
+
template += generateInlineHeaders(info.schema, options, model, info.inlineHeaders === "always");
|
|
687
|
+
}
|
|
688
|
+
template += '<ol class="sub-doc"' + (info.sortable ? " ui-sortable=\"sortableOptions\" ng-model=\"".concat(model, "\"") : '') + '>';
|
|
508
689
|
template += '<li ng-form class="' + (cssFrameworkService.framework() === 'bs2' ? 'row-fluid ' : '') +
|
|
509
|
-
|
|
690
|
+
(info.inlineHeaders ? 'width-controlled ' : '') +
|
|
691
|
+
convertFormStyleToClass(info.formStyle) + ' ' + (info.ngClass ? "ng-class:" + info.ngClass : "") + '" name="form_' + niceName + '{{$index}}" class="sub-doc well" id="' + info.id + 'List_{{$index}}" ' +
|
|
510
692
|
' ng-repeat="subDoc in ' + model + ' track by $index">';
|
|
511
693
|
if (cssFrameworkService.framework() === 'bs2') {
|
|
512
694
|
template += '<div class="row-fluid sub-doc">';
|
|
513
695
|
}
|
|
514
|
-
if (
|
|
696
|
+
if (info.noRemove !== true || info.customSubDoc) {
|
|
515
697
|
template += ' <div class="sub-doc-btns">';
|
|
516
698
|
if (typeof info.customSubDoc == 'string') {
|
|
517
699
|
template += info.customSubDoc;
|
|
518
700
|
}
|
|
519
701
|
if (info.noRemove !== true) {
|
|
520
|
-
template += "<button "
|
|
702
|
+
template += "<button ".concat(info.noRemove ? 'ng-hide="' + info.noRemove + '"' : '', " name=\"remove_").concat(info.id, "_btn\" ng-click=\"remove('").concat(info.name, "', $index, $event)\"");
|
|
521
703
|
if (info.remove) {
|
|
522
704
|
template += ' class="remove-btn btn btn-mini btn-default btn-xs form-btn"><i class="' + formMarkupHelper.glyphClass() + '-minus"></i> Remove';
|
|
523
705
|
}
|
|
@@ -534,31 +716,64 @@ var fng;
|
|
|
534
716
|
}
|
|
535
717
|
template += '</div> ';
|
|
536
718
|
}
|
|
719
|
+
var parts = void 0;
|
|
720
|
+
if (info.subDocContainerType) {
|
|
721
|
+
var containerType = scope[info.subDocContainerType] || info.subDocContainerType;
|
|
722
|
+
var containerProps = Object.assign({ containerType: containerType }, info.subDocContainerProps);
|
|
723
|
+
parts = containerInstructions(containerProps);
|
|
724
|
+
}
|
|
725
|
+
if (parts === null || parts === void 0 ? void 0 : parts.before) {
|
|
726
|
+
template += parts.before;
|
|
727
|
+
}
|
|
537
728
|
template += processInstructions(info.schema, false, {
|
|
538
729
|
subschema: 'true',
|
|
539
730
|
formstyle: info.formStyle,
|
|
540
731
|
model: options.model,
|
|
541
|
-
subschemaroot: info.name
|
|
732
|
+
subschemaroot: info.name,
|
|
733
|
+
suppressNestingWarning: info.suppressNestingWarning
|
|
542
734
|
});
|
|
735
|
+
if (parts === null || parts === void 0 ? void 0 : parts.after) {
|
|
736
|
+
template += parts.after;
|
|
737
|
+
}
|
|
543
738
|
if (cssFrameworkService.framework() === 'bs2') {
|
|
544
739
|
template += ' </div>';
|
|
545
740
|
}
|
|
546
741
|
template += '</li>';
|
|
547
742
|
template += '</ol>';
|
|
548
743
|
/* Array footer */
|
|
549
|
-
if (info.noAdd !== true || typeof info.customFooter == 'string') {
|
|
744
|
+
if (info.noAdd !== true || typeof info.customFooter == 'string' || info.noneIndicator) {
|
|
550
745
|
var footer = '';
|
|
551
746
|
if (typeof info.customFooter == 'string') {
|
|
552
747
|
footer = info.customFooter;
|
|
553
748
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
template += '<div class="row schema-foot"><div class="col-sm-offset-3">' + footer + '</div></div>';
|
|
749
|
+
var hideCond = '';
|
|
750
|
+
var indicatorShowCond = "".concat(model, ".length == 0");
|
|
751
|
+
if (info.noAdd === true) {
|
|
752
|
+
indicatorShowCond = "ng-show=\"".concat(indicatorShowCond, "\"");
|
|
559
753
|
}
|
|
560
754
|
else {
|
|
561
|
-
|
|
755
|
+
hideCond = info.noAdd ? "ng-hide=\"".concat(info.noAdd, "\"") : '';
|
|
756
|
+
indicatorShowCond = info.noAdd ? "ng-show=\"".concat(info.noAdd, " && ").concat(indicatorShowCond, "\"") : '';
|
|
757
|
+
footer += "<button ".concat(hideCond, " id=\"add_").concat(info.id, "_btn\" class=\"add-btn btn btn-default btn-xs btn-mini\" ng-click=\"add('").concat(info.name, "',$event)\">\n <i class=\"' + formMarkupHelper.glyphClass() + '-plus\"></i> \n Add\n </button>");
|
|
758
|
+
}
|
|
759
|
+
if (info.noneIndicator) {
|
|
760
|
+
footer += "<span ".concat(indicatorShowCond, " class=\"none_indicator\" id=\"no_").concat(info.id, "_indicator\">None</span>");
|
|
761
|
+
// hideCond for the schema-foot is if there's no add button and no indicator
|
|
762
|
+
hideCond = "".concat(model, ".length > 0");
|
|
763
|
+
if (info.noAdd === true) {
|
|
764
|
+
hideCond = "ng-hide=\"".concat(hideCond, "\"");
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
hideCond = info.noAdd ? "ng-hide=\"".concat(info.noAdd, " && ").concat(hideCond, "\"") : '';
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (footer !== '') {
|
|
771
|
+
if (cssFrameworkService.framework() === 'bs3') {
|
|
772
|
+
template += "<div ".concat(hideCond, " class=\"row schema-foot\"><div class=\"col-sm-offset-3\">").concat(footer, "</div></div>");
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
template += "<div ".concat(hideCond, " class = \"schema-foot \">").concat(footer, "</div>");
|
|
776
|
+
}
|
|
562
777
|
}
|
|
563
778
|
}
|
|
564
779
|
}
|
|
@@ -570,8 +785,8 @@ var fng;
|
|
|
570
785
|
var controlDivClasses = formMarkupHelper.controlDivClasses(options);
|
|
571
786
|
if (info.array) {
|
|
572
787
|
controlDivClasses.push('fng-array');
|
|
573
|
-
if (options.formstyle === 'inline') {
|
|
574
|
-
throw new Error('Cannot use arrays in an inline form');
|
|
788
|
+
if (options.formstyle === 'inline' || options.formstyle === 'stacked') {
|
|
789
|
+
throw new Error('Cannot use arrays in an inline or stacked form');
|
|
575
790
|
}
|
|
576
791
|
template += formMarkupHelper.label(scope, info, info.type !== 'link', options);
|
|
577
792
|
template += formMarkupHelper.handleArrayInputAndControlDiv(generateInput(info, info.type === 'link' ? null : 'arrayItem.x', true, info.id + '_{{$index}}', options), controlDivClasses, info, options);
|
|
@@ -579,25 +794,27 @@ var fng;
|
|
|
579
794
|
else {
|
|
580
795
|
// Single fields here
|
|
581
796
|
template += formMarkupHelper.label(scope, info, null, options);
|
|
582
|
-
if (options.required) {
|
|
583
|
-
console.log("********* Options required - found it ********");
|
|
584
|
-
}
|
|
585
797
|
template += formMarkupHelper.handleInputAndControlDiv(generateInput(info, null, options.required, info.id, options), controlDivClasses);
|
|
586
798
|
}
|
|
587
799
|
}
|
|
588
800
|
template += fieldChrome.closeTag;
|
|
589
801
|
return template;
|
|
590
802
|
};
|
|
591
|
-
var inferMissingProperties = function (info) {
|
|
803
|
+
var inferMissingProperties = function (info, options) {
|
|
592
804
|
// infer missing values
|
|
593
805
|
info.type = info.type || 'text';
|
|
594
806
|
if (info.id) {
|
|
595
|
-
if (typeof info.id === 'number' ||
|
|
807
|
+
if (typeof info.id === 'number' || info.id.match(/^[0-9]/)) {
|
|
596
808
|
info.id = '_' + info.id;
|
|
597
809
|
}
|
|
598
810
|
}
|
|
599
811
|
else {
|
|
600
|
-
|
|
812
|
+
if (options && options.noid) {
|
|
813
|
+
info.id = null;
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
info.id = 'f_' + info.name.replace(/\./g, '_');
|
|
817
|
+
}
|
|
601
818
|
}
|
|
602
819
|
info.label = (info.label !== undefined) ? (info.label === null ? '' : info.label) : $filter('titleCase')(info.name.split('.').slice(-1)[0]);
|
|
603
820
|
};
|
|
@@ -608,7 +825,11 @@ var fng;
|
|
|
608
825
|
if (instructionsArray) {
|
|
609
826
|
for (var anInstruction = 0; anInstruction < instructionsArray.length; anInstruction++) {
|
|
610
827
|
var info = instructionsArray[anInstruction];
|
|
611
|
-
if (
|
|
828
|
+
if (options.viewform) {
|
|
829
|
+
info = angular.copy(info);
|
|
830
|
+
info.readonly = true;
|
|
831
|
+
}
|
|
832
|
+
if (anInstruction === 0 && topLevel && !options.schema.match(/\$_schema_/) && typeof info.add !== 'object') {
|
|
612
833
|
info.add = info.add ? ' ' + info.add + ' ' : '';
|
|
613
834
|
if (info.add.indexOf('ui-date') === -1 && !options.noautofocus && !info.containerType) {
|
|
614
835
|
info.add = info.add + 'autofocus ';
|
|
@@ -617,9 +838,10 @@ var fng;
|
|
|
617
838
|
var callHandleField = true;
|
|
618
839
|
if (info.directive) {
|
|
619
840
|
var directiveName = info.directive;
|
|
620
|
-
var newElement =
|
|
841
|
+
var newElement = info.customHeader || "";
|
|
842
|
+
newElement += '<' + directiveName + ' model="' + (options.model || 'record') + '"';
|
|
621
843
|
var thisElement = element[0];
|
|
622
|
-
inferMissingProperties(info);
|
|
844
|
+
inferMissingProperties(info, options);
|
|
623
845
|
for (var i = 0; i < thisElement.attributes.length; i++) {
|
|
624
846
|
var thisAttr = thisElement.attributes[i];
|
|
625
847
|
switch (thisAttr.nodeName) {
|
|
@@ -655,7 +877,9 @@ var fng;
|
|
|
655
877
|
break;
|
|
656
878
|
case 'object':
|
|
657
879
|
for (var subAdd in info.add) {
|
|
658
|
-
|
|
880
|
+
if (info.add.hasOwnProperty(subAdd)) {
|
|
881
|
+
newElement += ' ' + subAdd + '="' + info.add[subAdd].toString().replace(/"/g, '"') + '"';
|
|
882
|
+
}
|
|
659
883
|
}
|
|
660
884
|
break;
|
|
661
885
|
default:
|
|
@@ -664,13 +888,21 @@ var fng;
|
|
|
664
888
|
break;
|
|
665
889
|
case directiveCamel:
|
|
666
890
|
for (var subProp in info[prop]) {
|
|
667
|
-
|
|
891
|
+
if (info[prop].hasOwnProperty(subProp)) {
|
|
892
|
+
newElement += " ".concat(info.directive, "-").concat(subProp, "=\"");
|
|
893
|
+
if (typeof info[prop][subProp] === 'string') {
|
|
894
|
+
newElement += "".concat(info[prop][subProp].replace(/"/g, '"'), "\"");
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
newElement += "".concat(JSON.stringify(info[prop][subProp]).replace(/"/g, '"'), "\"");
|
|
898
|
+
}
|
|
899
|
+
}
|
|
668
900
|
}
|
|
669
901
|
break;
|
|
670
902
|
default:
|
|
671
903
|
if (info[prop]) {
|
|
672
904
|
if (typeof info[prop] === 'string') {
|
|
673
|
-
newElement += ' fng-fld-' + prop + '="' + info[prop].
|
|
905
|
+
newElement += ' fng-fld-' + prop + '="' + info[prop].replace(/"/g, '"') + '"';
|
|
674
906
|
}
|
|
675
907
|
else {
|
|
676
908
|
newElement += ' fng-fld-' + prop + '="' + JSON.stringify(info[prop]).replace(/"/g, '"') + '"';
|
|
@@ -686,6 +918,7 @@ var fng;
|
|
|
686
918
|
}
|
|
687
919
|
}
|
|
688
920
|
newElement += 'ng-model="' + info.name + '"></' + directiveName + '>';
|
|
921
|
+
newElement += (info.customFooter || "");
|
|
689
922
|
result += newElement;
|
|
690
923
|
callHandleField = false;
|
|
691
924
|
}
|
|
@@ -722,9 +955,7 @@ var fng;
|
|
|
722
955
|
else if (options.subkey) {
|
|
723
956
|
// Don't display fields that form part of the subkey, as they should not be edited (because in these circumstances they form some kind of key)
|
|
724
957
|
var objectToSearch = angular.isArray(scope[options.subkey]) ? scope[options.subkey][0].keyList : scope[options.subkey].keyList;
|
|
725
|
-
if (_.find(objectToSearch, function (value, key) {
|
|
726
|
-
return scope[options.subkey].path + '.' + key === info.name;
|
|
727
|
-
})) {
|
|
958
|
+
if (_.find(objectToSearch, function (value, key) { return scope[options.subkey].path + '.' + key === info.name; })) {
|
|
728
959
|
callHandleField = false;
|
|
729
960
|
}
|
|
730
961
|
}
|
|
@@ -732,7 +963,7 @@ var fng;
|
|
|
732
963
|
// if (groupId) {
|
|
733
964
|
// scope['showHide' + groupId] = true;
|
|
734
965
|
// }
|
|
735
|
-
inferMissingProperties(info);
|
|
966
|
+
inferMissingProperties(info, options);
|
|
736
967
|
result += handleField(info, options);
|
|
737
968
|
}
|
|
738
969
|
}
|
|
@@ -746,8 +977,9 @@ var fng;
|
|
|
746
977
|
var unwatch = scope.$watch(attrs.schema, function (newValue) {
|
|
747
978
|
if (newValue) {
|
|
748
979
|
var newArrayValue = angular.isArray(newValue) ? newValue : [newValue]; // otherwise some old tests stop working for no real reason
|
|
749
|
-
if (newArrayValue.length > 0) {
|
|
980
|
+
if (newArrayValue.length > 0 && typeof unwatch === "function") {
|
|
750
981
|
unwatch();
|
|
982
|
+
unwatch = null;
|
|
751
983
|
var elementHtml = '';
|
|
752
984
|
var recordAttribute = attrs.model || 'record'; // By default data comes from scope.record
|
|
753
985
|
var theRecord = scope[recordAttribute];
|
|
@@ -761,12 +993,13 @@ var fng;
|
|
|
761
993
|
var customAttrs = '';
|
|
762
994
|
for (var thisAttr in attrs) {
|
|
763
995
|
if (attrs.hasOwnProperty(thisAttr)) {
|
|
764
|
-
if (thisAttr[0] !== '$' && ['name', 'formstyle', 'schema', 'subschema', 'model'].indexOf(thisAttr) === -1) {
|
|
996
|
+
if (thisAttr[0] !== '$' && ['name', 'formstyle', 'schema', 'subschema', 'model', 'viewform'].indexOf(thisAttr) === -1) {
|
|
765
997
|
customAttrs += ' ' + attrs.$attr[thisAttr] + '="' + attrs[thisAttr] + '"';
|
|
766
998
|
}
|
|
767
999
|
}
|
|
768
1000
|
}
|
|
769
|
-
|
|
1001
|
+
var tag = attrs.forceform ? 'ng-form' : 'form';
|
|
1002
|
+
elementHtml = "<".concat(tag, " name=\"").concat(scope.topLevelFormName, "\" class=\"").concat(convertFormStyleToClass(attrs.formstyle), "\" novalidate ").concat(customAttrs, ">");
|
|
770
1003
|
}
|
|
771
1004
|
if (theRecord === scope.topLevelFormName) {
|
|
772
1005
|
throw new Error('Model and Name must be distinct - they are both ' + theRecord);
|
|
@@ -782,10 +1015,12 @@ var fng;
|
|
|
782
1015
|
// If we have modelControllers we need to let them know when we have form + data
|
|
783
1016
|
var sharedData = scope[attrs.shared || 'sharedData'];
|
|
784
1017
|
var modelControllers_1 = sharedData ? sharedData.modelControllers : [];
|
|
785
|
-
if (subkeys.length > 0 || modelControllers_1.length > 0) {
|
|
1018
|
+
if ((subkeys.length > 0 || modelControllers_1.length > 0) && !scope.phaseWatcher) {
|
|
786
1019
|
var unwatch2 = scope.$watch('phase', function (newValue) {
|
|
787
|
-
|
|
1020
|
+
scope.phaseWatcher = true;
|
|
1021
|
+
if (newValue === 'ready' && typeof unwatch2 === "function") {
|
|
788
1022
|
unwatch2();
|
|
1023
|
+
unwatch2 = null;
|
|
789
1024
|
// Tell the 'model controllers' that the form and data are there
|
|
790
1025
|
for (var i = 0; i < modelControllers_1.length; i++) {
|
|
791
1026
|
if (modelControllers_1[i].onAllReady) {
|
|
@@ -814,7 +1049,7 @@ var fng;
|
|
|
814
1049
|
arrayOffset = scope[arrayToProcess[thisOffset].selectFunc](theRecord, info);
|
|
815
1050
|
}
|
|
816
1051
|
else if (arrayToProcess[thisOffset].keyList) {
|
|
817
|
-
// We are
|
|
1052
|
+
// We are choosing the array element by matching one or more keys
|
|
818
1053
|
var thisSubkeyList = arrayToProcess[thisOffset].keyList;
|
|
819
1054
|
for (arrayOffset = 0; arrayOffset < dataVal.length; arrayOffset++) {
|
|
820
1055
|
matching = true;
|
|
@@ -868,7 +1103,7 @@ var fng;
|
|
|
868
1103
|
}
|
|
869
1104
|
});
|
|
870
1105
|
}
|
|
871
|
-
$rootScope.$broadcast('formInputDone');
|
|
1106
|
+
$rootScope.$broadcast('formInputDone', attrs.name);
|
|
872
1107
|
if (formGenerator.updateDataDependentDisplay && theRecord && Object.keys(theRecord).length > 0) {
|
|
873
1108
|
// If this is not a test force the data dependent updates to the DOM
|
|
874
1109
|
formGenerator.updateDataDependentDisplay(theRecord, null, true, scope);
|
|
@@ -917,7 +1152,7 @@ var fng;
|
|
|
917
1152
|
/*@ngInject*/
|
|
918
1153
|
SearchCtrl.$inject = ["$scope", "$http", "$location", "routingService"];
|
|
919
1154
|
function SearchCtrl($scope, $http, $location, routingService) {
|
|
920
|
-
var
|
|
1155
|
+
var lastSearchSent;
|
|
921
1156
|
var _isNotMobile;
|
|
922
1157
|
_isNotMobile = (function () {
|
|
923
1158
|
var check = false;
|
|
@@ -957,7 +1192,7 @@ var fng;
|
|
|
957
1192
|
break;
|
|
958
1193
|
case 13:
|
|
959
1194
|
if ($scope.focus != null) {
|
|
960
|
-
$
|
|
1195
|
+
$location.url(makeUrlNoHtml5Hash($scope.results[$scope.focus]));
|
|
961
1196
|
}
|
|
962
1197
|
break;
|
|
963
1198
|
}
|
|
@@ -970,14 +1205,6 @@ var fng;
|
|
|
970
1205
|
$scope.results[index].focussed = true;
|
|
971
1206
|
$scope.focus = index;
|
|
972
1207
|
};
|
|
973
|
-
$scope.selectResult = function (resultNo) {
|
|
974
|
-
var result = $scope.results[resultNo];
|
|
975
|
-
var newURL = routingService.prefix() + '/' + result.resource + '/' + result.id + '/edit';
|
|
976
|
-
if (result.resourceTab) {
|
|
977
|
-
newURL += '/' + result.resourceTab;
|
|
978
|
-
}
|
|
979
|
-
$location.url(newURL);
|
|
980
|
-
};
|
|
981
1208
|
$scope.resultClass = function (index) {
|
|
982
1209
|
var resultClass = 'search-result';
|
|
983
1210
|
if ($scope.results && $scope.results[index].focussed) {
|
|
@@ -991,16 +1218,23 @@ var fng;
|
|
|
991
1218
|
$scope.results = [];
|
|
992
1219
|
$scope.focus = null;
|
|
993
1220
|
};
|
|
1221
|
+
function makeUrlNoHtml5Hash(result) {
|
|
1222
|
+
return result.url ? routingService.html5hash() + result.url.replace('|id|', result.id) :
|
|
1223
|
+
routingService.buildOperationUrl('edit', result.resource, undefined, result.id, result.resourceTab);
|
|
1224
|
+
}
|
|
994
1225
|
$scope.$watch('searchTarget', function (newValue) {
|
|
995
1226
|
if (newValue && newValue.length > 0) {
|
|
996
|
-
|
|
997
|
-
$http.get('/api/search?q=' + newValue).then(function (response) {
|
|
1227
|
+
lastSearchSent = $scope.testTime || new Date().valueOf();
|
|
1228
|
+
$http.get('/api/search?q=' + newValue + '&sentAt=' + lastSearchSent).then(function (response) {
|
|
998
1229
|
var data = response.data;
|
|
999
1230
|
// Check that we haven't fired off a subsequent request, in which
|
|
1000
1231
|
// case we are no longer interested in these results
|
|
1001
|
-
if (
|
|
1232
|
+
if (!data.timestamps || !data.timestamps.sentAt || Number.parseInt(data.timestamps.sentAt) === lastSearchSent) {
|
|
1002
1233
|
if ($scope.searchTarget.length > 0) {
|
|
1003
1234
|
$scope.results = data.results;
|
|
1235
|
+
$scope.results.forEach(function (result) {
|
|
1236
|
+
result.href = routingService.html5hash() + makeUrlNoHtml5Hash(result);
|
|
1237
|
+
});
|
|
1004
1238
|
$scope.moreCount = data.moreCount;
|
|
1005
1239
|
if (data.results.length > 0) {
|
|
1006
1240
|
$scope.errorClass = '';
|
|
@@ -1065,6 +1299,21 @@ var fng;
|
|
|
1065
1299
|
})(fng || (fng = {}));
|
|
1066
1300
|
/// <reference path="../../../../node_modules/@types/angular/index.d.ts" />
|
|
1067
1301
|
var fng;
|
|
1302
|
+
(function (fng) {
|
|
1303
|
+
var filters;
|
|
1304
|
+
(function (filters) {
|
|
1305
|
+
/*@ngInject*/
|
|
1306
|
+
function extractTimestampFromMongoID() {
|
|
1307
|
+
return function (id) {
|
|
1308
|
+
var timestamp = id.substring(0, 8);
|
|
1309
|
+
return new Date(parseInt(timestamp, 16) * 1000);
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
filters.extractTimestampFromMongoID = extractTimestampFromMongoID;
|
|
1313
|
+
})(filters = fng.filters || (fng.filters = {}));
|
|
1314
|
+
})(fng || (fng = {}));
|
|
1315
|
+
/// <reference path="../../../../node_modules/@types/angular/index.d.ts" />
|
|
1316
|
+
var fng;
|
|
1068
1317
|
(function (fng) {
|
|
1069
1318
|
var filters;
|
|
1070
1319
|
(function (filters) {
|
|
@@ -1245,6 +1494,7 @@ var fng;
|
|
|
1245
1494
|
controllerName += 'Ctrl';
|
|
1246
1495
|
locals.$scope = sharedData.modelControllers[level] = localScope;
|
|
1247
1496
|
var parentScope = localScope.$parent;
|
|
1497
|
+
parentScope.items = parentScope.items || [];
|
|
1248
1498
|
var addMenuOptions = function (array) {
|
|
1249
1499
|
angular.forEach(array, function (value) {
|
|
1250
1500
|
if (value.divider) {
|
|
@@ -1276,6 +1526,11 @@ var fng;
|
|
|
1276
1526
|
locals.$scope.contextMenuPromise.then(function (array) { return addMenuOptions(array); });
|
|
1277
1527
|
}
|
|
1278
1528
|
}
|
|
1529
|
+
if (sharedData.modelNameDisplayPromise) {
|
|
1530
|
+
sharedData.modelNameDisplayPromise.then(function (value) {
|
|
1531
|
+
parentScope.modelNameDisplay = value;
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1279
1534
|
}
|
|
1280
1535
|
catch (error) {
|
|
1281
1536
|
// Check to see if error is no such controller - don't care
|
|
@@ -1305,7 +1560,7 @@ var fng;
|
|
|
1305
1560
|
routing: 'ngroute',
|
|
1306
1561
|
prefix: '' // How do we want to prefix our routes? If not empty string then first character must be slash (which is added if not)
|
|
1307
1562
|
};
|
|
1308
|
-
var postActions = ['edit'];
|
|
1563
|
+
var postActions = ['edit', 'view'];
|
|
1309
1564
|
var builtInRoutes = [
|
|
1310
1565
|
{
|
|
1311
1566
|
route: '/analyse/:model/:reportSchemaName',
|
|
@@ -1315,12 +1570,19 @@ var fng;
|
|
|
1315
1570
|
{ route: '/analyse/:model', state: 'analyse::model', templateUrl: 'base-analysis.html' },
|
|
1316
1571
|
{ route: '/:model/:id/edit', state: 'model::edit', templateUrl: 'base-edit.html' },
|
|
1317
1572
|
{ route: '/:model/:id/edit/:tab', state: 'model::edit::tab', templateUrl: 'base-edit.html' },
|
|
1573
|
+
{ route: '/:model/:id/view', state: 'model::edit', templateUrl: 'base-view.html' },
|
|
1574
|
+
{ route: '/:model/:id/view/:tab', state: 'model::view::tab', templateUrl: 'base-view.html' },
|
|
1318
1575
|
{ route: '/:model/new', state: 'model::new', templateUrl: 'base-edit.html' },
|
|
1319
1576
|
{ route: '/:model', state: 'model::list', templateUrl: 'base-list.html' },
|
|
1577
|
+
{ route: '/:model/viewonly', state: 'model::view', templateUrl: 'base-list-view.html' },
|
|
1578
|
+
// Non default form (subset of fields etc)
|
|
1320
1579
|
{ route: '/:model/:form/:id/edit', state: 'model::form::edit', templateUrl: 'base-edit.html' },
|
|
1321
1580
|
{ route: '/:model/:form/:id/edit/:tab', state: 'model::form::edit::tab', templateUrl: 'base-edit.html' },
|
|
1581
|
+
{ route: '/:model/:form/:id/view', state: 'model::form::view', templateUrl: 'base-view.html' },
|
|
1582
|
+
{ route: '/:model/:form/:id/view/:tab', state: 'model::form::view::tab', templateUrl: 'base-view.html' },
|
|
1322
1583
|
{ route: '/:model/:form/new', state: 'model::form::new', templateUrl: 'base-edit.html' },
|
|
1323
|
-
{ route: '/:model/:form', state: 'model::form::list', templateUrl: 'base-list.html' }
|
|
1584
|
+
{ route: '/:model/:form', state: 'model::form::list', templateUrl: 'base-list.html' },
|
|
1585
|
+
{ route: '/:model/:form/viewonly', state: 'model::form::list::view', templateUrl: 'base-list-view.html' } // list page with edit links to non default form
|
|
1324
1586
|
];
|
|
1325
1587
|
var _routeProvider, _stateProvider;
|
|
1326
1588
|
var lastRoute = null;
|
|
@@ -1374,6 +1636,12 @@ var fng;
|
|
|
1374
1636
|
case 'edit':
|
|
1375
1637
|
urlStr = modelString + formString + '/' + id + '/edit' + tabString;
|
|
1376
1638
|
break;
|
|
1639
|
+
case 'view':
|
|
1640
|
+
urlStr = modelString + formString + '/' + id + '/view' + tabString;
|
|
1641
|
+
break;
|
|
1642
|
+
case 'read':
|
|
1643
|
+
urlStr = modelString + formString + '/' + id + '/read' + tabString;
|
|
1644
|
+
break;
|
|
1377
1645
|
case 'new':
|
|
1378
1646
|
urlStr = modelString + formString + '/new' + tabString;
|
|
1379
1647
|
break;
|
|
@@ -1456,8 +1724,9 @@ var fng;
|
|
|
1456
1724
|
lastObject.modelName = locationSplit[1];
|
|
1457
1725
|
var lastParts_1 = [locationSplit[locationParts - 1], locationSplit[locationParts - 2]];
|
|
1458
1726
|
var newPos = lastParts_1.indexOf('new');
|
|
1727
|
+
var viewonlyPos = lastParts_1.indexOf('viewonly');
|
|
1459
1728
|
var actionPos = void 0;
|
|
1460
|
-
if (newPos === -1) {
|
|
1729
|
+
if (newPos === -1 && viewonlyPos === -1) {
|
|
1461
1730
|
actionPos = postActions.reduce(function (previousValue, currentValue) {
|
|
1462
1731
|
var pos = lastParts_1.indexOf(currentValue);
|
|
1463
1732
|
return pos > -1 ? pos : previousValue;
|
|
@@ -1467,10 +1736,13 @@ var fng;
|
|
|
1467
1736
|
lastObject.id = locationSplit[locationParts];
|
|
1468
1737
|
}
|
|
1469
1738
|
}
|
|
1470
|
-
else {
|
|
1739
|
+
else if (newPos !== -1) {
|
|
1471
1740
|
lastObject.newRecord = true;
|
|
1472
1741
|
locationParts -= (1 + newPos);
|
|
1473
1742
|
}
|
|
1743
|
+
else {
|
|
1744
|
+
locationParts -= (1 + viewonlyPos);
|
|
1745
|
+
}
|
|
1474
1746
|
if (actionPos === 1 || newPos === 1) {
|
|
1475
1747
|
lastObject.tab = lastParts_1[0];
|
|
1476
1748
|
}
|
|
@@ -1481,34 +1753,9 @@ var fng;
|
|
|
1481
1753
|
}
|
|
1482
1754
|
return lastObject;
|
|
1483
1755
|
};
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
// * Parser for the states provided by ui.router
|
|
1488
|
-
// */
|
|
1489
|
-
//'use strict';
|
|
1490
|
-
//formsAngular.factory('$stateParse', [function () {
|
|
1491
|
-
//
|
|
1492
|
-
// var lastObject = {};
|
|
1493
|
-
//
|
|
1494
|
-
// return function (state) {
|
|
1495
|
-
// if (state.current && state.current.name) {
|
|
1496
|
-
// lastObject = {newRecord: false};
|
|
1497
|
-
// lastObject.modelName = state.params.model;
|
|
1498
|
-
// if (state.current.name === 'model::list') {
|
|
1499
|
-
// lastObject = {index: true};
|
|
1500
|
-
// lastObject.modelName = state.params.model;
|
|
1501
|
-
// } else if (state.current.name === 'model::edit') {
|
|
1502
|
-
// lastObject.id = state.params.id;
|
|
1503
|
-
// } else if (state.current.name === 'model::new') {
|
|
1504
|
-
// lastObject.newRecord = true;
|
|
1505
|
-
// } else if (state.current.name === 'model::analyse') {
|
|
1506
|
-
// lastObject.analyse = true;
|
|
1507
|
-
// }
|
|
1508
|
-
// }
|
|
1509
|
-
// return lastObject;
|
|
1510
|
-
// };
|
|
1511
|
-
//}]);
|
|
1756
|
+
},
|
|
1757
|
+
html5hash: function () {
|
|
1758
|
+
return config.html5Mode ? '' : '#';
|
|
1512
1759
|
},
|
|
1513
1760
|
buildUrl: function (path) {
|
|
1514
1761
|
var url = config.html5Mode ? '' : '#';
|
|
@@ -1525,46 +1772,25 @@ var fng;
|
|
|
1525
1772
|
},
|
|
1526
1773
|
redirectTo: function () {
|
|
1527
1774
|
return function (operation, scope, location, id, tab) {
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
if (
|
|
1531
|
-
|
|
1775
|
+
location.search({}); // Lose any search parameters
|
|
1776
|
+
var urlStr;
|
|
1777
|
+
if (operation === 'onDelete') {
|
|
1778
|
+
if (config.onDelete) {
|
|
1779
|
+
if (config.onDelete === 'new') {
|
|
1780
|
+
urlStr = _buildOperationUrl(config.prefix, 'new', scope.modelName, scope.formName, id, tab);
|
|
1781
|
+
}
|
|
1782
|
+
else {
|
|
1783
|
+
urlStr = config.onDelete;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
else {
|
|
1787
|
+
urlStr = _buildOperationUrl(config.prefix, 'list', scope.modelName, scope.formName, id, tab);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
else {
|
|
1791
|
+
urlStr = _buildOperationUrl(config.prefix, operation, scope.modelName, scope.formName, id, tab);
|
|
1532
1792
|
}
|
|
1533
|
-
var urlStr = _buildOperationUrl(config.prefix, operation, scope.modelName, scope.formName, id, tab);
|
|
1534
1793
|
location.path(urlStr);
|
|
1535
|
-
// break;
|
|
1536
|
-
// case 'uirouter' :
|
|
1537
|
-
// var formString = scope.formName ? ('/' + scope.formName) : '';
|
|
1538
|
-
// var modelString = config.prefix + '/' + scope.modelName;
|
|
1539
|
-
// console.log('form schemas not supported with ui-router');
|
|
1540
|
-
// switch (operation) {
|
|
1541
|
-
// case 'list' :
|
|
1542
|
-
// location.path(modelString + formString);
|
|
1543
|
-
// break;
|
|
1544
|
-
// case 'edit' :
|
|
1545
|
-
// location.path(modelString + formString + '/' + id + '/edit');
|
|
1546
|
-
// break;
|
|
1547
|
-
// case 'new' :
|
|
1548
|
-
// location.path(modelString + formString + '/new');
|
|
1549
|
-
// break;
|
|
1550
|
-
// }
|
|
1551
|
-
// switch (operation) {
|
|
1552
|
-
// case 'list' :
|
|
1553
|
-
// $state.go('model::list', { model: model });
|
|
1554
|
-
// break;
|
|
1555
|
-
// case 'edit' :
|
|
1556
|
-
// location.path('/' + scope.modelName + formString + '/' + id + '/edit');
|
|
1557
|
-
// break;
|
|
1558
|
-
// case 'new' :
|
|
1559
|
-
// location.path('/' + scope.modelName + formString + '/new');
|
|
1560
|
-
// break;
|
|
1561
|
-
// }
|
|
1562
|
-
// break;
|
|
1563
|
-
//
|
|
1564
|
-
//
|
|
1565
|
-
// // edit: $state.go('model::edit', {id: data._id, model: $scope.modelName });
|
|
1566
|
-
// // new: $state.go('model::new', {model: $scope.modelName});
|
|
1567
|
-
// break;
|
|
1568
1794
|
};
|
|
1569
1795
|
}
|
|
1570
1796
|
};
|
|
@@ -1586,7 +1812,7 @@ var fng;
|
|
|
1586
1812
|
* All methods should be state-less
|
|
1587
1813
|
*
|
|
1588
1814
|
*/
|
|
1589
|
-
function formGenerator($location, $timeout, $filter,
|
|
1815
|
+
function formGenerator($location, $timeout, $filter, routingService, recordHandler) {
|
|
1590
1816
|
function handleSchema(description, source, destForm, destList, prefix, doRecursion, $scope, ctrlState) {
|
|
1591
1817
|
function handletabInfo(tabName, thisInst) {
|
|
1592
1818
|
var tabTitle = angular.copy(tabName);
|
|
@@ -1612,50 +1838,55 @@ var fng;
|
|
|
1612
1838
|
}
|
|
1613
1839
|
tab.content.push(thisInst);
|
|
1614
1840
|
}
|
|
1841
|
+
if (typeof $scope.onSchemaFetch === "function") {
|
|
1842
|
+
$scope.onSchemaFetch(description, source);
|
|
1843
|
+
}
|
|
1615
1844
|
for (var field in source) {
|
|
1616
|
-
if (field
|
|
1617
|
-
if (
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
}
|
|
1621
|
-
else if (source.hasOwnProperty(field)) {
|
|
1622
|
-
var mongooseType = source[field], mongooseOptions = mongooseType.options || {};
|
|
1623
|
-
var formData = mongooseOptions.form || {};
|
|
1624
|
-
if (mongooseType.schema && !formData.hidden) {
|
|
1625
|
-
if (doRecursion && destForm) {
|
|
1626
|
-
var schemaSchema = [];
|
|
1627
|
-
handleSchema('Nested ' + field, mongooseType.schema, schemaSchema, null, field + '.', true, $scope, ctrlState);
|
|
1628
|
-
var sectionInstructions = basicInstructions(field, formData, prefix);
|
|
1629
|
-
sectionInstructions.schema = schemaSchema;
|
|
1630
|
-
if (formData.tab) {
|
|
1631
|
-
handletabInfo(formData.tab, sectionInstructions);
|
|
1632
|
-
}
|
|
1633
|
-
if (formData.order !== undefined) {
|
|
1634
|
-
destForm.splice(formData.order, 0, sectionInstructions);
|
|
1635
|
-
}
|
|
1636
|
-
else {
|
|
1637
|
-
destForm.push(sectionInstructions);
|
|
1638
|
-
}
|
|
1845
|
+
if (source.hasOwnProperty(field)) {
|
|
1846
|
+
if (field === '_id') {
|
|
1847
|
+
if (destList && source['_id'].options && source['_id'].options.list) {
|
|
1848
|
+
handleListInfo(destList, source['_id'].options.list, field);
|
|
1639
1849
|
}
|
|
1640
1850
|
}
|
|
1641
|
-
else {
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1851
|
+
else if (source.hasOwnProperty(field)) {
|
|
1852
|
+
var mongooseType = source[field], mongooseOptions = mongooseType.options || {};
|
|
1853
|
+
var formData = mongooseOptions.form || {};
|
|
1854
|
+
if (mongooseType.schema && !formData.hidden) {
|
|
1855
|
+
if (doRecursion && destForm) {
|
|
1856
|
+
var schemaSchema = [];
|
|
1857
|
+
handleSchema('Nested ' + field, mongooseType.schema, schemaSchema, null, field + '.', true, $scope, ctrlState);
|
|
1858
|
+
var sectionInstructions = basicInstructions(field, formData, prefix);
|
|
1859
|
+
sectionInstructions.schema = schemaSchema;
|
|
1860
|
+
if (formData.tab) {
|
|
1861
|
+
handletabInfo(formData.tab, sectionInstructions);
|
|
1648
1862
|
}
|
|
1649
1863
|
if (formData.order !== undefined) {
|
|
1650
|
-
destForm.splice(formData.order, 0,
|
|
1864
|
+
destForm.splice(formData.order, 0, sectionInstructions);
|
|
1651
1865
|
}
|
|
1652
1866
|
else {
|
|
1653
|
-
destForm.push(
|
|
1867
|
+
destForm.push(sectionInstructions);
|
|
1654
1868
|
}
|
|
1655
1869
|
}
|
|
1656
1870
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1871
|
+
else {
|
|
1872
|
+
if (destForm && !formData.hidden) {
|
|
1873
|
+
var formInstructions = basicInstructions(field, formData, prefix);
|
|
1874
|
+
if (handleConditionals(formInstructions.showIf, formInstructions.name, $scope) && field !== 'options') {
|
|
1875
|
+
var formInst = handleFieldType(formInstructions, mongooseType, mongooseOptions, $scope, ctrlState);
|
|
1876
|
+
if (formInst.tab) {
|
|
1877
|
+
handletabInfo(formInst.tab, formInst);
|
|
1878
|
+
}
|
|
1879
|
+
if (formData.order !== undefined) {
|
|
1880
|
+
destForm.splice(formData.order, 0, formInst);
|
|
1881
|
+
}
|
|
1882
|
+
else {
|
|
1883
|
+
destForm.push(formInst);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
if (destList && mongooseOptions.list) {
|
|
1888
|
+
handleListInfo(destList, mongooseOptions.list, field);
|
|
1889
|
+
}
|
|
1659
1890
|
}
|
|
1660
1891
|
}
|
|
1661
1892
|
}
|
|
@@ -1679,6 +1910,9 @@ var fng;
|
|
|
1679
1910
|
// console.log($scope.tabs[0]['title'])
|
|
1680
1911
|
// $location.hash($scope.tabs[0]['title']);
|
|
1681
1912
|
// }
|
|
1913
|
+
if (typeof $scope.onSchemaProcessed === "function") {
|
|
1914
|
+
$scope.onSchemaProcessed(description, description.slice(0, 5) === 'Main ' ? $scope.baseSchema() : destForm);
|
|
1915
|
+
}
|
|
1682
1916
|
if (destList && destList.length === 0) {
|
|
1683
1917
|
handleEmptyList(description, destList, destForm, source);
|
|
1684
1918
|
}
|
|
@@ -1687,23 +1921,23 @@ var fng;
|
|
|
1687
1921
|
function performLookupSelect() {
|
|
1688
1922
|
formInstructions.options = recordHandler.suffixCleanId(formInstructions, 'Options');
|
|
1689
1923
|
formInstructions.ids = recordHandler.suffixCleanId(formInstructions, '_ids');
|
|
1690
|
-
if (!formInstructions.hidden
|
|
1691
|
-
if (
|
|
1692
|
-
mongooseOptions.ref
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1924
|
+
if (!formInstructions.hidden) {
|
|
1925
|
+
if (mongooseOptions.ref) {
|
|
1926
|
+
recordHandler.setUpLookupOptions(mongooseOptions.ref, formInstructions, $scope, ctrlState, handleSchema);
|
|
1927
|
+
}
|
|
1928
|
+
else if (mongooseOptions.lookupListRef) {
|
|
1929
|
+
recordHandler.setUpLookupListOptions(mongooseOptions.lookupListRef, formInstructions, $scope, ctrlState);
|
|
1930
|
+
formInstructions.lookupListRef = mongooseOptions.lookupListRef;
|
|
1931
|
+
}
|
|
1932
|
+
else if (mongooseOptions.internalRef) {
|
|
1933
|
+
recordHandler.handleInternalLookup($scope, formInstructions, mongooseOptions.internalRef);
|
|
1934
|
+
formInstructions.internalRef = mongooseOptions.internalRef;
|
|
1935
|
+
}
|
|
1936
|
+
else if (mongooseOptions.customLookupOptions) {
|
|
1937
|
+
// nothing to do - call setUpCustomLookupOptions() when ready to provide id and option arrays
|
|
1938
|
+
}
|
|
1939
|
+
else {
|
|
1940
|
+
throw new Error("No supported select lookup type found in ".concat(formInstructions.name));
|
|
1707
1941
|
}
|
|
1708
1942
|
}
|
|
1709
1943
|
}
|
|
@@ -1737,13 +1971,22 @@ var fng;
|
|
|
1737
1971
|
}
|
|
1738
1972
|
else if (mongooseType.instance === 'ObjectID') {
|
|
1739
1973
|
formInstructions.ref = mongooseOptions.ref;
|
|
1740
|
-
if (formInstructions.link
|
|
1741
|
-
formInstructions.
|
|
1742
|
-
|
|
1974
|
+
if (formInstructions.link) {
|
|
1975
|
+
if (formInstructions.link.linkOnly) {
|
|
1976
|
+
formInstructions.type = 'link';
|
|
1977
|
+
formInstructions.linktext = formInstructions.link.text;
|
|
1978
|
+
}
|
|
1979
|
+
else if (formInstructions.link.label) {
|
|
1980
|
+
formInstructions.linklabel = true;
|
|
1981
|
+
}
|
|
1982
|
+
else {
|
|
1983
|
+
console.log('Unsupported link setup');
|
|
1984
|
+
}
|
|
1743
1985
|
formInstructions.form = formInstructions.link.form;
|
|
1986
|
+
formInstructions.linktab = formInstructions.link.linktab;
|
|
1744
1987
|
delete formInstructions.link;
|
|
1745
1988
|
}
|
|
1746
|
-
|
|
1989
|
+
if (formInstructions.type !== 'link') {
|
|
1747
1990
|
formInstructions.type = 'select';
|
|
1748
1991
|
if (formInstructions.select2 || (mongooseOptions.form && mongooseOptions.form.select2)) {
|
|
1749
1992
|
console.log('support for fng-select2 has been removed in 0.8.3 - please convert to fng-ui-select');
|
|
@@ -1755,16 +1998,18 @@ var fng;
|
|
|
1755
1998
|
}
|
|
1756
1999
|
else if (mongooseType.instance === 'Date') {
|
|
1757
2000
|
if (!formInstructions.type) {
|
|
2001
|
+
formInstructions.intType = 'date';
|
|
1758
2002
|
if (formInstructions.readonly) {
|
|
1759
2003
|
formInstructions.type = 'text';
|
|
1760
2004
|
}
|
|
1761
2005
|
else if (formInstructions.directive) {
|
|
1762
|
-
formInstructions.type = 'text';
|
|
2006
|
+
formInstructions.type = 'text';
|
|
1763
2007
|
}
|
|
1764
2008
|
else {
|
|
1765
2009
|
try {
|
|
1766
2010
|
formInstructions.add = formInstructions.add || '';
|
|
1767
|
-
|
|
2011
|
+
// Check whether DatePicker is installed
|
|
2012
|
+
angular.module('ui.date').requires;
|
|
1768
2013
|
formInstructions.type = 'text';
|
|
1769
2014
|
formInstructions.add += ' ui-date ui-date-format ';
|
|
1770
2015
|
// formInstructions.add += ' ui-date ui-date-format datepicker-popup-fix ';
|
|
@@ -1777,10 +2022,10 @@ var fng;
|
|
|
1777
2022
|
}
|
|
1778
2023
|
}
|
|
1779
2024
|
else if (mongooseType.instance.toLowerCase() === 'boolean') {
|
|
1780
|
-
formInstructions.type = 'checkbox';
|
|
2025
|
+
formInstructions.type = formInstructions.type || 'checkbox';
|
|
1781
2026
|
}
|
|
1782
2027
|
else if (mongooseType.instance === 'Number') {
|
|
1783
|
-
formInstructions.type = 'number';
|
|
2028
|
+
formInstructions.type = formInstructions.type || 'number';
|
|
1784
2029
|
if (mongooseOptions.min !== undefined) {
|
|
1785
2030
|
formInstructions.add = 'min="' + mongooseOptions.min + '" ' + (formInstructions.add || '');
|
|
1786
2031
|
}
|
|
@@ -1800,11 +2045,17 @@ var fng;
|
|
|
1800
2045
|
if (mongooseOptions.readonly) {
|
|
1801
2046
|
formInstructions['readonly'] = true;
|
|
1802
2047
|
}
|
|
2048
|
+
if (mongooseType.defaultValue !== undefined) {
|
|
2049
|
+
formInstructions.defaultValue = mongooseType.defaultValue;
|
|
2050
|
+
}
|
|
2051
|
+
else if (mongooseType.options && mongooseType.options.default !== undefined) {
|
|
2052
|
+
console.log('No support for default with no value, yet');
|
|
2053
|
+
}
|
|
1803
2054
|
return formInstructions;
|
|
1804
2055
|
}
|
|
1805
|
-
function getArrayFieldToExtend(fieldName, $scope) {
|
|
2056
|
+
function getArrayFieldToExtend(fieldName, $scope, modelOverride) {
|
|
1806
2057
|
var fieldParts = fieldName.split('.');
|
|
1807
|
-
var arrayField = $scope.record;
|
|
2058
|
+
var arrayField = modelOverride || $scope.record;
|
|
1808
2059
|
for (var i = 0, l = fieldParts.length; i < l; i++) {
|
|
1809
2060
|
if (!arrayField[fieldParts[i]]) {
|
|
1810
2061
|
if (i === l - 1) {
|
|
@@ -1921,6 +2172,9 @@ var fng;
|
|
|
1921
2172
|
generateEditUrl: function generateEditUrl(obj, $scope) {
|
|
1922
2173
|
return routingService.buildUrl($scope.modelName + '/' + ($scope.formName ? $scope.formName + '/' : '') + obj._id + '/edit');
|
|
1923
2174
|
},
|
|
2175
|
+
generateViewUrl: function generateViewUrl(obj, $scope) {
|
|
2176
|
+
return routingService.buildUrl($scope.modelName + '/' + ($scope.formName ? $scope.formName + '/' : '') + obj._id + '/view');
|
|
2177
|
+
},
|
|
1924
2178
|
generateNewUrl: function generateNewUrl($scope) {
|
|
1925
2179
|
return routingService.buildUrl($scope.modelName + '/' + ($scope.formName ? $scope.formName + '/' : '') + 'new');
|
|
1926
2180
|
},
|
|
@@ -2005,25 +2259,44 @@ var fng;
|
|
|
2005
2259
|
}
|
|
2006
2260
|
return forceNextTime;
|
|
2007
2261
|
},
|
|
2008
|
-
add: function add(fieldName, $event, $scope) {
|
|
2009
|
-
var
|
|
2010
|
-
|
|
2011
|
-
|
|
2262
|
+
add: function add(fieldName, $event, $scope, modelOverride) {
|
|
2263
|
+
var _a;
|
|
2264
|
+
// check that target element is visible. May not be reliable - see https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
|
2265
|
+
if ($event.target.offsetParent) {
|
|
2266
|
+
var arrayField = getArrayFieldToExtend(fieldName, $scope, modelOverride);
|
|
2267
|
+
var schemaElement = $scope.formSchema.find(function (f) { return f.name === fieldName; }); // In case someone is using the formSchema directly
|
|
2268
|
+
var subSchema = schemaElement ? schemaElement.schema : null;
|
|
2269
|
+
var obj = subSchema ? $scope.setDefaults(subSchema, fieldName + '.') : {};
|
|
2270
|
+
if (typeof ((_a = $scope.dataEventFunctions) === null || _a === void 0 ? void 0 : _a.onInitialiseNewSubDoc) === "function") {
|
|
2271
|
+
$scope.dataEventFunctions.onInitialiseNewSubDoc(fieldName, subSchema, obj);
|
|
2272
|
+
}
|
|
2273
|
+
arrayField.push(obj);
|
|
2274
|
+
$scope.setFormDirty($event);
|
|
2275
|
+
}
|
|
2012
2276
|
},
|
|
2013
|
-
unshift: function unshift(fieldName, $event, $scope) {
|
|
2014
|
-
var arrayField = getArrayFieldToExtend(fieldName, $scope);
|
|
2277
|
+
unshift: function unshift(fieldName, $event, $scope, modelOverride) {
|
|
2278
|
+
var arrayField = getArrayFieldToExtend(fieldName, $scope, modelOverride);
|
|
2015
2279
|
arrayField.unshift({});
|
|
2016
2280
|
$scope.setFormDirty($event);
|
|
2017
2281
|
},
|
|
2018
|
-
remove: function remove(fieldName, value, $event, $scope) {
|
|
2282
|
+
remove: function remove(fieldName, value, $event, $scope, modelOverride) {
|
|
2019
2283
|
// Remove an element from an array
|
|
2020
|
-
var
|
|
2021
|
-
var
|
|
2022
|
-
|
|
2023
|
-
|
|
2284
|
+
var arrayField = getArrayFieldToExtend(fieldName, $scope, modelOverride);
|
|
2285
|
+
var err;
|
|
2286
|
+
if (typeof $scope.dataEventFunctions.onDeleteSubDoc === "function") {
|
|
2287
|
+
var schemaElement = $scope.formSchema.find(function (f) {
|
|
2288
|
+
return f.name === fieldName;
|
|
2289
|
+
});
|
|
2290
|
+
var subSchema = schemaElement ? schemaElement.schema : null;
|
|
2291
|
+
err = $scope.dataEventFunctions.onDeleteSubDoc(fieldName, subSchema, arrayField, value);
|
|
2292
|
+
}
|
|
2293
|
+
if (err) {
|
|
2294
|
+
$scope.showError(err);
|
|
2295
|
+
}
|
|
2296
|
+
else {
|
|
2297
|
+
arrayField.splice(value, 1);
|
|
2298
|
+
$scope.setFormDirty($event);
|
|
2024
2299
|
}
|
|
2025
|
-
arrayField.splice(value, 1);
|
|
2026
|
-
$scope.setFormDirty($event);
|
|
2027
2300
|
},
|
|
2028
2301
|
hasError: function hasError(formName, name, index, $scope) {
|
|
2029
2302
|
var result = false;
|
|
@@ -2035,7 +2308,7 @@ var fng;
|
|
|
2035
2308
|
// Cannot assume that directives will use the same methods
|
|
2036
2309
|
if (form) {
|
|
2037
2310
|
var field_1 = form[name];
|
|
2038
|
-
if (field_1 && field_1.$invalid) {
|
|
2311
|
+
if (field_1 && field_1.$invalid && !field_1.$$attr.readonly) {
|
|
2039
2312
|
if (field_1.$dirty) {
|
|
2040
2313
|
result = true;
|
|
2041
2314
|
}
|
|
@@ -2075,6 +2348,9 @@ var fng;
|
|
|
2075
2348
|
$scope.generateEditUrl = function (obj) {
|
|
2076
2349
|
return formGeneratorInstance.generateEditUrl(obj, $scope);
|
|
2077
2350
|
};
|
|
2351
|
+
$scope.generateViewUrl = function (obj) {
|
|
2352
|
+
return formGeneratorInstance.generateViewUrl(obj, $scope);
|
|
2353
|
+
};
|
|
2078
2354
|
$scope.generateNewUrl = function () {
|
|
2079
2355
|
return formGeneratorInstance.generateNewUrl($scope);
|
|
2080
2356
|
};
|
|
@@ -2082,7 +2358,7 @@ var fng;
|
|
|
2082
2358
|
return recordHandlerInstance.scrollTheList($scope);
|
|
2083
2359
|
};
|
|
2084
2360
|
$scope.getListData = function (record, fieldName) {
|
|
2085
|
-
return recordHandlerInstance.getListData(
|
|
2361
|
+
return recordHandlerInstance.getListData(record, fieldName, $scope.listSchema, $scope);
|
|
2086
2362
|
};
|
|
2087
2363
|
$scope.setPristine = function (clearErrors) {
|
|
2088
2364
|
if (clearErrors) {
|
|
@@ -2104,17 +2380,17 @@ var fng;
|
|
|
2104
2380
|
console.log('setFormDirty called without an event (fine in a unit test)');
|
|
2105
2381
|
}
|
|
2106
2382
|
};
|
|
2107
|
-
$scope.add = function (fieldName, $event) {
|
|
2108
|
-
return formGeneratorInstance.add(fieldName, $event, $scope);
|
|
2383
|
+
$scope.add = function (fieldName, $event, modelOverride) {
|
|
2384
|
+
return formGeneratorInstance.add(fieldName, $event, $scope, modelOverride);
|
|
2109
2385
|
};
|
|
2110
2386
|
$scope.hasError = function (form, name, index) {
|
|
2111
2387
|
return formGeneratorInstance.hasError(form, name, index, $scope);
|
|
2112
2388
|
};
|
|
2113
|
-
$scope.unshift = function (fieldName, $event) {
|
|
2114
|
-
return formGeneratorInstance.unshift(fieldName, $event, $scope);
|
|
2389
|
+
$scope.unshift = function (fieldName, $event, modelOverride) {
|
|
2390
|
+
return formGeneratorInstance.unshift(fieldName, $event, $scope, modelOverride);
|
|
2115
2391
|
};
|
|
2116
|
-
$scope.remove = function (fieldName, value, $event) {
|
|
2117
|
-
return formGeneratorInstance.remove(fieldName, value, $event, $scope);
|
|
2392
|
+
$scope.remove = function (fieldName, value, $event, modelOverride) {
|
|
2393
|
+
return formGeneratorInstance.remove(fieldName, value, $event, $scope, modelOverride);
|
|
2118
2394
|
};
|
|
2119
2395
|
$scope.baseSchema = function () {
|
|
2120
2396
|
return ($scope.tabs.length ? $scope.tabs : $scope.formSchema);
|
|
@@ -2129,7 +2405,7 @@ var fng;
|
|
|
2129
2405
|
};
|
|
2130
2406
|
}
|
|
2131
2407
|
services.formGenerator = formGenerator;
|
|
2132
|
-
formGenerator.$inject = ["$location", "$timeout", "$filter", "
|
|
2408
|
+
formGenerator.$inject = ["$location", "$timeout", "$filter", "routingService", "recordHandler"];
|
|
2133
2409
|
})(services = fng.services || (fng.services = {}));
|
|
2134
2410
|
})(fng || (fng = {}));
|
|
2135
2411
|
/// <reference path="../../index.d.ts" />
|
|
@@ -2138,8 +2414,8 @@ var fng;
|
|
|
2138
2414
|
var services;
|
|
2139
2415
|
(function (services) {
|
|
2140
2416
|
/*@ngInject*/
|
|
2141
|
-
formMarkupHelper.$inject = ["cssFrameworkService", "inputSizeHelper", "addAllService"];
|
|
2142
|
-
function formMarkupHelper(cssFrameworkService, inputSizeHelper, addAllService) {
|
|
2417
|
+
formMarkupHelper.$inject = ["cssFrameworkService", "inputSizeHelper", "addAllService", "$filter"];
|
|
2418
|
+
function formMarkupHelper(cssFrameworkService, inputSizeHelper, addAllService, $filter) {
|
|
2143
2419
|
function generateNgShow(showWhen, model) {
|
|
2144
2420
|
function evaluateSide(side) {
|
|
2145
2421
|
var result = side;
|
|
@@ -2167,11 +2443,15 @@ var fng;
|
|
|
2167
2443
|
}
|
|
2168
2444
|
return evaluateSide(showWhen.lhs) + conditionSymbols[conditionPos] + evaluateSide(showWhen.rhs);
|
|
2169
2445
|
}
|
|
2170
|
-
var isHorizontalStyle = function isHorizontalStyle(formStyle) {
|
|
2171
|
-
|
|
2446
|
+
var isHorizontalStyle = function isHorizontalStyle(formStyle, includeStacked) {
|
|
2447
|
+
var exclude = ['vertical', 'inline'];
|
|
2448
|
+
if (!includeStacked) {
|
|
2449
|
+
exclude.push('stacked');
|
|
2450
|
+
}
|
|
2451
|
+
return (!formStyle || formStyle === 'undefined' || !exclude.includes(formStyle));
|
|
2172
2452
|
};
|
|
2173
2453
|
function glyphClass() {
|
|
2174
|
-
return (cssFrameworkService.framework() === 'bs2'
|
|
2454
|
+
return (cssFrameworkService.framework() === 'bs2' ? 'icon' : 'glyphicon glyphicon');
|
|
2175
2455
|
}
|
|
2176
2456
|
return {
|
|
2177
2457
|
isHorizontalStyle: isHorizontalStyle,
|
|
@@ -2189,7 +2469,9 @@ var fng;
|
|
|
2189
2469
|
insert += 'ng-show="' + generateNgShow(info.showWhen, options.model) + '"';
|
|
2190
2470
|
}
|
|
2191
2471
|
}
|
|
2192
|
-
|
|
2472
|
+
if (info.id && typeof info.id.replace === "function") {
|
|
2473
|
+
insert += ' id="cg_' + info.id.replace(/\./g, '-') + '"';
|
|
2474
|
+
}
|
|
2193
2475
|
if (cssFrameworkService.framework() === 'bs3') {
|
|
2194
2476
|
classes += ' form-group';
|
|
2195
2477
|
if (options.formstyle === 'vertical' && info.size !== 'block-level') {
|
|
@@ -2214,7 +2496,7 @@ var fng;
|
|
|
2214
2496
|
closeTag += '</div>';
|
|
2215
2497
|
}
|
|
2216
2498
|
else {
|
|
2217
|
-
if (isHorizontalStyle(options.formstyle)) {
|
|
2499
|
+
if (isHorizontalStyle(options.formstyle, true)) {
|
|
2218
2500
|
template += '<div' + addAllService.addAll(scope, 'Group', 'control-group', options);
|
|
2219
2501
|
closeTag = '</div>';
|
|
2220
2502
|
}
|
|
@@ -2228,11 +2510,13 @@ var fng;
|
|
|
2228
2510
|
},
|
|
2229
2511
|
label: function label(scope, fieldInfo, addButtonMarkup, options) {
|
|
2230
2512
|
var labelHTML = '';
|
|
2231
|
-
if ((cssFrameworkService.framework() === 'bs3' || (options.formstyle
|
|
2513
|
+
if ((cssFrameworkService.framework() === 'bs3' || (!['inline', 'stacked'].includes(options.formstyle) && fieldInfo.label !== '')) || addButtonMarkup) {
|
|
2232
2514
|
labelHTML = '<label';
|
|
2233
2515
|
var classes = 'control-label';
|
|
2234
|
-
if (isHorizontalStyle(options.formstyle)) {
|
|
2235
|
-
|
|
2516
|
+
if (isHorizontalStyle(options.formstyle, false)) {
|
|
2517
|
+
if (!fieldInfo.linklabel) {
|
|
2518
|
+
labelHTML += ' for="' + fieldInfo.id + '"';
|
|
2519
|
+
}
|
|
2236
2520
|
if (typeof fieldInfo.labelDefaultClass !== 'undefined') {
|
|
2237
2521
|
// Override default label class (can be empty)
|
|
2238
2522
|
classes += ' ' + fieldInfo.labelDefaultClass;
|
|
@@ -2241,7 +2525,7 @@ var fng;
|
|
|
2241
2525
|
classes += ' col-sm-3';
|
|
2242
2526
|
}
|
|
2243
2527
|
}
|
|
2244
|
-
else if (options.formstyle
|
|
2528
|
+
else if (['inline', 'stacked'].includes(options.formstyle)) {
|
|
2245
2529
|
labelHTML += ' for="' + fieldInfo.id + '"';
|
|
2246
2530
|
classes += ' sr-only';
|
|
2247
2531
|
}
|
|
@@ -2250,6 +2534,17 @@ var fng;
|
|
|
2250
2534
|
labelHTML += ' <i id="add_' + fieldInfo.id + '" ng-click="add(\'' + fieldInfo.name + '\',$event)" class="' + glyphClass() + '-plus-sign"></i>';
|
|
2251
2535
|
}
|
|
2252
2536
|
labelHTML += '</label>';
|
|
2537
|
+
if (fieldInfo.linklabel) {
|
|
2538
|
+
var value = '<fng-link fld="' + fieldInfo.name + '" ref="' + fieldInfo.ref + '" text="' + escape(labelHTML) + '"';
|
|
2539
|
+
if (fieldInfo.form) {
|
|
2540
|
+
value += ' form="' + fieldInfo.form + '"';
|
|
2541
|
+
}
|
|
2542
|
+
if (fieldInfo.linktab) {
|
|
2543
|
+
value += ' linktab="' + fieldInfo.linktab + '"';
|
|
2544
|
+
}
|
|
2545
|
+
value += '></fng-link>';
|
|
2546
|
+
labelHTML = value;
|
|
2547
|
+
}
|
|
2253
2548
|
}
|
|
2254
2549
|
return labelHTML;
|
|
2255
2550
|
},
|
|
@@ -2269,14 +2564,17 @@ var fng;
|
|
|
2269
2564
|
else {
|
|
2270
2565
|
sizeClassBS2 = (fieldInfo.size ? ' input-' + fieldInfo.size : '');
|
|
2271
2566
|
}
|
|
2272
|
-
if (options.formstyle
|
|
2567
|
+
if (['inline', 'stacked'].includes(options.formstyle)) {
|
|
2273
2568
|
placeHolder = placeHolder || fieldInfo.label;
|
|
2274
2569
|
}
|
|
2275
|
-
common = 'ng-model="' + modelString + '"' + (idString ? ' id="' + idString + '" name="' + idString + '" ' : ' name="' + nameString + '" ');
|
|
2570
|
+
common = 'data-ng-model="' + modelString + '"' + (idString ? ' id="' + idString + '" name="' + idString + '" ' : ' name="' + nameString + '" ');
|
|
2276
2571
|
common += (placeHolder ? ('placeholder="' + placeHolder + '" ') : '');
|
|
2277
2572
|
if (fieldInfo.popup) {
|
|
2278
2573
|
common += 'title="' + fieldInfo.popup + '" ';
|
|
2279
2574
|
}
|
|
2575
|
+
if (fieldInfo.ariaLabel) {
|
|
2576
|
+
common += 'aria-label="' + fieldInfo.ariaLabel + '" ';
|
|
2577
|
+
}
|
|
2280
2578
|
common += addAllService.addAll(scope, 'Field', null, options);
|
|
2281
2579
|
return {
|
|
2282
2580
|
common: common,
|
|
@@ -2287,28 +2585,36 @@ var fng;
|
|
|
2287
2585
|
};
|
|
2288
2586
|
},
|
|
2289
2587
|
inputChrome: function inputChrome(value, fieldInfo, options, markupVars) {
|
|
2290
|
-
if (cssFrameworkService.framework() === 'bs3' && isHorizontalStyle(options.formstyle) && fieldInfo.type !== 'checkbox') {
|
|
2588
|
+
if (cssFrameworkService.framework() === 'bs3' && isHorizontalStyle(options.formstyle, true) && fieldInfo.type !== 'checkbox') {
|
|
2291
2589
|
value = '<div class="bs3-input ' + markupVars.sizeClassBS3 + '">' + value + '</div>';
|
|
2292
2590
|
}
|
|
2293
2591
|
// Hack to cope with inline help in directives
|
|
2294
2592
|
var inlineHelp = (fieldInfo.helpInline || '') + (fieldInfo.helpinline || '');
|
|
2295
2593
|
if (inlineHelp.length > 0) {
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2594
|
+
var helpMarkup = cssFrameworkService.framework() === 'bs2' ? { el: 'span', cl: 'help-inline' } : { el: 'div', cl: 'help-block' };
|
|
2595
|
+
value += "<".concat(helpMarkup.el, " class=\"").concat(helpMarkup.cl, "\">").concat(inlineHelp, "</").concat(helpMarkup.el, ">");
|
|
2596
|
+
}
|
|
2597
|
+
if (!options.noid) {
|
|
2598
|
+
value += "<div ng-if=\"".concat((options.name || 'myForm'), "['").concat(fieldInfo.id, "'].$dirty\" class=\"help-block\">") +
|
|
2599
|
+
" <div ng-messages=\"".concat((options.name || 'myForm'), "['").concat(fieldInfo.id, "'].$error\">") +
|
|
2600
|
+
' <div ng-messages-include="error-messages.html">' +
|
|
2601
|
+
' </div>' +
|
|
2602
|
+
' </div>' +
|
|
2603
|
+
'</div>';
|
|
2604
|
+
}
|
|
2305
2605
|
if (fieldInfo.help) {
|
|
2306
|
-
value += '<
|
|
2606
|
+
value += '<div class="help-block">' + fieldInfo.help + '</div>';
|
|
2307
2607
|
}
|
|
2308
2608
|
return value;
|
|
2309
2609
|
},
|
|
2310
2610
|
generateSimpleInput: function generateSimpleInput(common, fieldInfo, options) {
|
|
2311
|
-
var result = '<input ' + common + 'type="' + fieldInfo.type + '"';
|
|
2611
|
+
var result = '<input ' + common + 'type="' + fieldInfo.type + '" ';
|
|
2612
|
+
if (!fieldInfo.label && !fieldInfo.ariaLabel) {
|
|
2613
|
+
result += "aria-label=\"".concat(fieldInfo.name.replace(/\./g, ' '), "\" ");
|
|
2614
|
+
}
|
|
2615
|
+
else if (options.subschema) {
|
|
2616
|
+
result += "aria-label=\"".concat(fieldInfo.label ? ($filter('titleCase')(options.subschemaroot) + ' ' + fieldInfo.label) : (fieldInfo.popup || fieldInfo.name.replace(/\./g, ' ')), "\" ");
|
|
2617
|
+
}
|
|
2312
2618
|
if (options.formstyle === 'inline' && cssFrameworkService.framework() === 'bs2' && !fieldInfo.size) {
|
|
2313
2619
|
result += 'class="input-small"';
|
|
2314
2620
|
}
|
|
@@ -2317,7 +2623,7 @@ var fng;
|
|
|
2317
2623
|
},
|
|
2318
2624
|
controlDivClasses: function controlDivClasses(options) {
|
|
2319
2625
|
var result = [];
|
|
2320
|
-
if (isHorizontalStyle(options.formstyle)) {
|
|
2626
|
+
if (isHorizontalStyle(options.formstyle, false)) {
|
|
2321
2627
|
result.push(cssFrameworkService.framework() === 'bs2' ? 'controls' : 'col-sm-9');
|
|
2322
2628
|
}
|
|
2323
2629
|
return result;
|
|
@@ -2351,7 +2657,13 @@ var fng;
|
|
|
2351
2657
|
if (fieldInfo.add) {
|
|
2352
2658
|
result += ' ' + fieldInfo.add + ' ';
|
|
2353
2659
|
}
|
|
2354
|
-
result += requiredStr
|
|
2660
|
+
result += requiredStr;
|
|
2661
|
+
if (fieldInfo.readonly) {
|
|
2662
|
+
result += " ".concat(typeof fieldInfo.readOnly === 'boolean' ? 'readonly' : 'ng-readonly="' + fieldInfo.readonly + '"', " ");
|
|
2663
|
+
}
|
|
2664
|
+
else {
|
|
2665
|
+
result += ' ';
|
|
2666
|
+
}
|
|
2355
2667
|
return result;
|
|
2356
2668
|
}
|
|
2357
2669
|
};
|
|
@@ -2411,15 +2723,17 @@ var fng;
|
|
|
2411
2723
|
var options = { formStyle: attr.formstyle };
|
|
2412
2724
|
var directiveOptions = {};
|
|
2413
2725
|
var directiveNameLength = directiveName ? directiveName.length : 0;
|
|
2726
|
+
var lcDirectiveName = directiveName === null || directiveName === void 0 ? void 0 : directiveName.toLowerCase();
|
|
2414
2727
|
for (var prop in attr) {
|
|
2415
2728
|
if (attr.hasOwnProperty(prop)) {
|
|
2416
|
-
|
|
2417
|
-
|
|
2729
|
+
var lcProp = prop.toLowerCase();
|
|
2730
|
+
if (lcProp.slice(0, 6) === 'fngfld') {
|
|
2731
|
+
info[lcProp.slice(6)] = deserialize(attr[prop]);
|
|
2418
2732
|
}
|
|
2419
|
-
else if (
|
|
2420
|
-
options[
|
|
2733
|
+
else if (lcProp.slice(0, 6) === 'fngopt') {
|
|
2734
|
+
options[lcProp.slice(6)] = deserialize(attr[prop]);
|
|
2421
2735
|
}
|
|
2422
|
-
else if (directiveName &&
|
|
2736
|
+
else if (directiveName && lcProp.slice(0, directiveNameLength) === lcDirectiveName) {
|
|
2423
2737
|
directiveOptions[_.kebabCase(prop.slice(directiveNameLength))] = deserialize(attr[prop]);
|
|
2424
2738
|
}
|
|
2425
2739
|
}
|
|
@@ -2507,26 +2821,32 @@ var fng;
|
|
|
2507
2821
|
*
|
|
2508
2822
|
*/
|
|
2509
2823
|
/*@ngInject*/
|
|
2510
|
-
recordHandler.$inject = ["$
|
|
2511
|
-
function recordHandler($
|
|
2824
|
+
recordHandler.$inject = ["$location", "$window", "$filter", "$timeout", "routingService", "cssFrameworkService", "SubmissionsService", "SchemasService"];
|
|
2825
|
+
function recordHandler($location, $window, $filter, $timeout, routingService, cssFrameworkService, SubmissionsService, SchemasService) {
|
|
2512
2826
|
// TODO: Put this in a service
|
|
2513
2827
|
var makeMongoId = function (rnd) {
|
|
2514
2828
|
if (rnd === void 0) { rnd = function (r16) { return Math.floor(r16).toString(16); }; }
|
|
2515
|
-
return rnd(Date.now() / 1000) +
|
|
2829
|
+
return rnd(Date.now() / 1000) + " ".repeat(16).replace(/./g, function () { return rnd(Math.random() * 16); });
|
|
2516
2830
|
};
|
|
2831
|
+
function _handleCancel(resp) {
|
|
2832
|
+
if (["cancel", "backdrop click", "escape key press"].indexOf(resp) === -1) {
|
|
2833
|
+
throw resp;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2517
2836
|
var suffixCleanId = function suffixCleanId(inst, suffix) {
|
|
2518
|
-
return (inst.id ||
|
|
2837
|
+
return (inst.id || "f_" + inst.name).replace(/\./g, "_") + suffix;
|
|
2519
2838
|
};
|
|
2520
|
-
var walkTree = function (object, fieldname, element) {
|
|
2839
|
+
var walkTree = function (object, fieldname, element, insertIntermediateObjects) {
|
|
2521
2840
|
// Walk through subdocs to find the required key
|
|
2522
2841
|
// for instance walkTree(master,'address.street.number',element)
|
|
2523
2842
|
// called by getData and setData
|
|
2843
|
+
if (insertIntermediateObjects === void 0) { insertIntermediateObjects = false; }
|
|
2524
2844
|
// element is used when accessing in the context of a input, as the id (like exams-2-grader)
|
|
2525
2845
|
// gives us the element of an array (one level down only for now). Leaving element blank returns the whole array
|
|
2526
|
-
var parts = fieldname.split(
|
|
2846
|
+
var parts = fieldname.split("."), higherLevels = parts.length - 1, workingRec = object;
|
|
2527
2847
|
for (var i = 0; i < higherLevels; i++) {
|
|
2528
2848
|
if (!workingRec) {
|
|
2529
|
-
throw new Error("walkTree failed: Object = "
|
|
2849
|
+
throw new Error("walkTree failed: Object = ".concat(object, ", fieldname = ").concat(fieldname, ", i = ").concat(i));
|
|
2530
2850
|
}
|
|
2531
2851
|
if (angular.isArray(workingRec)) {
|
|
2532
2852
|
workingRec = _.map(workingRec, function (obj) {
|
|
@@ -2534,18 +2854,21 @@ var fng;
|
|
|
2534
2854
|
});
|
|
2535
2855
|
}
|
|
2536
2856
|
else {
|
|
2857
|
+
if (insertIntermediateObjects && !workingRec[parts[i]]) {
|
|
2858
|
+
workingRec[parts[i]] = {};
|
|
2859
|
+
}
|
|
2537
2860
|
workingRec = workingRec[parts[i]];
|
|
2538
2861
|
}
|
|
2539
|
-
if (angular.isArray(workingRec) && typeof element !==
|
|
2540
|
-
if (element.scope && typeof element.scope ===
|
|
2862
|
+
if (angular.isArray(workingRec) && typeof element !== "undefined") {
|
|
2863
|
+
if (element.scope && typeof element.scope === "function") {
|
|
2541
2864
|
// If we come across an array we need to find the correct position, if we have an element
|
|
2542
2865
|
workingRec = workingRec[element.scope().$index];
|
|
2543
2866
|
}
|
|
2544
|
-
else if (typeof element ===
|
|
2867
|
+
else if (typeof element === "number") {
|
|
2545
2868
|
workingRec = workingRec[element];
|
|
2546
2869
|
}
|
|
2547
2870
|
else {
|
|
2548
|
-
throw new Error(
|
|
2871
|
+
throw new Error("Unsupported element type in walkTree " + fieldname);
|
|
2549
2872
|
}
|
|
2550
2873
|
}
|
|
2551
2874
|
if (!workingRec) {
|
|
@@ -2558,15 +2881,20 @@ var fng;
|
|
|
2558
2881
|
};
|
|
2559
2882
|
};
|
|
2560
2883
|
var setData = function setData(object, fieldname, element, value) {
|
|
2561
|
-
var leafData = walkTree(object, fieldname, element);
|
|
2884
|
+
var leafData = walkTree(object, fieldname, element, !!value);
|
|
2562
2885
|
if (leafData.lastObject && leafData.key) {
|
|
2563
|
-
if (
|
|
2564
|
-
|
|
2565
|
-
leafData.lastObject
|
|
2886
|
+
if (value) {
|
|
2887
|
+
if (angular.isArray(leafData.lastObject)) {
|
|
2888
|
+
for (var i = 0; i < leafData.lastObject.length; i++) {
|
|
2889
|
+
leafData.lastObject[i][leafData.key] = value[i];
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
else {
|
|
2893
|
+
leafData.lastObject[leafData.key] = value;
|
|
2566
2894
|
}
|
|
2567
2895
|
}
|
|
2568
2896
|
else {
|
|
2569
|
-
leafData.lastObject[leafData.key]
|
|
2897
|
+
delete leafData.lastObject[leafData.key];
|
|
2570
2898
|
}
|
|
2571
2899
|
}
|
|
2572
2900
|
};
|
|
@@ -2585,11 +2913,17 @@ var fng;
|
|
|
2585
2913
|
}
|
|
2586
2914
|
return retVal;
|
|
2587
2915
|
};
|
|
2588
|
-
var updateRecordWithLookupValues = function (schemaElement, $scope, ctrlState) {
|
|
2916
|
+
var updateRecordWithLookupValues = function (schemaElement, $scope, ctrlState, ignoreDirty) {
|
|
2917
|
+
if (ignoreDirty === void 0) { ignoreDirty = false; }
|
|
2589
2918
|
// Update the master and the record with the lookup values, master first
|
|
2590
|
-
if (!$scope.topLevelFormName || $scope[$scope.topLevelFormName].$pristine) {
|
|
2919
|
+
if (!$scope.topLevelFormName || ($scope[$scope.topLevelFormName] && (ignoreDirty || $scope[$scope.topLevelFormName].$pristine))) {
|
|
2591
2920
|
updateObject(schemaElement.name, ctrlState.master, function (value) {
|
|
2592
|
-
|
|
2921
|
+
if (typeof value == "object" && value.id) {
|
|
2922
|
+
return value;
|
|
2923
|
+
}
|
|
2924
|
+
else {
|
|
2925
|
+
return convertForeignKeys(schemaElement, value, $scope[suffixCleanId(schemaElement, "Options")], $scope[suffixCleanId(schemaElement, "_ids")]);
|
|
2926
|
+
}
|
|
2593
2927
|
});
|
|
2594
2928
|
// Then copy the converted keys from master into record
|
|
2595
2929
|
var newVal = getData(ctrlState.master, schemaElement.name);
|
|
@@ -2600,38 +2934,29 @@ var fng;
|
|
|
2600
2934
|
};
|
|
2601
2935
|
// Split a field name into the next level and all following levels
|
|
2602
2936
|
function splitFieldName(aFieldName) {
|
|
2603
|
-
var nesting = aFieldName.split(
|
|
2937
|
+
var nesting = aFieldName.split("."), result = [nesting[0]];
|
|
2604
2938
|
if (nesting.length > 1) {
|
|
2605
|
-
result.push(nesting.slice(1).join(
|
|
2939
|
+
result.push(nesting.slice(1).join("."));
|
|
2606
2940
|
}
|
|
2607
2941
|
return result;
|
|
2608
2942
|
}
|
|
2609
|
-
var getListData = function getListData(
|
|
2943
|
+
var getListData = function getListData(record, fieldName, listSchema, $scope) {
|
|
2610
2944
|
if (listSchema === void 0) { listSchema = null; }
|
|
2611
|
-
var retVal = record;
|
|
2612
|
-
var nests = fieldName.split('.');
|
|
2613
|
-
for (var i = 0; i < nests.length; i++) {
|
|
2614
|
-
if (retVal !== undefined && retVal !== null && nests && nests[i]) {
|
|
2615
|
-
retVal = retVal[nests[i]];
|
|
2616
|
-
}
|
|
2617
|
-
}
|
|
2618
|
-
if (retVal === undefined) {
|
|
2619
|
-
retVal = '';
|
|
2620
|
-
}
|
|
2945
|
+
var retVal = getData(record, fieldName) || "";
|
|
2621
2946
|
if (retVal && listSchema) {
|
|
2622
2947
|
// Convert list fields as per instructions in params (ideally should be the same as what is found in data_form getListFields
|
|
2623
|
-
var schemaElm = _.find(listSchema, function (elm) { return (elm[
|
|
2948
|
+
var schemaElm = _.find(listSchema, function (elm) { return (elm["name"] === fieldName); });
|
|
2624
2949
|
if (schemaElm) {
|
|
2625
|
-
switch (schemaElm[
|
|
2950
|
+
switch (schemaElm["params"]) {
|
|
2626
2951
|
case undefined:
|
|
2627
2952
|
break;
|
|
2628
|
-
case
|
|
2953
|
+
case "timestamp":
|
|
2629
2954
|
var timestamp = retVal.toString().substring(0, 8);
|
|
2630
2955
|
var date = new Date(parseInt(timestamp, 16) * 1000);
|
|
2631
|
-
retVal = date.toLocaleDateString() +
|
|
2956
|
+
retVal = date.toLocaleDateString() + " " + date.toLocaleTimeString();
|
|
2632
2957
|
break;
|
|
2633
2958
|
default:
|
|
2634
|
-
retVal = $scope.dataEventFunctions[schemaElm[
|
|
2959
|
+
retVal = $scope.dataEventFunctions[schemaElm["params"]](record);
|
|
2635
2960
|
}
|
|
2636
2961
|
}
|
|
2637
2962
|
}
|
|
@@ -2648,7 +2973,7 @@ var fng;
|
|
|
2648
2973
|
if (angular.isArray(theValue)) {
|
|
2649
2974
|
for (var i = theValue.length - 1; i >= 0; i--) {
|
|
2650
2975
|
var type = typeof theValue[i];
|
|
2651
|
-
if (type ===
|
|
2976
|
+
if (type === "undefined" || (type === "object" && Object.keys(theValue[i]).length === 0)) {
|
|
2652
2977
|
theValue.splice(i, 1);
|
|
2653
2978
|
}
|
|
2654
2979
|
}
|
|
@@ -2670,8 +2995,8 @@ var fng;
|
|
|
2670
2995
|
}
|
|
2671
2996
|
// Set up the lookup lists (value and id) on the scope for an internal lookup. Called by convertToAngularModel and $watch
|
|
2672
2997
|
function setUpInternalLookupLists($scope, options, ids, newVal, valueAttrib) {
|
|
2673
|
-
var optionsArray = (typeof options ===
|
|
2674
|
-
var idsArray = (typeof ids ===
|
|
2998
|
+
var optionsArray = (typeof options === "string" ? $scope[options] : options);
|
|
2999
|
+
var idsArray = (typeof ids === "string" ? $scope[ids] : ids);
|
|
2675
3000
|
optionsArray.length = 0;
|
|
2676
3001
|
idsArray.length = 0;
|
|
2677
3002
|
if (!!newVal && (newVal.length > 0)) {
|
|
@@ -2693,10 +3018,10 @@ var fng;
|
|
|
2693
3018
|
result = true;
|
|
2694
3019
|
}
|
|
2695
3020
|
else if (!aSchema.directive) {
|
|
2696
|
-
if (aSchema.type ===
|
|
3021
|
+
if (aSchema.type === "text") {
|
|
2697
3022
|
result = true;
|
|
2698
3023
|
}
|
|
2699
|
-
else if (aSchema.type ===
|
|
3024
|
+
else if (aSchema.type === "select" && !aSchema.ids) {
|
|
2700
3025
|
result = true;
|
|
2701
3026
|
}
|
|
2702
3027
|
}
|
|
@@ -2706,7 +3031,7 @@ var fng;
|
|
|
2706
3031
|
function getConversionObject(scope, entryName, schemaName) {
|
|
2707
3032
|
var conversions = scope.conversions;
|
|
2708
3033
|
if (schemaName) {
|
|
2709
|
-
conversions = conversions
|
|
3034
|
+
conversions = getData(conversions, schemaName) || {};
|
|
2710
3035
|
}
|
|
2711
3036
|
return conversions[entryName];
|
|
2712
3037
|
}
|
|
@@ -2717,37 +3042,58 @@ var fng;
|
|
|
2717
3042
|
for (var i = 0; i < schema.length; i++) {
|
|
2718
3043
|
var schemaEntry = schema[i];
|
|
2719
3044
|
var fieldName = schemaEntry.name.slice(prefixLength);
|
|
3045
|
+
if (!fieldName.length) {
|
|
3046
|
+
fieldName = schemaEntry.name.split('.').pop();
|
|
3047
|
+
}
|
|
2720
3048
|
var fieldValue = getData(anObject, fieldName);
|
|
3049
|
+
if (schemaEntry.intType === 'date' && typeof fieldValue === 'string') {
|
|
3050
|
+
setData(anObject, fieldName, null, new Date(fieldValue));
|
|
3051
|
+
}
|
|
2721
3052
|
if (schemaEntry.schema) {
|
|
2722
3053
|
if (fieldValue) {
|
|
2723
3054
|
for (var j = 0; j < fieldValue.length; j++) {
|
|
2724
|
-
fieldValue[j] = convertToAngularModel(schemaEntry.schema, fieldValue[j],
|
|
3055
|
+
fieldValue[j] = convertToAngularModel(schemaEntry.schema, fieldValue[j], 1 + fieldName.length, $scope, fieldName, master, j);
|
|
2725
3056
|
}
|
|
2726
3057
|
}
|
|
2727
3058
|
}
|
|
2728
3059
|
else {
|
|
2729
|
-
if (schemaEntry.
|
|
2730
|
-
setUpInternalLookupLists($scope, schemaEntry.options, schemaEntry.ids, master[schemaEntry.
|
|
3060
|
+
if (schemaEntry.internalRef) {
|
|
3061
|
+
setUpInternalLookupLists($scope, schemaEntry.options, schemaEntry.ids, master[schemaEntry.internalRef.property], schemaEntry.internalRef.value);
|
|
2731
3062
|
}
|
|
2732
3063
|
// Convert {array:['item 1']} to {array:[{x:'item 1'}]}
|
|
2733
|
-
var thisField = getListData(
|
|
2734
|
-
if (schemaEntry.array &&
|
|
3064
|
+
var thisField = getListData(anObject, fieldName, null, $scope);
|
|
3065
|
+
if (schemaEntry.array &&
|
|
3066
|
+
simpleArrayNeedsX(schemaEntry) &&
|
|
3067
|
+
thisField &&
|
|
3068
|
+
!(thisField.length > 0 && thisField[0].x) // Don't keep on coverting
|
|
3069
|
+
) {
|
|
2735
3070
|
for (var k = 0; k < thisField.length; k++) {
|
|
2736
3071
|
thisField[k] = { x: thisField[k] };
|
|
2737
3072
|
}
|
|
2738
3073
|
}
|
|
2739
3074
|
// Convert {lookup:'012abcde'} to {lookup:'List description for 012abcde'}
|
|
2740
|
-
var idList = $scope[suffixCleanId(schemaEntry,
|
|
3075
|
+
var idList = $scope[suffixCleanId(schemaEntry, "_ids")];
|
|
2741
3076
|
var thisConversion = void 0;
|
|
2742
3077
|
if (fieldValue && idList && idList.length > 0) {
|
|
2743
|
-
if (fieldName.indexOf(
|
|
2744
|
-
throw new Error(
|
|
3078
|
+
if (fieldName.indexOf(".") !== -1) {
|
|
3079
|
+
throw new Error("Trying to directly assign to a nested field 332");
|
|
2745
3080
|
} // Not sure that this can happen, but put in a runtime test
|
|
2746
|
-
|
|
3081
|
+
if (
|
|
3082
|
+
/*
|
|
3083
|
+
Check we are starting with an ObjectId (ie not being called because of $watch on conversion, with a
|
|
3084
|
+
converted value, which would cause an exception)
|
|
3085
|
+
*/
|
|
3086
|
+
fieldValue.toString().match(/^[a-f0-9]{24}$/) &&
|
|
3087
|
+
/*
|
|
3088
|
+
We are not suppressing conversions
|
|
3089
|
+
*/
|
|
3090
|
+
(!schemaEntry.internalRef || !schemaEntry.internalRef.noConvert)) {
|
|
3091
|
+
anObject[fieldName] = convertForeignKeys(schemaEntry, fieldValue, $scope[suffixCleanId(schemaEntry, "Options")], idList);
|
|
3092
|
+
}
|
|
2747
3093
|
}
|
|
2748
3094
|
else if (schemaEntry.select2) {
|
|
2749
3095
|
// Do nothing with these - handled elsewhere (and deprecated)
|
|
2750
|
-
console.log(
|
|
3096
|
+
console.log("fng-select2 is deprecated - use fng-ui-select instead");
|
|
2751
3097
|
void (schemaEntry.select2);
|
|
2752
3098
|
}
|
|
2753
3099
|
else if (fieldValue && (thisConversion = getConversionObject($scope, fieldName, schemaName)) &&
|
|
@@ -2756,7 +3102,7 @@ var fng;
|
|
|
2756
3102
|
thisConversion.fngajax(fieldValue, schemaEntry, function (updateEntry, value) {
|
|
2757
3103
|
// Update the master and (preserving pristine if appropriate) the record
|
|
2758
3104
|
setData(master, updateEntry.name, offset, value);
|
|
2759
|
-
preservePristine(angular.element(
|
|
3105
|
+
preservePristine(angular.element("#" + updateEntry.id), function () {
|
|
2760
3106
|
setData($scope.record, updateEntry.name, offset, value);
|
|
2761
3107
|
});
|
|
2762
3108
|
});
|
|
@@ -2769,9 +3115,9 @@ var fng;
|
|
|
2769
3115
|
// Called when the model is read and when the lookups are read
|
|
2770
3116
|
// No support for nested schemas here as it is called from convertToAngularModel which does that
|
|
2771
3117
|
function convertForeignKeys(schemaElement, input, values, ids) {
|
|
2772
|
-
if (schemaElement.array) {
|
|
3118
|
+
if (schemaElement.array || angular.isArray(input)) {
|
|
2773
3119
|
var returnArray = [];
|
|
2774
|
-
var needsX = !schemaElement.directive || simpleArrayNeedsX(schemaElement);
|
|
3120
|
+
var needsX = schemaElement.array && (!schemaElement.directive || simpleArrayNeedsX(schemaElement));
|
|
2775
3121
|
for (var j = 0; j < input.length; j++) {
|
|
2776
3122
|
var val = input[j];
|
|
2777
3123
|
if (val && val.x) {
|
|
@@ -2815,7 +3161,7 @@ var fng;
|
|
|
2815
3161
|
else {
|
|
2816
3162
|
var index = valuesArray.indexOf(textToConvert);
|
|
2817
3163
|
if (index === -1) {
|
|
2818
|
-
throw new Error(
|
|
3164
|
+
throw new Error("convertListValueToId: Invalid data - value " + textToConvert + " not found in " + valuesArray + " processing " + fname);
|
|
2819
3165
|
}
|
|
2820
3166
|
return idsArray[index];
|
|
2821
3167
|
}
|
|
@@ -2823,7 +3169,7 @@ var fng;
|
|
|
2823
3169
|
var preservePristine = function preservePristine(element, fn) {
|
|
2824
3170
|
// stop the form being set to dirty when a fn is called
|
|
2825
3171
|
// Use when the record (and master) need to be updated by lookup values displayed asynchronously
|
|
2826
|
-
var modelController = element.inheritedData(
|
|
3172
|
+
var modelController = element.inheritedData("$ngModelController");
|
|
2827
3173
|
var isClean = (modelController && modelController.$pristine);
|
|
2828
3174
|
if (isClean) {
|
|
2829
3175
|
// fake it to dirty here and reset after call to fn
|
|
@@ -2835,18 +3181,21 @@ var fng;
|
|
|
2835
3181
|
}
|
|
2836
3182
|
};
|
|
2837
3183
|
var convertIdToListValue = function convertIdToListValue(id, idsArray, valuesArray, fname) {
|
|
2838
|
-
if (typeof (id) ===
|
|
3184
|
+
if (typeof (id) === "object") {
|
|
2839
3185
|
id = id.id;
|
|
2840
3186
|
}
|
|
2841
3187
|
var index = idsArray.indexOf(id);
|
|
2842
3188
|
if (index === -1) {
|
|
2843
|
-
|
|
3189
|
+
index = valuesArray.indexOf(id); // This can get called twice - second time with converted value (not sure how atm) so protect against that...
|
|
3190
|
+
if (index === -1) {
|
|
3191
|
+
throw new Error("convertIdToListValue: Invalid data - id " + id + " not found in " + idsArray + " processing " + fname);
|
|
3192
|
+
}
|
|
2844
3193
|
}
|
|
2845
3194
|
return valuesArray[index];
|
|
2846
3195
|
};
|
|
2847
3196
|
var processServerData = function processServerData(recordFromServer, $scope, ctrlState) {
|
|
2848
3197
|
ctrlState.master = convertToAngularModel($scope.formSchema, recordFromServer, 0, $scope);
|
|
2849
|
-
$scope.phase =
|
|
3198
|
+
$scope.phase = "ready";
|
|
2850
3199
|
$scope.cancel();
|
|
2851
3200
|
};
|
|
2852
3201
|
function convertOldToNew(ref, val, attrib, newVals, oldVals) {
|
|
@@ -2865,102 +3214,169 @@ var fng;
|
|
|
2865
3214
|
var listOnly = (!$scope.id && !$scope.newRecord);
|
|
2866
3215
|
// passing null for formSchema parameter prevents all the work being done when we are just after the list data,
|
|
2867
3216
|
// but should be removed when/if formschemas are cached
|
|
2868
|
-
formGeneratorInstance.handleSchema(
|
|
3217
|
+
formGeneratorInstance.handleSchema("Main " + $scope.modelName, schema, listOnly ? null : $scope.formSchema, $scope.listSchema, "", true, $scope, ctrlState);
|
|
3218
|
+
function processLookupHandlers(newValue, oldValue) {
|
|
3219
|
+
// If we have any internal lookups then update the references
|
|
3220
|
+
$scope.internalLookups.forEach(function (lkp) {
|
|
3221
|
+
var newVal = newValue[lkp.ref.property];
|
|
3222
|
+
var oldVal = oldValue[lkp.ref.property];
|
|
3223
|
+
setUpInternalLookupLists($scope, lkp.lookupOptions, lkp.lookupIds, newVal, lkp.ref.value);
|
|
3224
|
+
// now change the looked-up values that matched the old to the new
|
|
3225
|
+
if ((newVal && newVal.length > 0) || (oldVal && oldVal.length > 0)) {
|
|
3226
|
+
lkp.handlers.forEach(function (h) {
|
|
3227
|
+
if (h.possibleArray) {
|
|
3228
|
+
var arr = getData($scope.record, h.possibleArray, null);
|
|
3229
|
+
if (arr && arr.length > 0) {
|
|
3230
|
+
arr.forEach(function (a) { return convertOldToNew(lkp.ref, a, h.lastPart, newVal, oldVal); });
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
else if (angular.isArray($scope.record[h.lastPart])) {
|
|
3234
|
+
$scope.record[h.lastPart].forEach(function (a) {
|
|
3235
|
+
convertOldToNew(lkp.ref, a, "x", newVal, oldVal);
|
|
3236
|
+
});
|
|
3237
|
+
}
|
|
3238
|
+
else {
|
|
3239
|
+
convertOldToNew(lkp.ref, $scope.record, h.lastPart, newVal, oldVal);
|
|
3240
|
+
}
|
|
3241
|
+
});
|
|
3242
|
+
}
|
|
3243
|
+
});
|
|
3244
|
+
// If we have any list lookups then update the references
|
|
3245
|
+
$scope.listLookups.forEach(function (lkp) {
|
|
3246
|
+
function extractIdVal(obj, idString) {
|
|
3247
|
+
var retVal = obj[idString];
|
|
3248
|
+
if (retVal && retVal.id) {
|
|
3249
|
+
retVal = retVal.id;
|
|
3250
|
+
}
|
|
3251
|
+
return retVal;
|
|
3252
|
+
}
|
|
3253
|
+
function blankListLookup(inst) {
|
|
3254
|
+
setData($scope.record, inst.name);
|
|
3255
|
+
}
|
|
3256
|
+
var idString = lkp.ref.id.slice(1);
|
|
3257
|
+
if (idString.includes(".")) {
|
|
3258
|
+
throw new Error("No support for nested list lookups yet - ".concat(JSON.stringify(lkp.ref)));
|
|
3259
|
+
}
|
|
3260
|
+
var newVal = extractIdVal(newValue, idString);
|
|
3261
|
+
var oldVal = extractIdVal(oldValue, idString);
|
|
3262
|
+
if (newVal !== oldVal) {
|
|
3263
|
+
if (newVal) {
|
|
3264
|
+
if (oldVal) {
|
|
3265
|
+
lkp.handlers.forEach(function (h) {
|
|
3266
|
+
h.oldValue = getData($scope.record, h.formInstructions.name);
|
|
3267
|
+
if (angular.isArray(h.oldValue)) {
|
|
3268
|
+
h.oldId = h.oldValue.map(function (a) {
|
|
3269
|
+
return $scope[h.formInstructions.ids][$scope[h.formInstructions.options].indexOf(a)];
|
|
3270
|
+
});
|
|
3271
|
+
}
|
|
3272
|
+
else {
|
|
3273
|
+
h.oldId = $scope[h.formInstructions.ids][$scope[h.formInstructions.options].indexOf(h.oldValue)];
|
|
3274
|
+
}
|
|
3275
|
+
});
|
|
3276
|
+
}
|
|
3277
|
+
SubmissionsService.readRecord(lkp.ref.collection, newVal).then(function (response) {
|
|
3278
|
+
lkp.handlers.forEach(function (h) {
|
|
3279
|
+
var optionsList = $scope[h.formInstructions.options];
|
|
3280
|
+
optionsList.length = 0;
|
|
3281
|
+
var idList = $scope[h.formInstructions.ids];
|
|
3282
|
+
idList.length = 0;
|
|
3283
|
+
var data = response.data[lkp.ref.property] || [];
|
|
3284
|
+
for (var i = 0; i < data.length; i++) {
|
|
3285
|
+
var option = data[i][lkp.ref.value];
|
|
3286
|
+
var pos = _.sortedIndex(optionsList, option);
|
|
3287
|
+
// handle dupes
|
|
3288
|
+
if (optionsList[pos] === option) {
|
|
3289
|
+
option = option + " (" + data[i]._id + ")";
|
|
3290
|
+
pos = _.sortedIndex(optionsList, option);
|
|
3291
|
+
}
|
|
3292
|
+
optionsList.splice(pos, 0, option);
|
|
3293
|
+
idList.splice(pos, 0, data[i]._id);
|
|
3294
|
+
}
|
|
3295
|
+
if (Object.keys(oldValue).length === 0) {
|
|
3296
|
+
// Not sure how safe this is, but the record is fresh so I think it's OK...
|
|
3297
|
+
updateRecordWithLookupValues(h.formInstructions, $scope, ctrlState, true);
|
|
3298
|
+
}
|
|
3299
|
+
else if (h.oldId) {
|
|
3300
|
+
// Here we are reacting to a change in the lookup pointer in the record.
|
|
3301
|
+
// If the old id exists in the new idList we can keep it, otherwise we need to blank it.
|
|
3302
|
+
// We need to remember that we can have an array of ids
|
|
3303
|
+
if (angular.isArray(h.oldId)) {
|
|
3304
|
+
h.oldId.forEach(function (id, idx) {
|
|
3305
|
+
var pos = idList.indexOf(id);
|
|
3306
|
+
setData($scope.record, h.formInstructions.name, idx, pos === -1 ? undefined : optionsList[pos]);
|
|
3307
|
+
});
|
|
3308
|
+
}
|
|
3309
|
+
else {
|
|
3310
|
+
var pos_1 = idList.indexOf(h.oldId);
|
|
3311
|
+
if (pos_1 !== -1) {
|
|
3312
|
+
setData($scope.record, h.formInstructions.name, undefined, optionsList[pos_1]);
|
|
3313
|
+
}
|
|
3314
|
+
else {
|
|
3315
|
+
blankListLookup(h.formInstructions);
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
else {
|
|
3320
|
+
blankListLookup(h.formInstructions);
|
|
3321
|
+
}
|
|
3322
|
+
});
|
|
3323
|
+
});
|
|
3324
|
+
}
|
|
3325
|
+
else {
|
|
3326
|
+
lkp.handlers.forEach(function (h) {
|
|
3327
|
+
$scope[h.formInstructions.options].length = 0;
|
|
3328
|
+
$scope[h.formInstructions.ids].length = 0;
|
|
3329
|
+
blankListLookup(h.formInstructions);
|
|
3330
|
+
});
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
});
|
|
3334
|
+
}
|
|
3335
|
+
function notifyReady() {
|
|
3336
|
+
$scope.phase = "ready";
|
|
3337
|
+
$scope.cancel();
|
|
3338
|
+
processLookupHandlers($scope.record, {});
|
|
3339
|
+
}
|
|
2869
3340
|
if (listOnly) {
|
|
2870
3341
|
ctrlState.allowLocationChange = true;
|
|
2871
3342
|
}
|
|
2872
3343
|
else {
|
|
2873
3344
|
var force = true;
|
|
2874
3345
|
if (!$scope.newRecord) {
|
|
2875
|
-
$scope.dropConversionWatcher = $scope.$watchCollection(
|
|
3346
|
+
$scope.dropConversionWatcher = $scope.$watchCollection("conversions", function (newValue, oldValue) {
|
|
2876
3347
|
if (newValue !== oldValue && $scope.originalData) {
|
|
2877
3348
|
processServerData($scope.originalData, $scope, ctrlState);
|
|
2878
3349
|
}
|
|
2879
3350
|
});
|
|
2880
3351
|
}
|
|
2881
|
-
$scope.$watch(
|
|
3352
|
+
$scope.$watch("record", function (newValue, oldValue) {
|
|
2882
3353
|
if (newValue !== oldValue) {
|
|
2883
3354
|
if (Object.keys(oldValue).length > 0 && $scope.dropConversionWatcher) {
|
|
2884
3355
|
$scope.dropConversionWatcher(); // Don't want to convert changed data
|
|
2885
3356
|
$scope.dropConversionWatcher = null;
|
|
2886
3357
|
}
|
|
2887
3358
|
force = formGeneratorInstance.updateDataDependentDisplay(newValue, oldValue, force, $scope);
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
var
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
// now change the looked-up values that matched the old to the new
|
|
2894
|
-
if ((newVal && newVal.length > 0) || (oldVal && oldVal.length > 0)) {
|
|
2895
|
-
lkp.handlers.forEach(function (h) {
|
|
2896
|
-
if (h.possibleArray) {
|
|
2897
|
-
var arr = getData($scope.record, h.possibleArray, null);
|
|
2898
|
-
if (arr && arr.length > 0) {
|
|
2899
|
-
arr.forEach(function (a) { return convertOldToNew(lkp.ref, a, h.lastPart, newVal, oldVal); });
|
|
2900
|
-
}
|
|
2901
|
-
}
|
|
2902
|
-
else if (angular.isArray($scope.record[h.lastPart])) {
|
|
2903
|
-
$scope.record[h.lastPart].forEach(function (a) {
|
|
2904
|
-
convertOldToNew(lkp.ref, a, 'x', newVal, oldVal);
|
|
2905
|
-
});
|
|
2906
|
-
}
|
|
2907
|
-
else {
|
|
2908
|
-
convertOldToNew(lkp.ref, $scope.record, h.lastPart, newVal, oldVal);
|
|
2909
|
-
}
|
|
2910
|
-
});
|
|
3359
|
+
processLookupHandlers(newValue, oldValue);
|
|
3360
|
+
if (fng.formsAngular.title) {
|
|
3361
|
+
var title = fng.formsAngular.title.prefix || '';
|
|
3362
|
+
if ($scope['editFormHeader']) {
|
|
3363
|
+
title += $scope['editFormHeader']();
|
|
2911
3364
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
if (retVal && retVal.id) {
|
|
2918
|
-
retVal = retVal.id;
|
|
2919
|
-
}
|
|
2920
|
-
return retVal;
|
|
2921
|
-
}
|
|
2922
|
-
var idString = lkp.ref.id.slice(1);
|
|
2923
|
-
if (idString.includes('.')) {
|
|
2924
|
-
throw new Error("No support for nested list lookups yet - " + JSON.stringify(lkp.ref));
|
|
2925
|
-
}
|
|
2926
|
-
var newVal = extractIdVal(newValue, idString);
|
|
2927
|
-
var oldVal = extractIdVal(oldValue, idString);
|
|
2928
|
-
if (newVal !== oldVal) {
|
|
2929
|
-
if (newVal) {
|
|
2930
|
-
SubmissionsService.readRecord(lkp.ref.collection, newVal).then(function (response) {
|
|
2931
|
-
lkp.handlers.forEach(function (h) {
|
|
2932
|
-
var optionsList = $scope[h.formInstructions.options];
|
|
2933
|
-
var idList = $scope[h.formInstructions.ids];
|
|
2934
|
-
var data = response.data[lkp.ref.property] || [];
|
|
2935
|
-
for (var i = 0; i < data.length; i++) {
|
|
2936
|
-
var option = data[i][lkp.ref.value];
|
|
2937
|
-
var pos = _.sortedIndex(optionsList, option);
|
|
2938
|
-
// handle dupes
|
|
2939
|
-
if (optionsList[pos] === option) {
|
|
2940
|
-
option = option + ' (' + data[i]._id + ')';
|
|
2941
|
-
pos = _.sortedIndex(optionsList, option);
|
|
2942
|
-
}
|
|
2943
|
-
optionsList.splice(pos, 0, option);
|
|
2944
|
-
idList.splice(pos, 0, data[i]._id);
|
|
2945
|
-
}
|
|
2946
|
-
updateRecordWithLookupValues(h.formInstructions, $scope, ctrlState);
|
|
2947
|
-
});
|
|
2948
|
-
});
|
|
2949
|
-
}
|
|
2950
|
-
else {
|
|
2951
|
-
lkp.handlers.forEach(function (h) {
|
|
2952
|
-
$scope[h.formInstructions.options].length = 0;
|
|
2953
|
-
$scope[h.formInstructions.ids].length = 0;
|
|
2954
|
-
updateRecordWithLookupValues(h.formInstructions, $scope, ctrlState);
|
|
2955
|
-
});
|
|
3365
|
+
else {
|
|
3366
|
+
for (var listElm in $scope.listSchema) {
|
|
3367
|
+
if ($scope.listSchema.hasOwnProperty(listElm)) {
|
|
3368
|
+
title += $scope.getListData($scope.record, $scope.listSchema[listElm].name) + ' ';
|
|
3369
|
+
}
|
|
2956
3370
|
}
|
|
2957
3371
|
}
|
|
2958
|
-
|
|
3372
|
+
title = title.trimEnd() + (fng.formsAngular.title.suffix || '');
|
|
3373
|
+
$window.document.title = title;
|
|
3374
|
+
}
|
|
2959
3375
|
}
|
|
2960
3376
|
}, true);
|
|
2961
3377
|
if ($scope.id) {
|
|
2962
3378
|
// Going to read a record
|
|
2963
|
-
if (typeof $scope.dataEventFunctions.onBeforeRead ===
|
|
3379
|
+
if (typeof $scope.dataEventFunctions.onBeforeRead === "function") {
|
|
2964
3380
|
$scope.dataEventFunctions.onBeforeRead($scope.id, function (err) {
|
|
2965
3381
|
if (err) {
|
|
2966
3382
|
$scope.showError(err);
|
|
@@ -2976,99 +3392,125 @@ var fng;
|
|
|
2976
3392
|
}
|
|
2977
3393
|
else {
|
|
2978
3394
|
// New record
|
|
2979
|
-
ctrlState.
|
|
3395
|
+
ctrlState.allowLocationChange = false;
|
|
3396
|
+
ctrlState.master = $scope.setDefaults($scope.formSchema);
|
|
2980
3397
|
var passedRecord = $scope.initialiseNewRecord || $location.$$search.r;
|
|
2981
3398
|
if (passedRecord) {
|
|
2982
3399
|
try {
|
|
2983
|
-
ctrlState.master
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
$scope[$scope.topLevelFormName]
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3400
|
+
Object.assign(ctrlState.master, JSON.parse(passedRecord));
|
|
3401
|
+
if (!$scope["newRecordsStartPristine"]) {
|
|
3402
|
+
// Although this is a new record we are making it dirty from the url so we need to $setDirty
|
|
3403
|
+
$scope.$on("fngCancel", function () {
|
|
3404
|
+
$timeout(function () {
|
|
3405
|
+
if ($scope[$scope.topLevelFormName]) {
|
|
3406
|
+
$scope[$scope.topLevelFormName].$setDirty();
|
|
3407
|
+
}
|
|
3408
|
+
}, 1000); // Has to fire after the setPristime timeout.
|
|
3409
|
+
});
|
|
3410
|
+
}
|
|
2992
3411
|
}
|
|
2993
3412
|
catch (e) {
|
|
2994
|
-
console.log(
|
|
3413
|
+
console.log("Error parsing specified record : " + e.message);
|
|
2995
3414
|
}
|
|
2996
3415
|
}
|
|
2997
|
-
if (typeof $scope.dataEventFunctions.onInitialiseNewRecord ===
|
|
3416
|
+
if (typeof $scope.dataEventFunctions.onInitialiseNewRecord === "function") {
|
|
3417
|
+
console.log("onInitialiseNewRecord is deprecated - use the async version - onNewRecordInit(data,cb)");
|
|
2998
3418
|
$scope.dataEventFunctions.onInitialiseNewRecord(ctrlState.master);
|
|
2999
3419
|
}
|
|
3000
|
-
$scope.
|
|
3001
|
-
|
|
3420
|
+
if (typeof $scope.dataEventFunctions.onNewRecordInit === "function") {
|
|
3421
|
+
$scope.dataEventFunctions.onNewRecordInit(ctrlState.master, function (err) {
|
|
3422
|
+
if (err) {
|
|
3423
|
+
$scope.showError(err);
|
|
3424
|
+
}
|
|
3425
|
+
else {
|
|
3426
|
+
notifyReady();
|
|
3427
|
+
}
|
|
3428
|
+
});
|
|
3429
|
+
}
|
|
3430
|
+
else {
|
|
3431
|
+
notifyReady();
|
|
3432
|
+
}
|
|
3002
3433
|
}
|
|
3003
3434
|
}
|
|
3004
3435
|
}
|
|
3005
3436
|
function handleError($scope) {
|
|
3006
3437
|
return function (response) {
|
|
3007
3438
|
if ([200, 400].indexOf(response.status) !== -1) {
|
|
3008
|
-
var errorMessage =
|
|
3439
|
+
var errorMessage = "";
|
|
3009
3440
|
for (var errorField in response.data.errors) {
|
|
3010
3441
|
if (response.data.errors.hasOwnProperty(errorField)) {
|
|
3011
|
-
errorMessage +=
|
|
3442
|
+
errorMessage += "<li><b>" + $filter("titleCase")(errorField) + ": </b> ";
|
|
3012
3443
|
switch (response.data.errors[errorField].type) {
|
|
3013
|
-
case
|
|
3014
|
-
errorMessage +=
|
|
3444
|
+
case "enum":
|
|
3445
|
+
errorMessage += "You need to select from the list of values";
|
|
3015
3446
|
break;
|
|
3016
3447
|
default:
|
|
3017
3448
|
errorMessage += response.data.errors[errorField].message;
|
|
3018
3449
|
break;
|
|
3019
3450
|
}
|
|
3020
|
-
errorMessage +=
|
|
3451
|
+
errorMessage += "</li>";
|
|
3021
3452
|
}
|
|
3022
3453
|
}
|
|
3023
3454
|
if (errorMessage.length > 0) {
|
|
3024
|
-
errorMessage = response.data.message +
|
|
3455
|
+
errorMessage = (response.data.message || response.data._message) + "<br /><ul>" + errorMessage + "</ul>";
|
|
3025
3456
|
}
|
|
3026
3457
|
else {
|
|
3027
|
-
errorMessage = response.data.message ||
|
|
3458
|
+
errorMessage = response.data.message || response.data._message || response.data.err || "Error! Sorry - No further details available.";
|
|
3028
3459
|
}
|
|
3029
3460
|
$scope.showError(errorMessage);
|
|
3030
3461
|
}
|
|
3031
3462
|
else {
|
|
3032
|
-
$scope.showError(response.status +
|
|
3463
|
+
$scope.showError(response.status + " " + JSON.stringify(response.data));
|
|
3033
3464
|
}
|
|
3034
3465
|
};
|
|
3035
3466
|
}
|
|
3036
3467
|
function handleIncomingData(data, $scope, ctrlState) {
|
|
3037
3468
|
ctrlState.allowLocationChange = false;
|
|
3038
|
-
$scope.phase =
|
|
3039
|
-
if (typeof $scope.dataEventFunctions.onAfterRead ===
|
|
3469
|
+
$scope.phase = "reading";
|
|
3470
|
+
if (typeof $scope.dataEventFunctions.onAfterRead === "function") {
|
|
3040
3471
|
$scope.dataEventFunctions.onAfterRead(data);
|
|
3041
3472
|
}
|
|
3042
3473
|
$scope.originalData = data;
|
|
3043
3474
|
processServerData(data, $scope, ctrlState);
|
|
3044
3475
|
}
|
|
3476
|
+
function addArrayLookupToLookupList($scope, formInstructions, ref, lookups) {
|
|
3477
|
+
var nameElements = formInstructions.name.split(".");
|
|
3478
|
+
var refHandler = lookups.find(function (lkp) {
|
|
3479
|
+
return lkp.ref.property === ref.property && lkp.ref.value === ref.value;
|
|
3480
|
+
});
|
|
3481
|
+
var thisHandler = {
|
|
3482
|
+
formInstructions: formInstructions,
|
|
3483
|
+
lastPart: nameElements.pop(),
|
|
3484
|
+
possibleArray: nameElements.join(".")
|
|
3485
|
+
};
|
|
3486
|
+
if (!refHandler) {
|
|
3487
|
+
refHandler = {
|
|
3488
|
+
ref: ref,
|
|
3489
|
+
lookupOptions: [],
|
|
3490
|
+
lookupIds: [],
|
|
3491
|
+
handlers: []
|
|
3492
|
+
};
|
|
3493
|
+
lookups.push(refHandler);
|
|
3494
|
+
}
|
|
3495
|
+
refHandler.handlers.push(thisHandler);
|
|
3496
|
+
$scope[formInstructions.options] = refHandler.lookupOptions;
|
|
3497
|
+
$scope[formInstructions.ids] = refHandler.lookupIds;
|
|
3498
|
+
}
|
|
3045
3499
|
return {
|
|
3046
3500
|
readRecord: function readRecord($scope, ctrlState) {
|
|
3047
|
-
|
|
3048
|
-
|
|
3501
|
+
$scope.readingRecord = SubmissionsService.readRecord($scope.modelName, $scope.id);
|
|
3502
|
+
$scope.readingRecord
|
|
3049
3503
|
.then(function (response) {
|
|
3050
|
-
var data = response.data;
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
//
|
|
3056
|
-
// ctrlState.allowLocationChange = false;
|
|
3057
|
-
// $scope.phase = 'ready';
|
|
3058
|
-
// $scope.record = angular.copy(response.data);
|
|
3059
|
-
// ctrlState.master = angular.copy(response.master);
|
|
3060
|
-
// if (response.changed) {
|
|
3061
|
-
// $timeout(() => {
|
|
3062
|
-
// $scope[$scope.topLevelFormName].$setDirty();
|
|
3063
|
-
// });
|
|
3064
|
-
// } else {
|
|
3065
|
-
// $timeout($scope.setPristine);
|
|
3066
|
-
// }
|
|
3504
|
+
var data = angular.copy(response.data);
|
|
3505
|
+
handleIncomingData(data, $scope, ctrlState);
|
|
3506
|
+
}, function (error) {
|
|
3507
|
+
if (error.status === 404) {
|
|
3508
|
+
$location.path("/404");
|
|
3067
3509
|
}
|
|
3068
3510
|
else {
|
|
3069
|
-
|
|
3511
|
+
$scope.handleHttpError(error);
|
|
3070
3512
|
}
|
|
3071
|
-
}
|
|
3513
|
+
});
|
|
3072
3514
|
},
|
|
3073
3515
|
scrollTheList: function scrollTheList($scope) {
|
|
3074
3516
|
var pagesLoaded = $scope.pagesLoaded;
|
|
@@ -3088,31 +3530,38 @@ var fng;
|
|
|
3088
3530
|
$scope.recordList = $scope.recordList.concat(data);
|
|
3089
3531
|
}
|
|
3090
3532
|
else {
|
|
3091
|
-
console.log(
|
|
3533
|
+
console.log("DEBUG: infinite scroll component asked for a page twice - the model was " + $scope.modelName);
|
|
3092
3534
|
}
|
|
3093
3535
|
}
|
|
3094
3536
|
else {
|
|
3095
|
-
$scope.showError(data,
|
|
3537
|
+
$scope.showError(data, "Invalid query");
|
|
3096
3538
|
}
|
|
3097
3539
|
}, $scope.handleHttpError);
|
|
3098
3540
|
},
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
SubmissionsService.deleteRecord(model, id)
|
|
3541
|
+
deleteRecord: function deleteRecord(id, $scope, ctrlState) {
|
|
3542
|
+
SubmissionsService.deleteRecord($scope.modelName, id)
|
|
3102
3543
|
.then(function () {
|
|
3103
|
-
if (typeof $scope.dataEventFunctions.onAfterDelete ===
|
|
3544
|
+
if (typeof $scope.dataEventFunctions.onAfterDelete === "function") {
|
|
3104
3545
|
$scope.dataEventFunctions.onAfterDelete(ctrlState.master);
|
|
3105
3546
|
}
|
|
3106
|
-
routingService.redirectTo()(
|
|
3547
|
+
routingService.redirectTo()("onDelete", $scope, $location);
|
|
3548
|
+
}, function (err) {
|
|
3549
|
+
if (err.status === 404) {
|
|
3550
|
+
// Someone already deleted it
|
|
3551
|
+
routingService.redirectTo()("onDelete", $scope, $location);
|
|
3552
|
+
}
|
|
3553
|
+
else {
|
|
3554
|
+
$scope.showError("".concat(err.statusText, " (").concat(err.status, ") while deleting record<br />").concat(err.data), 'Error deleting record');
|
|
3555
|
+
}
|
|
3107
3556
|
});
|
|
3108
3557
|
},
|
|
3109
3558
|
updateDocument: function updateDocument(dataToSave, options, $scope, ctrlState) {
|
|
3110
|
-
$scope.phase =
|
|
3559
|
+
$scope.phase = "updating";
|
|
3111
3560
|
SubmissionsService.updateRecord($scope.modelName, $scope.id, dataToSave)
|
|
3112
3561
|
.then(function (response) {
|
|
3113
3562
|
var data = response.data;
|
|
3114
3563
|
if (data.success !== false) {
|
|
3115
|
-
if (typeof $scope.dataEventFunctions.onAfterUpdate ===
|
|
3564
|
+
if (typeof $scope.dataEventFunctions.onAfterUpdate === "function") {
|
|
3116
3565
|
$scope.dataEventFunctions.onAfterUpdate(data, ctrlState.master);
|
|
3117
3566
|
}
|
|
3118
3567
|
if (options.redirect) {
|
|
@@ -3131,19 +3580,20 @@ var fng;
|
|
|
3131
3580
|
}
|
|
3132
3581
|
}, $scope.handleHttpError);
|
|
3133
3582
|
},
|
|
3134
|
-
createNew: function createNew(dataToSave, options, $scope) {
|
|
3583
|
+
createNew: function createNew(dataToSave, options, $scope, ctrlState) {
|
|
3135
3584
|
SubmissionsService.createRecord($scope.modelName, dataToSave)
|
|
3136
3585
|
.then(function (response) {
|
|
3137
3586
|
var data = response.data;
|
|
3138
3587
|
if (data.success !== false) {
|
|
3139
|
-
|
|
3588
|
+
ctrlState.allowLocationChange = true;
|
|
3589
|
+
if (typeof $scope.dataEventFunctions.onAfterCreate === "function") {
|
|
3140
3590
|
$scope.dataEventFunctions.onAfterCreate(data);
|
|
3141
3591
|
}
|
|
3142
3592
|
if (options.redirect) {
|
|
3143
3593
|
$window.location = options.redirect;
|
|
3144
3594
|
}
|
|
3145
3595
|
else {
|
|
3146
|
-
routingService.redirectTo()(
|
|
3596
|
+
routingService.redirectTo()("edit", $scope, $location, data._id);
|
|
3147
3597
|
}
|
|
3148
3598
|
}
|
|
3149
3599
|
else {
|
|
@@ -3161,9 +3611,9 @@ var fng;
|
|
|
3161
3611
|
.then(function (response) {
|
|
3162
3612
|
var data = response.data;
|
|
3163
3613
|
var listInstructions = [];
|
|
3164
|
-
handleSchema(
|
|
3614
|
+
handleSchema("Lookup " + lookupCollection, data, null, listInstructions, "", false, $scope, ctrlState);
|
|
3165
3615
|
var dataRequest;
|
|
3166
|
-
if (typeof schemaElement.filter !==
|
|
3616
|
+
if (typeof schemaElement.filter !== "undefined" && schemaElement.filter) {
|
|
3167
3617
|
dataRequest = SubmissionsService.getPagedAndFilteredList(lookupCollection, schemaElement.filter);
|
|
3168
3618
|
}
|
|
3169
3619
|
else {
|
|
@@ -3171,25 +3621,30 @@ var fng;
|
|
|
3171
3621
|
}
|
|
3172
3622
|
dataRequest
|
|
3173
3623
|
.then(function (response) {
|
|
3174
|
-
var data = response.data;
|
|
3624
|
+
var data = angular.copy(response.data);
|
|
3175
3625
|
if (data) {
|
|
3176
3626
|
for (var i = 0; i < data.length; i++) {
|
|
3177
|
-
var option =
|
|
3627
|
+
var option = "";
|
|
3178
3628
|
for (var j = 0; j < listInstructions.length; j++) {
|
|
3179
3629
|
var thisVal = data[i][listInstructions[j].name];
|
|
3180
|
-
option += thisVal ? thisVal +
|
|
3630
|
+
option += thisVal ? thisVal + " " : "";
|
|
3181
3631
|
}
|
|
3182
3632
|
option = option.trim();
|
|
3183
3633
|
var pos = _.sortedIndex(optionsList, option);
|
|
3184
3634
|
// handle dupes (ideally people will use unique indexes to stop them but...)
|
|
3185
3635
|
if (optionsList[pos] === option) {
|
|
3186
|
-
option = option +
|
|
3636
|
+
option = option + " (" + data[i]._id + ")";
|
|
3187
3637
|
pos = _.sortedIndex(optionsList, option);
|
|
3188
3638
|
}
|
|
3189
3639
|
optionsList.splice(pos, 0, option);
|
|
3190
3640
|
idList.splice(pos, 0, data[i]._id);
|
|
3191
3641
|
}
|
|
3192
|
-
|
|
3642
|
+
if ($scope.readingRecord) {
|
|
3643
|
+
$scope.readingRecord
|
|
3644
|
+
.then(function () {
|
|
3645
|
+
updateRecordWithLookupValues(schemaElement, $scope, ctrlState);
|
|
3646
|
+
});
|
|
3647
|
+
}
|
|
3193
3648
|
}
|
|
3194
3649
|
});
|
|
3195
3650
|
});
|
|
@@ -3197,31 +3652,9 @@ var fng;
|
|
|
3197
3652
|
setUpLookupListOptions: function setUpLookupListOptions(ref, formInstructions, $scope, ctrlState) {
|
|
3198
3653
|
var optionsList = $scope[formInstructions.options] = [];
|
|
3199
3654
|
var idList = $scope[formInstructions.ids] = [];
|
|
3200
|
-
if (ref.id[0] ===
|
|
3201
|
-
// id of document
|
|
3202
|
-
|
|
3203
|
-
var nameElements = formInstructions.name.split('.');
|
|
3204
|
-
var refHandler = $scope.listLookups.find(function (lkp) {
|
|
3205
|
-
return lkp.ref.property === ref.property && lkp.ref.value === ref.value;
|
|
3206
|
-
});
|
|
3207
|
-
var thisHandler = {
|
|
3208
|
-
formInstructions: formInstructions,
|
|
3209
|
-
lastPart: nameElements.pop(),
|
|
3210
|
-
possibleArray: nameElements.join('.')
|
|
3211
|
-
};
|
|
3212
|
-
if (!refHandler) {
|
|
3213
|
-
refHandler = {
|
|
3214
|
-
ref: ref,
|
|
3215
|
-
lookupOptions: [],
|
|
3216
|
-
lookupIds: [],
|
|
3217
|
-
handlers: []
|
|
3218
|
-
};
|
|
3219
|
-
$scope.listLookups.push(refHandler);
|
|
3220
|
-
}
|
|
3221
|
-
refHandler.handlers.push(thisHandler);
|
|
3222
|
-
$scope[formInstructions.options] = refHandler.lookupOptions;
|
|
3223
|
-
$scope[formInstructions.ids] = refHandler.lookupIds;
|
|
3224
|
-
// TODO DRY this and handleInternalLookup below
|
|
3655
|
+
if (ref.id[0] === "$") {
|
|
3656
|
+
// id of document that contains out lookup list comes from record, so we need to deal with in $watch by adding it to listLookups
|
|
3657
|
+
addArrayLookupToLookupList($scope, formInstructions, ref, $scope.listLookups);
|
|
3225
3658
|
}
|
|
3226
3659
|
else {
|
|
3227
3660
|
// we can do it now
|
|
@@ -3232,7 +3665,7 @@ var fng;
|
|
|
3232
3665
|
var pos = _.sortedIndex(optionsList, option);
|
|
3233
3666
|
// handle dupes
|
|
3234
3667
|
if (optionsList[pos] === option) {
|
|
3235
|
-
option = option +
|
|
3668
|
+
option = option + " (" + data[i]._id + ")";
|
|
3236
3669
|
pos = _.sortedIndex(optionsList, option);
|
|
3237
3670
|
}
|
|
3238
3671
|
optionsList.splice(pos, 0, option);
|
|
@@ -3243,27 +3676,7 @@ var fng;
|
|
|
3243
3676
|
}
|
|
3244
3677
|
},
|
|
3245
3678
|
handleInternalLookup: function handleInternalLookup($scope, formInstructions, ref) {
|
|
3246
|
-
|
|
3247
|
-
var refHandler = $scope.internalLookups.find(function (lkp) {
|
|
3248
|
-
return lkp.ref.property === ref.property && lkp.ref.value === ref.value;
|
|
3249
|
-
});
|
|
3250
|
-
var thisHandler = {
|
|
3251
|
-
formInstructions: formInstructions,
|
|
3252
|
-
lastPart: nameElements.pop(),
|
|
3253
|
-
possibleArray: nameElements.join('.')
|
|
3254
|
-
};
|
|
3255
|
-
if (!refHandler) {
|
|
3256
|
-
refHandler = {
|
|
3257
|
-
ref: ref,
|
|
3258
|
-
lookupOptions: [],
|
|
3259
|
-
lookupIds: [],
|
|
3260
|
-
handlers: []
|
|
3261
|
-
};
|
|
3262
|
-
$scope.internalLookups.push(refHandler);
|
|
3263
|
-
}
|
|
3264
|
-
refHandler.handlers.push(thisHandler);
|
|
3265
|
-
$scope[formInstructions.options] = refHandler.lookupOptions;
|
|
3266
|
-
$scope[formInstructions.ids] = refHandler.lookupIds;
|
|
3679
|
+
addArrayLookupToLookupList($scope, formInstructions, ref, $scope.internalLookups);
|
|
3267
3680
|
},
|
|
3268
3681
|
preservePristine: preservePristine,
|
|
3269
3682
|
// Reverse the process of convertToAngularModel
|
|
@@ -3280,48 +3693,54 @@ var fng;
|
|
|
3280
3693
|
}
|
|
3281
3694
|
return retVal;
|
|
3282
3695
|
}
|
|
3283
|
-
|
|
3284
|
-
var
|
|
3285
|
-
var
|
|
3286
|
-
|
|
3696
|
+
var _loop_1 = function () {
|
|
3697
|
+
var schemaI = schema[i];
|
|
3698
|
+
var fieldname = schemaI.name.slice(prefixLength);
|
|
3699
|
+
var thisField = getListData(anObject, fieldname, null, $scope);
|
|
3700
|
+
if (schemaI.schema) {
|
|
3287
3701
|
if (thisField) {
|
|
3288
3702
|
for (var j = 0; j < thisField.length; j++) {
|
|
3289
|
-
thisField[j] = convertToMongoModel(
|
|
3703
|
+
thisField[j] = convertToMongoModel(schemaI.schema, thisField[j], 1 + fieldname.length, $scope, fieldname);
|
|
3290
3704
|
}
|
|
3291
3705
|
}
|
|
3292
3706
|
}
|
|
3293
3707
|
else {
|
|
3294
3708
|
// Convert {array:[{x:'item 1'}]} to {array:['item 1']}
|
|
3295
|
-
if (
|
|
3709
|
+
if (schemaI.array && simpleArrayNeedsX(schemaI) && thisField) {
|
|
3296
3710
|
for (var k = 0; k < thisField.length; k++) {
|
|
3297
3711
|
thisField[k] = thisField[k].x;
|
|
3298
3712
|
}
|
|
3299
3713
|
}
|
|
3300
3714
|
// Convert {lookup:'List description for 012abcde'} to {lookup:'012abcde'}
|
|
3301
|
-
var
|
|
3302
|
-
|
|
3303
|
-
if (idList && idList.length > 0) {
|
|
3715
|
+
var idList_1 = $scope[suffixCleanId(schemaI, "_ids")];
|
|
3716
|
+
if (idList_1 && idList_1.length > 0) {
|
|
3304
3717
|
updateObject(fieldname, anObject, function (value) {
|
|
3305
|
-
return convertToForeignKeys(
|
|
3718
|
+
return convertToForeignKeys(schemaI, value, $scope[suffixCleanId(schemaI, "Options")], idList_1);
|
|
3306
3719
|
});
|
|
3307
3720
|
}
|
|
3308
|
-
else
|
|
3309
|
-
var
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
newVal =
|
|
3313
|
-
if (
|
|
3314
|
-
|
|
3315
|
-
|
|
3721
|
+
else {
|
|
3722
|
+
var thisConversion = getConversionObject($scope, fieldname, schemaName);
|
|
3723
|
+
if (thisConversion) {
|
|
3724
|
+
var lookup = getData(anObject, fieldname, null);
|
|
3725
|
+
var newVal = void 0;
|
|
3726
|
+
if (schemaI.array) {
|
|
3727
|
+
newVal = [];
|
|
3728
|
+
if (lookup) {
|
|
3729
|
+
for (var n = 0; n < lookup.length; n++) {
|
|
3730
|
+
newVal[n] = convertLookup(lookup[n], thisConversion);
|
|
3731
|
+
}
|
|
3316
3732
|
}
|
|
3317
3733
|
}
|
|
3734
|
+
else {
|
|
3735
|
+
newVal = convertLookup(lookup, thisConversion);
|
|
3736
|
+
}
|
|
3737
|
+
setData(anObject, fieldname, null, newVal);
|
|
3318
3738
|
}
|
|
3319
|
-
else {
|
|
3320
|
-
newVal = convertLookup(lookup, thisConversion);
|
|
3321
|
-
}
|
|
3322
|
-
setData(anObject, fieldname, null, newVal);
|
|
3323
3739
|
}
|
|
3324
3740
|
}
|
|
3741
|
+
};
|
|
3742
|
+
for (var i = 0; i < schema.length; i++) {
|
|
3743
|
+
_loop_1();
|
|
3325
3744
|
}
|
|
3326
3745
|
return anObject;
|
|
3327
3746
|
},
|
|
@@ -3331,7 +3750,7 @@ var fng;
|
|
|
3331
3750
|
$scope.handleHttpError = handleError($scope);
|
|
3332
3751
|
$scope.cancel = function () {
|
|
3333
3752
|
angular.copy(ctrlState.master, $scope.record);
|
|
3334
|
-
$scope.$broadcast(
|
|
3753
|
+
$scope.$broadcast("fngCancel", $scope);
|
|
3335
3754
|
// Let call backs etc resolve in case they dirty form, then clean it
|
|
3336
3755
|
$timeout($scope.setPristine);
|
|
3337
3756
|
};
|
|
@@ -3340,15 +3759,21 @@ var fng;
|
|
|
3340
3759
|
// scope.$emit('showErrorMessage', {title: 'Your error Title', body: 'The body of the error message'});
|
|
3341
3760
|
// or
|
|
3342
3761
|
// scope.$broadcast('showErrorMessage', {title: 'Your error Title', body: 'The body of the error message'});
|
|
3343
|
-
$scope.$on(
|
|
3344
|
-
|
|
3762
|
+
$scope.$on("showErrorMessage", function (event, args) {
|
|
3763
|
+
if (!event.defaultPrevented) {
|
|
3764
|
+
event.defaultPrevented = true;
|
|
3765
|
+
$scope.showError(args.body, args.title);
|
|
3766
|
+
}
|
|
3345
3767
|
});
|
|
3346
3768
|
$scope.showError = function (error, alertTitle) {
|
|
3347
|
-
$scope.alertTitle = alertTitle ? alertTitle :
|
|
3348
|
-
if (typeof error ===
|
|
3769
|
+
$scope.alertTitle = alertTitle ? alertTitle : "Error!";
|
|
3770
|
+
if (typeof error === "string") {
|
|
3349
3771
|
$scope.errorMessage = error;
|
|
3350
3772
|
}
|
|
3351
|
-
else if (error
|
|
3773
|
+
else if (!error) {
|
|
3774
|
+
$scope.errorMessage = "An error occurred - that's all we got. Sorry.";
|
|
3775
|
+
}
|
|
3776
|
+
else if (error.message && typeof error.message === "string") {
|
|
3352
3777
|
$scope.errorMessage = error.message;
|
|
3353
3778
|
}
|
|
3354
3779
|
else if (error.data && error.data.message) {
|
|
@@ -3362,16 +3787,35 @@ var fng;
|
|
|
3362
3787
|
$scope.errorMessage = error;
|
|
3363
3788
|
}
|
|
3364
3789
|
}
|
|
3790
|
+
$scope.errorHideTimer = window.setTimeout(function () {
|
|
3791
|
+
$scope.dismissError();
|
|
3792
|
+
$scope.$digest();
|
|
3793
|
+
}, 3500 + (1000 * ($scope.alertTitle + $scope.errorMessage).length / 50));
|
|
3794
|
+
$scope.errorVisible = true;
|
|
3795
|
+
window.setTimeout(function () {
|
|
3796
|
+
$scope.$digest();
|
|
3797
|
+
});
|
|
3798
|
+
};
|
|
3799
|
+
$scope.clearTimeout = function () {
|
|
3800
|
+
if ($scope.errorHideTimer) {
|
|
3801
|
+
clearTimeout($scope.errorHideTimer);
|
|
3802
|
+
delete $scope.errorHideTimer;
|
|
3803
|
+
}
|
|
3365
3804
|
};
|
|
3366
3805
|
$scope.dismissError = function () {
|
|
3806
|
+
$scope.clearTimeout;
|
|
3807
|
+
$scope.errorVisible = false;
|
|
3367
3808
|
delete $scope.errorMessage;
|
|
3368
3809
|
delete $scope.alertTitle;
|
|
3369
3810
|
};
|
|
3811
|
+
$scope.stickError = function () {
|
|
3812
|
+
clearTimeout($scope.errorHideTimer);
|
|
3813
|
+
};
|
|
3370
3814
|
$scope.prepareForSave = function (cb) {
|
|
3371
3815
|
//Convert the lookup values into ids
|
|
3372
3816
|
var dataToSave = recordHandlerInstance.convertToMongoModel($scope.formSchema, angular.copy($scope.record), 0, $scope);
|
|
3373
3817
|
if ($scope.id) {
|
|
3374
|
-
if (typeof $scope.dataEventFunctions.onBeforeUpdate ===
|
|
3818
|
+
if (typeof $scope.dataEventFunctions.onBeforeUpdate === "function") {
|
|
3375
3819
|
$scope.dataEventFunctions.onBeforeUpdate(dataToSave, ctrlState.master, function (err) {
|
|
3376
3820
|
if (err) {
|
|
3377
3821
|
cb(err);
|
|
@@ -3386,7 +3830,7 @@ var fng;
|
|
|
3386
3830
|
}
|
|
3387
3831
|
}
|
|
3388
3832
|
else {
|
|
3389
|
-
if (typeof $scope.dataEventFunctions.onBeforeCreate ===
|
|
3833
|
+
if (typeof $scope.dataEventFunctions.onBeforeCreate === "function") {
|
|
3390
3834
|
$scope.dataEventFunctions.onBeforeCreate(dataToSave, function (err) {
|
|
3391
3835
|
if (err) {
|
|
3392
3836
|
cb(err);
|
|
@@ -3405,22 +3849,24 @@ var fng;
|
|
|
3405
3849
|
options = options || {};
|
|
3406
3850
|
$scope.prepareForSave(function (err, dataToSave) {
|
|
3407
3851
|
if (err) {
|
|
3408
|
-
if (err !==
|
|
3409
|
-
$
|
|
3852
|
+
if (err !== "_update_handled_") {
|
|
3853
|
+
$timeout(function () {
|
|
3854
|
+
$scope.showError(err);
|
|
3855
|
+
});
|
|
3410
3856
|
}
|
|
3411
3857
|
}
|
|
3412
3858
|
else if ($scope.id) {
|
|
3413
3859
|
recordHandlerInstance.updateDocument(dataToSave, options, $scope, ctrlState);
|
|
3414
3860
|
}
|
|
3415
3861
|
else {
|
|
3416
|
-
recordHandlerInstance.createNew(dataToSave, options, $scope);
|
|
3862
|
+
recordHandlerInstance.createNew(dataToSave, options, $scope, ctrlState);
|
|
3417
3863
|
}
|
|
3418
3864
|
});
|
|
3419
3865
|
};
|
|
3420
3866
|
$scope.newClick = function () {
|
|
3421
|
-
routingService.redirectTo()(
|
|
3867
|
+
routingService.redirectTo()("new", $scope, $location);
|
|
3422
3868
|
};
|
|
3423
|
-
$scope.$on(
|
|
3869
|
+
$scope.$on("$locationChangeStart", function (event, next) {
|
|
3424
3870
|
// let changed = !$scope.isCancelDisabled();
|
|
3425
3871
|
// let curPath = window.location.href.split('/');
|
|
3426
3872
|
// let nextPath = next.split('/');
|
|
@@ -3439,21 +3885,12 @@ var fng;
|
|
|
3439
3885
|
if (!ctrlState.allowLocationChange && !$scope.isCancelDisabled()) {
|
|
3440
3886
|
event.preventDefault();
|
|
3441
3887
|
var modalInstance = $uibModal.open({
|
|
3442
|
-
template:
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
'<div class="modal-body">' +
|
|
3446
|
-
' <p>Would you like to save your changes?</p>' +
|
|
3447
|
-
'</div>' +
|
|
3448
|
-
'<div class="modal-footer">' +
|
|
3449
|
-
' <button class="btn btn-primary dlg-yes" ng-click="yes()">Yes</button>' +
|
|
3450
|
-
' <button class="btn btn-warning dlg-no" ng-click="no()">No</button>' +
|
|
3451
|
-
' <button class="btn dlg-cancel" ng-click="cancel()">Cancel</button>' +
|
|
3452
|
-
'</div>',
|
|
3453
|
-
controller: 'SaveChangesModalCtrl',
|
|
3454
|
-
backdrop: 'static'
|
|
3888
|
+
template: "<div class=\"modal-header\">\n <h3>Record modified</h3>\n</div>\n<div class=\"modal-body\">\n <p>Would you like to save your changes?</p>\n</div>\n<div class=\"modal-footer\">\n <button class=\"btn btn-primary dlg-yes\" ng-click=\"yes()\">Yes</button>\n <button class=\"btn btn-warning dlg-no\" ng-click=\"no()\">No</button>\n <button class=\"btn dlg-cancel\" ng-click=\"cancel()\">Cancel</button>\n</div>",
|
|
3889
|
+
controller: "SaveChangesModalCtrl",
|
|
3890
|
+
backdrop: "static"
|
|
3455
3891
|
});
|
|
3456
|
-
modalInstance.result
|
|
3892
|
+
modalInstance.result
|
|
3893
|
+
.then(function (result) {
|
|
3457
3894
|
if (result) {
|
|
3458
3895
|
$scope.save({ redirect: next, allowChange: true }); // save changes
|
|
3459
3896
|
}
|
|
@@ -3461,7 +3898,8 @@ var fng;
|
|
|
3461
3898
|
ctrlState.allowLocationChange = true;
|
|
3462
3899
|
$window.location = next;
|
|
3463
3900
|
}
|
|
3464
|
-
})
|
|
3901
|
+
})
|
|
3902
|
+
.catch(_handleCancel);
|
|
3465
3903
|
}
|
|
3466
3904
|
});
|
|
3467
3905
|
$scope.deleteClick = function () {
|
|
@@ -3472,85 +3910,176 @@ var fng;
|
|
|
3472
3910
|
}
|
|
3473
3911
|
else {
|
|
3474
3912
|
var modalInstance = $uibModal.open({
|
|
3475
|
-
template:
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
'<div class="modal-body">' +
|
|
3479
|
-
' <p>Are you sure you want to delete this record?</p>' +
|
|
3480
|
-
'</div>' +
|
|
3481
|
-
'<div class="modal-footer">' +
|
|
3482
|
-
' <button class="btn btn-primary dlg-no" ng-click="cancel()">No</button>' +
|
|
3483
|
-
' <button class="btn btn-warning dlg-yes" ng-click="yes()">Yes</button>' +
|
|
3484
|
-
'</div>',
|
|
3485
|
-
controller: 'SaveChangesModalCtrl',
|
|
3486
|
-
backdrop: 'static'
|
|
3913
|
+
template: "<div class=\"modal-header\">\n <h3>Delete Item</h3>\n</div>\n<div class=\"modal-body\">\n <p>Are you sure you want to delete this record?</p>\n</div>\n<div class=\"modal-footer\">\n <button class=\"btn btn-primary dlg-no\" ng-click=\"cancel()\">No</button>\n <button class=\"btn btn-warning dlg-yes\" ng-click=\"yes()\">Yes</button>\n</div>",
|
|
3914
|
+
controller: "SaveChangesModalCtrl",
|
|
3915
|
+
backdrop: "static"
|
|
3487
3916
|
});
|
|
3488
3917
|
confirmDelete = modalInstance.result;
|
|
3489
3918
|
}
|
|
3490
3919
|
confirmDelete.then(function (result) {
|
|
3920
|
+
function doTheDeletion() {
|
|
3921
|
+
recordHandlerInstance.deleteRecord($scope.id, $scope, ctrlState);
|
|
3922
|
+
}
|
|
3491
3923
|
if (result) {
|
|
3492
|
-
if (typeof $scope.dataEventFunctions.onBeforeDelete ===
|
|
3924
|
+
if (typeof $scope.dataEventFunctions.onBeforeDelete === "function") {
|
|
3493
3925
|
$scope.dataEventFunctions.onBeforeDelete(ctrlState.master, function (err) {
|
|
3494
3926
|
if (err) {
|
|
3495
|
-
if (err !==
|
|
3927
|
+
if (err !== "_delete_handled_") {
|
|
3496
3928
|
$scope.showError(err);
|
|
3497
3929
|
}
|
|
3498
3930
|
}
|
|
3499
3931
|
else {
|
|
3500
|
-
|
|
3932
|
+
doTheDeletion();
|
|
3501
3933
|
}
|
|
3502
3934
|
});
|
|
3503
3935
|
}
|
|
3504
3936
|
else {
|
|
3505
|
-
|
|
3937
|
+
doTheDeletion();
|
|
3506
3938
|
}
|
|
3507
3939
|
}
|
|
3508
|
-
})
|
|
3940
|
+
})
|
|
3941
|
+
.catch(_handleCancel);
|
|
3509
3942
|
}
|
|
3510
3943
|
};
|
|
3511
3944
|
$scope.isCancelDisabled = function () {
|
|
3512
|
-
if (
|
|
3945
|
+
if ($scope[$scope.topLevelFormName] && $scope[$scope.topLevelFormName].$pristine) {
|
|
3946
|
+
return true;
|
|
3947
|
+
}
|
|
3948
|
+
else if (typeof $scope.disableFunctions.isCancelDisabled === "function") {
|
|
3513
3949
|
return $scope.disableFunctions.isCancelDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
|
|
3514
3950
|
}
|
|
3515
3951
|
else {
|
|
3516
|
-
return
|
|
3952
|
+
return false;
|
|
3517
3953
|
}
|
|
3518
3954
|
};
|
|
3519
3955
|
$scope.isSaveDisabled = function () {
|
|
3520
|
-
|
|
3521
|
-
|
|
3956
|
+
$scope.whyDisabled = undefined;
|
|
3957
|
+
var pristine = false;
|
|
3958
|
+
function generateWhyDisabledMessage(form, subFormName) {
|
|
3959
|
+
form.$$controls.forEach(function (c) {
|
|
3960
|
+
if (c.$invalid) {
|
|
3961
|
+
if (c.$$controls) {
|
|
3962
|
+
// nested form
|
|
3963
|
+
generateWhyDisabledMessage(c, c.$name);
|
|
3964
|
+
}
|
|
3965
|
+
else {
|
|
3966
|
+
$scope.whyDisabled += "<br /><strong>";
|
|
3967
|
+
if (subFormName) {
|
|
3968
|
+
$scope.whyDisabled += subFormName + ' ';
|
|
3969
|
+
}
|
|
3970
|
+
if (cssFrameworkService.framework() === "bs2" &&
|
|
3971
|
+
c.$$element &&
|
|
3972
|
+
c.$$element.parent() &&
|
|
3973
|
+
c.$$element.parent().parent() &&
|
|
3974
|
+
c.$$element.parent().parent().find("label") &&
|
|
3975
|
+
c.$$element.parent().parent().find("label").text()) {
|
|
3976
|
+
$scope.whyDisabled += c.$$element.parent().parent().find("label").text();
|
|
3977
|
+
}
|
|
3978
|
+
else if (cssFrameworkService.framework() === "bs3" &&
|
|
3979
|
+
c.$$element &&
|
|
3980
|
+
c.$$element.parent() &&
|
|
3981
|
+
c.$$element.parent().parent() &&
|
|
3982
|
+
c.$$element.parent().parent().parent() &&
|
|
3983
|
+
c.$$element.parent().parent().parent().find("label") &&
|
|
3984
|
+
c.$$element.parent().parent().parent().find("label").text()) {
|
|
3985
|
+
$scope.whyDisabled += c.$$element.parent().parent().parent().find("label").text();
|
|
3986
|
+
}
|
|
3987
|
+
else {
|
|
3988
|
+
$scope.whyDisabled += c.$name;
|
|
3989
|
+
}
|
|
3990
|
+
$scope.whyDisabled += "</strong>: ";
|
|
3991
|
+
if (c.$error) {
|
|
3992
|
+
for (var type in c.$error) {
|
|
3993
|
+
if (c.$error.hasOwnProperty(type)) {
|
|
3994
|
+
switch (type) {
|
|
3995
|
+
case "required":
|
|
3996
|
+
$scope.whyDisabled += "Field missing required value. ";
|
|
3997
|
+
break;
|
|
3998
|
+
case "pattern":
|
|
3999
|
+
$scope.whyDisabled += "Field does not match required pattern. ";
|
|
4000
|
+
break;
|
|
4001
|
+
default:
|
|
4002
|
+
$scope.whyDisabled += type + ". ";
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
});
|
|
4010
|
+
}
|
|
4011
|
+
if ($scope[$scope.topLevelFormName]) {
|
|
4012
|
+
if ($scope[$scope.topLevelFormName].$invalid) {
|
|
4013
|
+
$scope.whyDisabled = 'The form data is invalid:';
|
|
4014
|
+
generateWhyDisabledMessage($scope[$scope.topLevelFormName]);
|
|
4015
|
+
}
|
|
4016
|
+
else if ($scope[$scope.topLevelFormName].$pristine) {
|
|
4017
|
+
// Don't have disabled message - should be obvious from Cancel being disabled,
|
|
4018
|
+
// and the message comes up when the Save button is clicked.
|
|
4019
|
+
pristine = true;
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
else {
|
|
4023
|
+
$scope.whyDisabled = "Top level form name invalid";
|
|
4024
|
+
}
|
|
4025
|
+
if (pristine || !!$scope.whyDisabled) {
|
|
4026
|
+
return true;
|
|
4027
|
+
}
|
|
4028
|
+
else if (typeof $scope.disableFunctions.isSaveDisabled !== "function") {
|
|
4029
|
+
return false;
|
|
3522
4030
|
}
|
|
3523
4031
|
else {
|
|
3524
|
-
|
|
4032
|
+
var retVal = $scope.disableFunctions.isSaveDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
|
|
4033
|
+
if (typeof retVal === "string") {
|
|
4034
|
+
$scope.whyDisabled = retVal;
|
|
4035
|
+
}
|
|
4036
|
+
else {
|
|
4037
|
+
$scope.whyDisabled = "An application level user-specified function is inhibiting saving the record";
|
|
4038
|
+
}
|
|
4039
|
+
return !!retVal;
|
|
3525
4040
|
}
|
|
3526
4041
|
};
|
|
3527
4042
|
$scope.isDeleteDisabled = function () {
|
|
3528
|
-
if (
|
|
4043
|
+
if (!$scope.id) {
|
|
4044
|
+
return true;
|
|
4045
|
+
}
|
|
4046
|
+
else if (typeof $scope.disableFunctions.isDeleteDisabled === "function") {
|
|
3529
4047
|
return $scope.disableFunctions.isDeleteDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
|
|
3530
4048
|
}
|
|
3531
4049
|
else {
|
|
3532
|
-
return
|
|
4050
|
+
return false;
|
|
3533
4051
|
}
|
|
3534
4052
|
};
|
|
3535
4053
|
$scope.isNewDisabled = function () {
|
|
3536
|
-
if (typeof $scope.disableFunctions.isNewDisabled ===
|
|
4054
|
+
if (typeof $scope.disableFunctions.isNewDisabled === "function") {
|
|
3537
4055
|
return $scope.disableFunctions.isNewDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
|
|
3538
4056
|
}
|
|
3539
4057
|
else {
|
|
3540
4058
|
return false;
|
|
3541
4059
|
}
|
|
3542
4060
|
};
|
|
3543
|
-
$scope.
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
4061
|
+
$scope.setDefaults = function (formSchema, base) {
|
|
4062
|
+
if (base === void 0) { base = ''; }
|
|
4063
|
+
var retVal = {};
|
|
4064
|
+
formSchema.forEach(function (s) {
|
|
4065
|
+
if (s.defaultValue !== undefined) {
|
|
4066
|
+
var nameParts = s.name.replace(base, '').split(".");
|
|
4067
|
+
var target = retVal;
|
|
4068
|
+
for (var i = 0; i < nameParts.length - 1; i++) {
|
|
4069
|
+
if (!target[nameParts[i]]) {
|
|
4070
|
+
target[nameParts[i]] = {};
|
|
4071
|
+
}
|
|
4072
|
+
target = target[nameParts[i]];
|
|
4073
|
+
}
|
|
4074
|
+
target[nameParts[nameParts.length - 1]] = s.defaultValue;
|
|
4075
|
+
}
|
|
4076
|
+
});
|
|
4077
|
+
return retVal;
|
|
3549
4078
|
};
|
|
3550
4079
|
$scope.getVal = function (expression, index) {
|
|
3551
|
-
if (expression.indexOf(
|
|
4080
|
+
if (expression.indexOf("$index") === -1 || typeof index !== "undefined") {
|
|
3552
4081
|
expression = expression.replace(/\$index/g, index);
|
|
3553
|
-
return $scope.$eval(
|
|
4082
|
+
return $scope.$eval("record." + expression);
|
|
3554
4083
|
}
|
|
3555
4084
|
//else {
|
|
3556
4085
|
// Used to show error here, but angular seems to call before record is populated sometimes
|
|
@@ -3564,6 +4093,23 @@ var fng;
|
|
|
3564
4093
|
}
|
|
3565
4094
|
}
|
|
3566
4095
|
};
|
|
4096
|
+
$scope.setUpCustomLookupOptions = function (schemaElement, ids, options, baseScope) {
|
|
4097
|
+
for (var _i = 0, _a = [$scope, baseScope]; _i < _a.length; _i++) {
|
|
4098
|
+
var scope = _a[_i];
|
|
4099
|
+
if (scope) {
|
|
4100
|
+
// need to be accessible on our scope for generation of the select options, and - for nested schemas -
|
|
4101
|
+
// on baseScope for the conversion back to ids done by prepareForSave
|
|
4102
|
+
scope[schemaElement.ids] = ids;
|
|
4103
|
+
scope[schemaElement.options] = options;
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
var data = getData($scope.record, schemaElement.name);
|
|
4107
|
+
if (!data) {
|
|
4108
|
+
return;
|
|
4109
|
+
}
|
|
4110
|
+
data = convertForeignKeys(schemaElement, data, options, ids);
|
|
4111
|
+
setData($scope.record, schemaElement.name, undefined, data);
|
|
4112
|
+
};
|
|
3567
4113
|
},
|
|
3568
4114
|
fillFormFromBackendCustomSchema: fillFormFromBackendCustomSchema,
|
|
3569
4115
|
fillFormWithBackendSchema: function fillFormWithBackendSchema($scope, formGeneratorInstance, recordHandlerInstance, ctrlState) {
|
|
@@ -3596,13 +4142,45 @@ var fng;
|
|
|
3596
4142
|
})(services = fng.services || (fng.services = {}));
|
|
3597
4143
|
})(fng || (fng = {}));
|
|
3598
4144
|
/// <reference path="../../../../node_modules/@types/angular/index.d.ts" />
|
|
4145
|
+
var ExpirationCache = /** @class */ (function () {
|
|
4146
|
+
function ExpirationCache(timeout) {
|
|
4147
|
+
if (timeout === void 0) { timeout = 60 * 1000; }
|
|
4148
|
+
this.store = new Map();
|
|
4149
|
+
this.timeout = timeout;
|
|
4150
|
+
}
|
|
4151
|
+
ExpirationCache.prototype.get = function (key) {
|
|
4152
|
+
// this.store.has(key) ? console.log(`cache hit`) : console.log(`cache miss`);
|
|
4153
|
+
return this.store.get(key);
|
|
4154
|
+
};
|
|
4155
|
+
ExpirationCache.prototype.put = function (key, val) {
|
|
4156
|
+
var _this = this;
|
|
4157
|
+
this.store.set(key, val);
|
|
4158
|
+
// remove it once it's expired
|
|
4159
|
+
setTimeout(function () {
|
|
4160
|
+
// console.log(`removing expired key ${key}`);
|
|
4161
|
+
_this.remove(key);
|
|
4162
|
+
}, this.timeout);
|
|
4163
|
+
};
|
|
4164
|
+
ExpirationCache.prototype.remove = function (key) {
|
|
4165
|
+
this.store.delete(key);
|
|
4166
|
+
};
|
|
4167
|
+
ExpirationCache.prototype.removeAll = function () {
|
|
4168
|
+
this.store = new Map();
|
|
4169
|
+
};
|
|
4170
|
+
ExpirationCache.prototype.delete = function () {
|
|
4171
|
+
//no op here because this is standalone, not a part of $cacheFactory
|
|
4172
|
+
};
|
|
4173
|
+
return ExpirationCache;
|
|
4174
|
+
}());
|
|
3599
4175
|
var fng;
|
|
3600
4176
|
(function (fng) {
|
|
3601
4177
|
var services;
|
|
3602
4178
|
(function (services) {
|
|
3603
4179
|
/*@ngInject*/
|
|
3604
|
-
SubmissionsService.$inject = ["$http"
|
|
3605
|
-
function SubmissionsService($http
|
|
4180
|
+
SubmissionsService.$inject = ["$http"];
|
|
4181
|
+
function SubmissionsService($http) {
|
|
4182
|
+
var useCacheForGetAll = true;
|
|
4183
|
+
var expCache = new ExpirationCache();
|
|
3606
4184
|
/*
|
|
3607
4185
|
generate a query string for a filtered and paginated query for submissions.
|
|
3608
4186
|
options consists of the following:
|
|
@@ -3660,11 +4238,11 @@ var fng;
|
|
|
3660
4238
|
// };
|
|
3661
4239
|
// },
|
|
3662
4240
|
getListAttributes: function (ref, id) {
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
4241
|
+
var actualId = typeof id === "string" ? id : id.id || id._id || id.x || id;
|
|
4242
|
+
if (typeof actualId !== "string") {
|
|
4243
|
+
throw new Error("getListAttributes requires a string id but was provided with ".concat(JSON.stringify(id)));
|
|
3666
4244
|
}
|
|
3667
|
-
return $http.get('/api/' + ref
|
|
4245
|
+
return $http.get('/api/' + ref + '/' + actualId + '/list', { cache: expCache });
|
|
3668
4246
|
},
|
|
3669
4247
|
readRecord: function (modelName, id) {
|
|
3670
4248
|
// TODO Figure out tab history updates (check for other tab-history-todos)
|
|
@@ -3680,7 +4258,7 @@ var fng;
|
|
|
3680
4258
|
},
|
|
3681
4259
|
getAll: function (modelName, _options) {
|
|
3682
4260
|
var options = angular.extend({
|
|
3683
|
-
cache:
|
|
4261
|
+
cache: useCacheForGetAll ? expCache : false
|
|
3684
4262
|
}, _options);
|
|
3685
4263
|
return $http.get('/api/' + modelName, options);
|
|
3686
4264
|
},
|
|
@@ -3691,12 +4269,21 @@ var fng;
|
|
|
3691
4269
|
return $http.delete('/api/' + model + '/' + id);
|
|
3692
4270
|
},
|
|
3693
4271
|
updateRecord: function (modelName, id, dataToSave) {
|
|
3694
|
-
|
|
4272
|
+
expCache.remove('/api/' + modelName);
|
|
3695
4273
|
return $http.post('/api/' + modelName + '/' + id, dataToSave);
|
|
3696
4274
|
},
|
|
3697
4275
|
createRecord: function (modelName, dataToSave) {
|
|
3698
|
-
|
|
4276
|
+
expCache.remove('/api/' + modelName);
|
|
3699
4277
|
return $http.post('/api/' + modelName, dataToSave);
|
|
4278
|
+
},
|
|
4279
|
+
useCache: function (val) {
|
|
4280
|
+
useCacheForGetAll = val;
|
|
4281
|
+
},
|
|
4282
|
+
getCache: function () {
|
|
4283
|
+
return !!expCache;
|
|
4284
|
+
},
|
|
4285
|
+
clearCache: function () {
|
|
4286
|
+
expCache.removeAll();
|
|
3700
4287
|
}
|
|
3701
4288
|
};
|
|
3702
4289
|
}
|
|
@@ -3722,6 +4309,7 @@ var fng;
|
|
|
3722
4309
|
fngInvalidRequired: 'fng-invalid-required',
|
|
3723
4310
|
allowLocationChange: true // Set when the data arrives..
|
|
3724
4311
|
};
|
|
4312
|
+
$scope.errorVisible = false;
|
|
3725
4313
|
angular.extend($scope, routingService.parsePathFunc()($location.$$path));
|
|
3726
4314
|
// Load context menu. For /person/client/:id/edit we need
|
|
3727
4315
|
// to load PersonCtrl and PersonClientCtrl
|
|
@@ -3736,17 +4324,33 @@ var fng;
|
|
|
3736
4324
|
$rootScope.$broadcast('fngFormLoadStart', $scope);
|
|
3737
4325
|
formGenerator.decorateScope($scope, formGenerator, recordHandler, $scope.sharedData);
|
|
3738
4326
|
recordHandler.decorateScope($scope, $uibModal, recordHandler, ctrlState);
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
$scope.sharedData.modelControllers[i].onBaseCtrlReady
|
|
4327
|
+
function processTheForm() {
|
|
4328
|
+
recordHandler.fillFormWithBackendSchema($scope, formGenerator, recordHandler, ctrlState);
|
|
4329
|
+
// Tell the 'model controllers' that they can start fiddling with baseScope
|
|
4330
|
+
for (var i = 0; i < $scope.sharedData.modelControllers.length; i++) {
|
|
4331
|
+
if ($scope.sharedData.modelControllers[i].onBaseCtrlReady) {
|
|
4332
|
+
$scope.sharedData.modelControllers[i].onBaseCtrlReady($scope);
|
|
4333
|
+
}
|
|
3744
4334
|
}
|
|
4335
|
+
$scope.$on('$destroy', function () {
|
|
4336
|
+
$scope.sharedData.modelControllers.forEach(function (value) { return value.$destroy(); });
|
|
4337
|
+
$rootScope.$broadcast('fngControllersUnloaded');
|
|
4338
|
+
});
|
|
4339
|
+
}
|
|
4340
|
+
//Check that we are ready
|
|
4341
|
+
if (typeof fng.formsAngular.beforeProcess === "function") {
|
|
4342
|
+
fng.formsAngular.beforeProcess($scope, function (err) {
|
|
4343
|
+
if (err) {
|
|
4344
|
+
$scope.showError(err.message, 'Error preparing to process form');
|
|
4345
|
+
}
|
|
4346
|
+
else {
|
|
4347
|
+
processTheForm();
|
|
4348
|
+
}
|
|
4349
|
+
});
|
|
4350
|
+
}
|
|
4351
|
+
else {
|
|
4352
|
+
processTheForm();
|
|
3745
4353
|
}
|
|
3746
|
-
$scope.$on('$destroy', function () {
|
|
3747
|
-
$scope.sharedData.modelControllers.forEach(function (value) { return value.$destroy(); });
|
|
3748
|
-
$rootScope.$broadcast('fngControllersUnloaded');
|
|
3749
|
-
});
|
|
3750
4354
|
}
|
|
3751
4355
|
controllers.BaseCtrl = BaseCtrl;
|
|
3752
4356
|
})(controllers = fng.controllers || (fng.controllers = {}));
|
|
@@ -3802,13 +4406,17 @@ var fng;
|
|
|
3802
4406
|
var controllers;
|
|
3803
4407
|
(function (controllers) {
|
|
3804
4408
|
/*@ngInject*/
|
|
3805
|
-
NavCtrl.$inject = ["$scope", "$location", "$filter", "routingService", "cssFrameworkService"];
|
|
3806
|
-
function NavCtrl($scope, $location, $filter, routingService, cssFrameworkService) {
|
|
4409
|
+
NavCtrl.$inject = ["$rootScope", "$window", "$scope", "$location", "$filter", "routingService", "cssFrameworkService"];
|
|
4410
|
+
function NavCtrl($rootScope, $window, $scope, $location, $filter, routingService, cssFrameworkService) {
|
|
3807
4411
|
function clearContextMenu() {
|
|
3808
4412
|
$scope.items = [];
|
|
3809
4413
|
$scope.contextMenu = undefined;
|
|
3810
4414
|
}
|
|
4415
|
+
$rootScope.navScope = $scope; // Lets plugins access menus
|
|
3811
4416
|
clearContextMenu();
|
|
4417
|
+
$scope.toggleCollapsed = function () {
|
|
4418
|
+
$scope.collapsed = !$scope.collapsed;
|
|
4419
|
+
};
|
|
3812
4420
|
/* isCollapsed and showShortcuts are used to control how the menu is displayed in a responsive environment and whether the shortcut keystrokes help should be displayed */
|
|
3813
4421
|
$scope.isCollapsed = true;
|
|
3814
4422
|
$scope.showShortcuts = false;
|
|
@@ -3836,8 +4444,8 @@ var fng;
|
|
|
3836
4444
|
}
|
|
3837
4445
|
}
|
|
3838
4446
|
function filter(event) {
|
|
3839
|
-
var tagName = (event.target
|
|
3840
|
-
return !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
|
|
4447
|
+
var tagName = (event.target).tagName;
|
|
4448
|
+
return !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA' || tagName == "DIV" && event.target.classList.contains('ck-editor__editable'));
|
|
3841
4449
|
}
|
|
3842
4450
|
//console.log(event.keyCode, event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
|
|
3843
4451
|
if (event.keyCode === 191 && (filter(event) || (event.ctrlKey && !event.altKey && !event.metaKey))) {
|
|
@@ -3866,7 +4474,7 @@ var fng;
|
|
|
3866
4474
|
else if (event.keyCode === 45 && event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey) {
|
|
3867
4475
|
deferredBtnClick('newButton'); // Ctrl+Shift+Ins creates New record
|
|
3868
4476
|
}
|
|
3869
|
-
else if (event.keyCode === 88 && event.ctrlKey && event.shiftKey && event.altKey && !event.metaKey) {
|
|
4477
|
+
else if (event.keyCode === 88 && event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey) {
|
|
3870
4478
|
deferredBtnClick('deleteButton'); // Ctrl+Shift+X deletes record
|
|
3871
4479
|
}
|
|
3872
4480
|
};
|
|
@@ -3882,6 +4490,11 @@ var fng;
|
|
|
3882
4490
|
};
|
|
3883
4491
|
$scope.$on('fngControllersLoaded', function (evt, sharedData, modelName) {
|
|
3884
4492
|
$scope.contextMenu = sharedData.dropDownDisplay || sharedData.modelNameDisplay || $filter('titleCase')(modelName, false);
|
|
4493
|
+
if (sharedData.dropDownDisplayPromise) {
|
|
4494
|
+
sharedData.dropDownDisplayPromise.then(function (value) {
|
|
4495
|
+
$scope.contextMenu = value;
|
|
4496
|
+
});
|
|
4497
|
+
}
|
|
3885
4498
|
});
|
|
3886
4499
|
$scope.$on('fngControllersUnloaded', function (evt) {
|
|
3887
4500
|
clearContextMenu();
|
|
@@ -3897,28 +4510,59 @@ var fng;
|
|
|
3897
4510
|
}
|
|
3898
4511
|
else {
|
|
3899
4512
|
// Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
|
|
3900
|
-
var args = item.args || []
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
4513
|
+
var args = item.args || [];
|
|
4514
|
+
var fn = item.fn;
|
|
4515
|
+
if (typeof fn === "function") {
|
|
4516
|
+
switch (args.length) {
|
|
4517
|
+
case 0:
|
|
4518
|
+
fn();
|
|
4519
|
+
break;
|
|
4520
|
+
case 1:
|
|
4521
|
+
fn(args[0]);
|
|
4522
|
+
break;
|
|
4523
|
+
case 2:
|
|
4524
|
+
fn(args[0], args[1]);
|
|
4525
|
+
break;
|
|
4526
|
+
case 3:
|
|
4527
|
+
fn(args[0], args[1], args[2]);
|
|
4528
|
+
break;
|
|
4529
|
+
case 4:
|
|
4530
|
+
fn(args[0], args[1], args[2], args[3]);
|
|
4531
|
+
break;
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
else if (fn) {
|
|
4535
|
+
throw new Error("Incorrect menu setup");
|
|
3917
4536
|
}
|
|
3918
4537
|
}
|
|
3919
4538
|
};
|
|
3920
4539
|
$scope.isHidden = function (index) {
|
|
3921
|
-
|
|
4540
|
+
function explicitlyHidden(item) {
|
|
4541
|
+
return item.isHidden ? item.isHidden() : false;
|
|
4542
|
+
}
|
|
4543
|
+
var dividerHide = false;
|
|
4544
|
+
// Hide a divider if it appears under another
|
|
4545
|
+
if ($scope.items[index].divider) {
|
|
4546
|
+
if (index === 0) {
|
|
4547
|
+
dividerHide = true;
|
|
4548
|
+
}
|
|
4549
|
+
else {
|
|
4550
|
+
var foundVisible = false;
|
|
4551
|
+
var check = index - 1;
|
|
4552
|
+
while (check >= 0 && !dividerHide && !foundVisible) {
|
|
4553
|
+
if ($scope.items[check].divider) {
|
|
4554
|
+
dividerHide = true;
|
|
4555
|
+
}
|
|
4556
|
+
else if (!explicitlyHidden($scope.items[check])) {
|
|
4557
|
+
foundVisible = true;
|
|
4558
|
+
}
|
|
4559
|
+
else {
|
|
4560
|
+
--check;
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4565
|
+
return dividerHide || explicitlyHidden($scope.items[index]);
|
|
3922
4566
|
};
|
|
3923
4567
|
$scope.isDisabled = function (index) {
|
|
3924
4568
|
return $scope.items[index].isDisabled ? $scope.items[index].isDisabled() : false;
|
|
@@ -3937,6 +4581,10 @@ var fng;
|
|
|
3937
4581
|
}
|
|
3938
4582
|
return thisClass;
|
|
3939
4583
|
};
|
|
4584
|
+
var originalTitle = $window.document.title;
|
|
4585
|
+
$scope.$on('$routeChangeSuccess', function () {
|
|
4586
|
+
$window.document.title = originalTitle;
|
|
4587
|
+
});
|
|
3940
4588
|
}
|
|
3941
4589
|
controllers.NavCtrl = NavCtrl;
|
|
3942
4590
|
})(controllers = fng.controllers || (fng.controllers = {}));
|
|
@@ -3977,6 +4625,7 @@ var fng;
|
|
|
3977
4625
|
])
|
|
3978
4626
|
.controller('BaseCtrl', fng.controllers.BaseCtrl)
|
|
3979
4627
|
.controller('SaveChangesModalCtrl', fng.controllers.SaveChangesModalCtrl)
|
|
4628
|
+
.controller('LinkCtrl', fng.controllers.LinkCtrl)
|
|
3980
4629
|
.controller('ModelCtrl', fng.controllers.ModelCtrl)
|
|
3981
4630
|
.controller('NavCtrl', fng.controllers.NavCtrl)
|
|
3982
4631
|
.directive('modelControllerDropdown', fng.directives.modelControllerDropdown)
|
|
@@ -3988,6 +4637,7 @@ var fng;
|
|
|
3988
4637
|
.directive('fngNakedDate', fng.directives.fngNakedDate)
|
|
3989
4638
|
.filter('camelCase', fng.filters.camelCase)
|
|
3990
4639
|
.filter('titleCase', fng.filters.titleCase)
|
|
4640
|
+
.filter('extractTimestampFromMongoID', fng.filters.extractTimestampFromMongoID)
|
|
3991
4641
|
.service('addAllService', fng.services.addAllService)
|
|
3992
4642
|
.provider('cssFrameworkService', fng.services.cssFrameworkService)
|
|
3993
4643
|
.provider('routingService', fng.services.routingService)
|
|
@@ -4003,11 +4653,15 @@ var fng;
|
|
|
4003
4653
|
// expose the library
|
|
4004
4654
|
var formsAngular = fng.formsAngular;
|
|
4005
4655
|
|
|
4006
|
-
angular.module('formsAngular').run(['$templateCache', function($templateCache) {$templateCache.put('base-analysis.html','<div ng-controller="AnalysisCtrl">\n <div class="container-fluid page-header report-header">\n <div ng-class="css(\'rowFluid\')">\n <div class="header-lhs col-xs-7 span7">\n <h1>{{
|
|
4007
|
-
$templateCache.put('base-edit.html','<div ng-controller="BaseCtrl">\n <div ng-class="css(\'rowFluid\')" class="page-header edit-header">\n <div class="header-lhs col-sm-8 span8">\n <
|
|
4008
|
-
$templateCache.put('base-list.html','<div ng-controller="BaseCtrl">\n <div ng-class="css(\'rowFluid\')" class="page-header list-header">\n <div class="header-lhs col-sm-8 span8">\n <h1>{{modelNameDisplay}}</h1>\n </div>\n
|
|
4656
|
+
angular.module('formsAngular').run(['$templateCache', function($templateCache) {$templateCache.put('base-analysis.html','<div ng-controller="AnalysisCtrl">\n <error-display></error-display>\n <div class="container-fluid page-header report-header">\n <div ng-class="css(\'rowFluid\')">\n <div class="header-lhs col-xs-7 span7">\n <h1>{{ titleWithSubstitutions }}</h1>\n </div>\n <div class="header-rhs col-xs-5 span5">\n <form-input schema="paramSchema" name="paramForm" ng-show="paramSchema" formstyle="horizontalCompact"></form-input>\n </div>\n </div>\n </div>\n <div class="container-fluid page-body report-body">\n <div class="row-fluid report-grow">\n <div class="gridStyle" style="height:100%;" ui-grid="gridOptions" ui-grid-selection ui-grid-resize-columns></div>\n </div>\n </div>\n</div>\n');
|
|
4657
|
+
$templateCache.put('base-edit.html','<div ng-controller="BaseCtrl">\n <error-display></error-display>\n <div ng-class="css(\'rowFluid\')" class="page-header edit-header">\n <div class="header-lhs col-sm-8 span8">\n <h1 id="header-text">{{modelNameDisplay}} :\n <span id="header-data-desc">\n <span ng-show="!!editFormHeader" >{{ editFormHeader() }}</span>\n <span ng-hide="!!editFormHeader" ng-repeat="field in listSchema" ng-bind-html="getListData(record, field.name) + \' \'"></span>\n </span>\n </h1>\n </div>\n <div class="header-rhs col-sm-2 span2">\n <div form-buttons></div>\n </div>\n </div>\n <div class="container-fluid page-body edit-body">\n <form-input name="baseForm" schema="baseSchema()" formstyle="compact"></form-input>\n </div>\n<!-- <pre>-->\n <!--Record-->\n <!--{{ record | json }}-->\n <!--formSchema-->\n <!--{{ formSchema | json }}-->\n<!-- </pre>-->\n</div>\n');
|
|
4658
|
+
$templateCache.put('base-list-view.html','<div ng-controller="BaseCtrl">\n <error-display></error-display>\n <div ng-class="css(\'rowFluid\')" class="page-header list-header">\n <div class="header-lhs col-sm-8 span8">\n <h1>{{modelNameDisplay}}</h1>\n </div>\n </div>\n <div class="page-body list-body">\n <div ng-class="css(\'rowFluid\')" infinite-scroll="scrollTheList()">\n <a ng-repeat="record in recordList" ng-href="{{generateViewUrl(record)}}">\n <div class="list-item">\n <div ng-class="css(\'span\',12/listSchema.length)" ng-repeat="field in listSchema">{{getListData(record, field.name)}} </div>\n </div>\n </a>\n </div>\n </div>\n</div>\n');
|
|
4659
|
+
$templateCache.put('base-list.html','<div ng-controller="BaseCtrl">\n <error-display></error-display>\n <div ng-class="css(\'rowFluid\')" class="page-header list-header">\n <div class="header-lhs col-sm-8 span8">\n <h1>{{modelNameDisplay}}</h1>\n </div>\n <div class="header-rhs col-sm-2 span2">\n <a ng-href="{{generateNewUrl()}}"><button id="newBtn" class="btn btn-default"><i class="icon-plus"></i> New</button></a>\n </div>\n </div>\n <div class="page-body list-body">\n <div ng-class="css(\'rowFluid\')" infinite-scroll="scrollTheList()">\n <a ng-repeat="record in recordList" ng-href="{{generateEditUrl(record)}}">\n <div class="list-item">\n <div ng-class="css(\'span\',12/listSchema.length)" ng-repeat="field in listSchema">{{getListData(record, field.name)}} </div>\n </div>\n </a>\n </div>\n </div>\n</div>\n');
|
|
4660
|
+
$templateCache.put('base-view.html','<div ng-controller="BaseCtrl">\n <error-display></error-display>\n <div ng-class="css(\'rowFluid\')" class="page-header edit-header">\n <div class="header-lhs col-sm-8 span8">\n <h1 id="header-text">{{modelNameDisplay}} :\n <span ng-repeat="field in listSchema" ng-bind-html="getListData(record, field.name) + \' \'"></span>\n </h1>\n </div>\n </div>\n <div class="container-fluid page-body edit-body">\n <form-input name="baseForm" schema="baseSchema()" formstyle="compact" viewform="true"></form-input>\n </div>\n</div>\n');
|
|
4661
|
+
$templateCache.put('error-display-bs2.html','<div id="display-error" ng-show="errorVisible" class="row-fluid ng-hide">\n <div class="alert alert-error offset1 span10">\n <button type="button" id="err-hide" class="close" ng-click="dismissError()"><i class="icon-remove"></i></button>\n <button type="button" id="err-pin" class="close" ng-click="stickError()"><i class="icon-eye-open"></i></button>\n <h4 id="err-title">{{alertTitle}}</h4>\n <div id="err-msg" ng-bind-html="errorMessage"></div>\n </div>\n</div>\n');
|
|
4662
|
+
$templateCache.put('error-display-bs3.html','<div id="display-error" ng-show="errorVisible" class="row ng-hide">\n <div class="alert alert-error col-md-offset-1 col-md-10 alert-danger">\n <button type="button" id="err-hide" class="close" ng-click="dismissError()"><i class="glyphicon glyphicon-remove"></i></button>\n <button type="button" id="err-pin" class="close" ng-click="stickError()"><i class="glyphicon glyphicon-pushpin"></i></button>\n <h4 id="err-title">{{alertTitle}}</h4>\n <div id="err-msg" ng-bind-html="errorMessage"></div>\n </div>\n</div>\n');
|
|
4009
4663
|
$templateCache.put('error-messages.html','<div ng-message="required">A value is required for this field</div>\n<div ng-message="minlength">Too few characters entered</div>\n<div ng-message="maxlength">Too many characters entered</div>\n<div ng-message="min">That value is too small</div>\n<div ng-message="max">That value is too large</div>\n<div ng-message="email">You need to enter a valid email address</div>\n<div ng-message="pattern">This field does not match the expected pattern</div>\n');
|
|
4010
|
-
$templateCache.put('form-button-bs2.html','<div class="form-btn-grp">\n <div class="btn-group pull-right">\n <button id="saveButton" class="btn btn-mini btn-primary form-btn" ng-click="save()" ng-disabled="isSaveDisabled()"><i class="icon-ok"></i> Save</button>\n <button id="cancelButton" class="btn btn-mini btn-warning form-btn" ng-click="cancel()" ng-disabled="isCancelDisabled()"><i class="icon-remove"></i> Cancel</button>\n </div>\n <div class="btn-group pull-right">\n <button id="newButton" class="btn btn-mini btn-success form-btn" ng-click="newClick()" ng-disabled="isNewDisabled()"><i class="icon-plus"></i> New</button>\n <button id="deleteButton" class="btn btn-mini btn-danger form-btn" ng-click="deleteClick()" ng-disabled="isDeleteDisabled()"><i class="icon-minus"></i> Delete</button>\n </div>\n</div>\n');
|
|
4011
|
-
$templateCache.put('form-button-bs3.html','<div class="form-btn-grp">\n <div class="btn-group pull-right">\n <button id="saveButton" class="btn btn-primary form-btn btn-xs" ng-click="save()" ng-disabled="isSaveDisabled()"><i class="glyphicon glyphicon-ok"></i> Save</button>\n <button id="cancelButton" class="btn btn-warning form-btn btn-xs" ng-click="cancel()" ng-disabled="isCancelDisabled()"><i class="glyphicon glyphicon-remove"></i> Cancel</button>\n </div>\n <div class="btn-group pull-right">\n <button id="newButton" class="btn btn-success form-btn btn-xs" ng-click="newClick()" ng-disabled="isNewDisabled()"><i class="glyphicon glyphicon-plus"></i> New</button>\n <button id="deleteButton" class="btn btn-danger form-btn btn-xs" ng-click="deleteClick()" ng-disabled="isDeleteDisabled()"><i class="glyphicon glyphicon-minus"></i> Delete</button>\n </div>\n</div>\n');
|
|
4012
|
-
$templateCache.put('search-bs2.html','<form class="navbar-search pull-right">\n <div id="search-cg" class="control-group" ng-class="errorClass">\n <input type="text" autocomplete="off" id="searchinput" ng-model="searchTarget" ng-model-options="{debounce:250}" class="search-query" placeholder="{{searchPlaceholder}}" ng-keyup="handleKey($event)">\n </div>\n</form>\n<div class="results-container" ng-show="results.length >= 1">\n <div class="search-results">\n <div ng-repeat="result in results">\n <
|
|
4013
|
-
$templateCache.put('search-bs3.html','<form class="pull-right navbar-form">\n <div id="search-cg" class="form-group" ng-class="errorClass">\n <input type="text" autocomplete="off" id="searchinput" ng-model="searchTarget" ng-model-options="{debounce:250}" class="search-query form-control" placeholder="{{searchPlaceholder}}" ng-keyup="handleKey($event)">\n </div>\n</form>\n<div class="results-container" ng-show="results.length >= 1">\n <div class="search-results">\n <div ng-repeat="result in results">\n <
|
|
4664
|
+
$templateCache.put('form-button-bs2.html','<div class="form-btn-grp">\n <div class="btn-group pull-right">\n <button id="saveButton" class="btn btn-mini btn-primary form-btn" ng-click="save()" ng-disabled="isSaveDisabled()"><i class="icon-ok"></i> Save</button>\n <div id="why-disabled" ng-class="{showwhy:!!whyDisabled}" ng-bind-html="whyDisabled"></div>\n <button id="cancelButton" class="btn btn-mini btn-warning form-btn" ng-click="cancel()" ng-disabled="isCancelDisabled()"><i class="icon-remove"></i> Cancel</button>\n </div>\n <div class="btn-group pull-right">\n <button id="newButton" class="btn btn-mini btn-success form-btn" ng-click="newClick()" ng-disabled="isNewDisabled()"><i class="icon-plus"></i> New</button>\n <button id="deleteButton" class="btn btn-mini btn-danger form-btn" ng-click="deleteClick()" ng-disabled="isDeleteDisabled()"><i class="icon-minus"></i> Delete</button>\n </div>\n</div>\n');
|
|
4665
|
+
$templateCache.put('form-button-bs3.html','<div class="form-btn-grp">\n <div class="btn-group pull-right">\n <button id="saveButton" class="btn btn-primary form-btn btn-xs" ng-click="save()" ng-disabled="isSaveDisabled()"><i class="glyphicon glyphicon-ok"></i> Save</button>\n <div id="why-disabled" ng-class="{showwhy:!!whyDisabled}" ng-bind-html="whyDisabled"></div>\n <button id="cancelButton" class="btn btn-warning form-btn btn-xs" ng-click="cancel()" ng-disabled="isCancelDisabled()"><i class="glyphicon glyphicon-remove"></i> Cancel</button>\n </div>\n <div class="btn-group pull-right">\n <button id="newButton" class="btn btn-success form-btn btn-xs" ng-click="newClick()" ng-disabled="isNewDisabled()"><i class="glyphicon glyphicon-plus"></i> New</button>\n <button id="deleteButton" class="btn btn-danger form-btn btn-xs" ng-click="deleteClick()" ng-disabled="isDeleteDisabled()"><i class="glyphicon glyphicon-minus"></i> Delete</button>\n </div>\n</div>\n');
|
|
4666
|
+
$templateCache.put('search-bs2.html','<form class="navbar-search pull-right">\n <div id="search-cg" class="control-group" ng-class="errorClass">\n <input type="text" spellcheck="false" autocomplete="off" id="searchinput" ng-model="searchTarget" ng-model-options="{debounce:250}" class="search-query" placeholder="{{searchPlaceholder}}" ng-keyup="handleKey($event)">\n </div>\n</form>\n<div class="results-container" ng-show="results.length >= 1">\n <div class="search-results">\n <div ng-repeat="result in results">\n <a href="{{result.href}}" ng-class="resultClass($index)" title="{{result.additional}}">{{result.resourceText}} {{result.text}}</a>\n </div>\n <div ng-show="moreCount > 0">(plus more - continue typing to narrow down search...)\n </div>\n </div>\n</div>\n');
|
|
4667
|
+
$templateCache.put('search-bs3.html','<form class="pull-right navbar-form">\n <div id="search-cg" class="form-group" ng-class="errorClass">\n <input type="text" spellcheck="false" autocomplete="off" id="searchinput" ng-model="searchTarget" ng-model-options="{debounce:250}" class="search-query form-control" placeholder="{{searchPlaceholder}}" ng-keyup="handleKey($event)">\n </div>\n</form>\n<div class="results-container" ng-show="results.length >= 1">\n <div class="search-results">\n <div ng-repeat="result in results">\n <a href="{{result.href}}" ng-class="resultClass($index)" title="{{result.additional}}">{{result.resourceText}} {{result.text}}</a>\n </div>\n <div ng-show="moreCount > 0">(plus more - continue typing to narrow down search...)\n </div>\n </div>\n</div>\n');}]);
|