forms-angular 0.12.0-beta.191 → 0.12.0-beta.193
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.js +444 -182
- package/dist/client/forms-angular.min.js +1 -1
- package/dist/client/index.d.ts +211 -102
- package/dist/server/data_form.js +2 -4
- package/package.json +1 -1
|
@@ -5,21 +5,52 @@ var fng;
|
|
|
5
5
|
(function (directives) {
|
|
6
6
|
/*@ngInject*/
|
|
7
7
|
function modelControllerDropdown() {
|
|
8
|
+
var menuVisibilityStr;
|
|
9
|
+
var menuDisabledStr;
|
|
10
|
+
var itemVisibilityStr = "isHidden($index)";
|
|
11
|
+
var itemClassStr = "ng-class=\"dropdownClass($index)\"";
|
|
12
|
+
if (fng.formsAngular.elemSecurityFuncBinding) {
|
|
13
|
+
// without a more fundamental re-write, we cannot support "instant" binding here, so we'll fall-back to using
|
|
14
|
+
// the next-best alternative, which is one-time binding
|
|
15
|
+
var oneTimeBinding = fng.formsAngular.elemSecurityFuncBinding !== "normal";
|
|
16
|
+
var bindingStr = oneTimeBinding ? "::" : "";
|
|
17
|
+
// as ng-class is already being used, we'll add the .disabled class if the menu item is securely disabled using
|
|
18
|
+
// class="{{ }}". note that we "prevent" a disabled menu item from being clicked by checking for the DISABLED
|
|
19
|
+
// attribute in the doClick(...) function, and aborting if this is found.
|
|
20
|
+
// note that the 'normal' class introduced here might not actually do anything, but for one-time binding to work
|
|
21
|
+
// properly, we need a truthy value
|
|
22
|
+
itemClassStr += " class=\"{{ ".concat(bindingStr, "isSecurelyDisabled(choice.id) ? 'disabled' : 'normal' }}\"");
|
|
23
|
+
if (oneTimeBinding) {
|
|
24
|
+
// because the isHidden(...) logic is highly likely to be model dependent, that cannot be one-time bound. to
|
|
25
|
+
// be able to combine one-time and regular binding, we'll use ng-if for the one-time bound stuff and ng-hide for the rest
|
|
26
|
+
itemVisibilityStr = "ng-if=\"::!isSecurelyHidden(choice.id)\" ng-hide=\"".concat(itemVisibilityStr, "\"");
|
|
27
|
+
}
|
|
28
|
+
else if (fng.formsAngular.elemSecurityFuncBinding === "normal") {
|
|
29
|
+
itemVisibilityStr = "ng-hide=\"isSecurelyHidden(choice.id) || ".concat(itemVisibilityStr, "\"");
|
|
30
|
+
}
|
|
31
|
+
menuVisibilityStr = "ng-if=\"!contextMenuHidden\"";
|
|
32
|
+
menuDisabledStr = "disableable-link ng-disabled=\"contextMenuDisabled\"";
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
menuVisibilityStr = "";
|
|
36
|
+
menuDisabledStr = "";
|
|
37
|
+
itemVisibilityStr = "ng-hide=\"".concat(itemVisibilityStr, "\"");
|
|
38
|
+
}
|
|
8
39
|
return {
|
|
9
|
-
restrict:
|
|
40
|
+
restrict: "AE",
|
|
10
41
|
replace: true,
|
|
11
|
-
template:
|
|
42
|
+
template: "<li id=\"{{ contextMenuId }}\" ng-show=\"items.length > 0\" class=\"mcdd\" uib-dropdown ".concat(menuVisibilityStr, " ").concat(menuDisabledStr, ">") +
|
|
12
43
|
' <a href="#" uib-dropdown-toggle>' +
|
|
13
44
|
' {{contextMenu}} <b class="caret"></b>' +
|
|
14
|
-
|
|
45
|
+
" </a>" +
|
|
15
46
|
' <ul class="uib-dropdown-menu dropdown-menu">' +
|
|
16
|
-
|
|
47
|
+
" <li ng-repeat=\"choice in items\" ng-attr-id=\"{{choice.id}}\" ".concat(itemVisibilityStr, " ").concat(itemClassStr, ">") +
|
|
17
48
|
' <a ng-show="choice.text || choice.textFunc" class="dropdown-option" ng-href="{{choice.url || choice.urlFunc()}}" ng-click="doClick($index, $event)">' +
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
49
|
+
" {{ choice.text || choice.textFunc() }}" +
|
|
50
|
+
" </a>" +
|
|
51
|
+
" </li>" +
|
|
52
|
+
" </ul>" +
|
|
53
|
+
"</li>",
|
|
23
54
|
};
|
|
24
55
|
}
|
|
25
56
|
directives.modelControllerDropdown = modelControllerDropdown;
|
|
@@ -288,7 +319,7 @@ var fng;
|
|
|
288
319
|
// <input type="text" class="input-small" placeholder="Email">
|
|
289
320
|
var subkeys = [];
|
|
290
321
|
var tabsSetup = tabsSetupState.N;
|
|
291
|
-
var generateInput = function (fieldInfo, modelString, isRequired,
|
|
322
|
+
var generateInput = function (fieldInfo, modelString, isRequired, options) {
|
|
292
323
|
function generateEnumInstructions() {
|
|
293
324
|
var enumInstruction;
|
|
294
325
|
if (angular.isArray(scope[fieldInfo.options])) {
|
|
@@ -314,6 +345,10 @@ var fng;
|
|
|
314
345
|
}
|
|
315
346
|
return enumInstruction;
|
|
316
347
|
}
|
|
348
|
+
var idString = fieldInfo.id;
|
|
349
|
+
if (fieldInfo.array || options.subschema) {
|
|
350
|
+
idString = formMarkupHelper.generateArrayElementIdString(idString, fieldInfo, options);
|
|
351
|
+
}
|
|
317
352
|
var nameString;
|
|
318
353
|
if (!modelString) {
|
|
319
354
|
var modelBase = (options.model || 'record') + '.';
|
|
@@ -335,7 +370,6 @@ var fng;
|
|
|
335
370
|
}
|
|
336
371
|
else {
|
|
337
372
|
modelString += '[$index].' + lastPart;
|
|
338
|
-
idString = null;
|
|
339
373
|
nameString = compoundName.replace(/\./g, '-');
|
|
340
374
|
}
|
|
341
375
|
}
|
|
@@ -350,28 +384,13 @@ var fng;
|
|
|
350
384
|
isRequired = isRequired || fieldInfo.required;
|
|
351
385
|
var requiredStr = isRequired ? ' required ' : '';
|
|
352
386
|
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
|
-
}
|
|
368
387
|
switch (fieldInfo.type) {
|
|
369
388
|
case 'select':
|
|
370
389
|
if (fieldInfo.select2) {
|
|
371
390
|
value = '<input placeholder="fng-select2 has been removed" readonly>';
|
|
372
391
|
}
|
|
373
392
|
else {
|
|
374
|
-
common += handleReadOnlyDisabled(fieldInfo
|
|
393
|
+
common += formMarkupHelper.handleReadOnlyDisabled(fieldInfo);
|
|
375
394
|
common += fieldInfo.add ? (' ' + fieldInfo.add + ' ') : '';
|
|
376
395
|
common += " aria-label=\"".concat(fieldInfo.label && fieldInfo.label !== "" ? fieldInfo.label : fieldInfo.name, "\" ");
|
|
377
396
|
value = '<select ' + common + 'class="' + allInputsVars.formControl.trim() + allInputsVars.compactClass + allInputsVars.sizeClassBS2 + '" ' + requiredStr + '>';
|
|
@@ -425,7 +444,7 @@ var fng;
|
|
|
425
444
|
case 'radio':
|
|
426
445
|
value = '';
|
|
427
446
|
common += requiredStr;
|
|
428
|
-
common += handleReadOnlyDisabled(fieldInfo
|
|
447
|
+
common += formMarkupHelper.handleReadOnlyDisabled(fieldInfo);
|
|
429
448
|
common += fieldInfo.add ? (' ' + fieldInfo.add + ' ') : '';
|
|
430
449
|
var separateLines = options.formstyle === 'vertical' || (options.formstyle !== 'inline' && !fieldInfo.inlineRadio);
|
|
431
450
|
if (angular.isArray(fieldInfo.options)) {
|
|
@@ -456,7 +475,7 @@ var fng;
|
|
|
456
475
|
break;
|
|
457
476
|
case 'checkbox':
|
|
458
477
|
common += requiredStr;
|
|
459
|
-
common += handleReadOnlyDisabled(fieldInfo
|
|
478
|
+
common += formMarkupHelper.handleReadOnlyDisabled(fieldInfo);
|
|
460
479
|
common += fieldInfo.add ? (' ' + fieldInfo.add + ' ') : '';
|
|
461
480
|
value = formMarkupHelper.generateSimpleInput(common, fieldInfo, options);
|
|
462
481
|
if (cssFrameworkService.framework() === 'bs3') {
|
|
@@ -465,6 +484,7 @@ var fng;
|
|
|
465
484
|
break;
|
|
466
485
|
default:
|
|
467
486
|
common += formMarkupHelper.addTextInputMarkup(allInputsVars, fieldInfo, requiredStr);
|
|
487
|
+
common += formMarkupHelper.handleReadOnlyDisabled(fieldInfo);
|
|
468
488
|
if (fieldInfo.type === 'textarea') {
|
|
469
489
|
if (fieldInfo.rows) {
|
|
470
490
|
if (fieldInfo.rows === 'auto') {
|
|
@@ -629,6 +649,9 @@ var fng;
|
|
|
629
649
|
};
|
|
630
650
|
var handleField = function (info, options) {
|
|
631
651
|
var fieldChrome = formMarkupHelper.fieldChrome(scope, info, options);
|
|
652
|
+
if (fieldChrome.omit) {
|
|
653
|
+
return "";
|
|
654
|
+
}
|
|
632
655
|
var template = fieldChrome.template;
|
|
633
656
|
if (info.schema) {
|
|
634
657
|
var niceName = info.name.replace(/\./g, '_');
|
|
@@ -685,12 +708,24 @@ var fng;
|
|
|
685
708
|
if (info.formStyle === "inline" && info.inlineHeaders) {
|
|
686
709
|
template += generateInlineHeaders(info.schema, options, model, info.inlineHeaders === "always");
|
|
687
710
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
711
|
+
var disableCond = formMarkupHelper.handleReadOnlyDisabled(info);
|
|
712
|
+
// if we already know that the field is disabled (only possible when formsAngular.elemSecurityFuncBinding === "instant")
|
|
713
|
+
// then we don't need to add the sortable attribute at all
|
|
714
|
+
// otherwise, we need to include the ng-disabled on the <ol> so this can be referenced by the ui-sortable directive
|
|
715
|
+
// (see sortableOptions)
|
|
716
|
+
var sortableStr = info.sortable && disableCond.trim().toLowerCase() !== "disabled"
|
|
717
|
+
? "".concat(disableCond, " ui-sortable=\"sortableOptions\" ng-model=\"").concat(model, "\"")
|
|
718
|
+
: "";
|
|
719
|
+
template += "<ol class=\"sub-doc\" ".concat(sortableStr, ">");
|
|
720
|
+
template +=
|
|
721
|
+
"<li ng-form id=\"".concat(info.id, "List_{{$index}}\" name=\"form_").concat(niceName, "{{$index}}\" ") +
|
|
722
|
+
" class=\"".concat(convertFormStyleToClass(info.formStyle)) +
|
|
723
|
+
" ".concat(cssFrameworkService.framework() === 'bs2' ? 'row-fluid' : '') +
|
|
724
|
+
" ".concat(info.inlineHeaders ? 'width-controlled' : '') +
|
|
725
|
+
" ".concat(info.ngClass ? "ng-class:" + info.ngClass : '', "\"") +
|
|
726
|
+
" ng-repeat=\"subDoc in ".concat(model, " track by $index\"") +
|
|
727
|
+
" ".concat(info.filterable ? 'data-ng-hide="subDoc._hidden"' : '') +
|
|
728
|
+
">";
|
|
694
729
|
if (cssFrameworkService.framework() === 'bs2') {
|
|
695
730
|
template += '<div class="row-fluid sub-doc">';
|
|
696
731
|
}
|
|
@@ -700,7 +735,7 @@ var fng;
|
|
|
700
735
|
template += info.customSubDoc;
|
|
701
736
|
}
|
|
702
737
|
if (info.noRemove !== true) {
|
|
703
|
-
template += "<button ".concat(info.noRemove ? 'ng-hide="' + info.noRemove + '"' : '', " name=\"remove_").concat(info.id, "_btn\" ng-click=\"remove('").concat(info.name, "', $index, $event)\"");
|
|
738
|
+
template += "<button ".concat(disableCond, " ").concat(info.noRemove ? 'ng-hide="' + info.noRemove + '"' : '', " name=\"remove_").concat(info.id, "_btn\" ng-click=\"remove('").concat(info.name, "', $index, $event)\"");
|
|
704
739
|
if (info.remove) {
|
|
705
740
|
template += ' class="remove-btn btn btn-mini btn-default btn-xs form-btn"><i class="' + formMarkupHelper.glyphClass() + '-minus"></i> Remove';
|
|
706
741
|
}
|
|
@@ -755,7 +790,11 @@ var fng;
|
|
|
755
790
|
else {
|
|
756
791
|
hideCond = info.noAdd ? "ng-hide=\"".concat(info.noAdd, "\"") : '';
|
|
757
792
|
indicatorShowCond = info.noAdd ? "ng-show=\"".concat(info.noAdd, " && ").concat(indicatorShowCond, "\"") : '';
|
|
758
|
-
|
|
793
|
+
var disableCond_1 = formMarkupHelper.handleReadOnlyDisabled(info);
|
|
794
|
+
footer +=
|
|
795
|
+
"<button ".concat(hideCond, " ").concat(disableCond_1, " id=\"add_").concat(info.id, "_btn\" class=\"add-btn btn btn-default btn-xs btn-mini\" ng-click=\"add('").concat(info.name, "',$event)\">") +
|
|
796
|
+
" <i class=\"".concat(formMarkupHelper.glyphClass(), "-plus\"></i> Add ") +
|
|
797
|
+
"</button>";
|
|
759
798
|
}
|
|
760
799
|
if (info.noneIndicator) {
|
|
761
800
|
footer += "<span ".concat(indicatorShowCond, " class=\"none_indicator\" id=\"no_").concat(info.id, "_indicator\">None</span>");
|
|
@@ -790,12 +829,16 @@ var fng;
|
|
|
790
829
|
throw new Error('Cannot use arrays in an inline or stacked form');
|
|
791
830
|
}
|
|
792
831
|
template += formMarkupHelper.label(scope, info, info.type !== 'link', options);
|
|
793
|
-
|
|
832
|
+
var stashedHelp = info.help;
|
|
833
|
+
delete info.help;
|
|
834
|
+
var inputHtml = generateInput(info, info.type === 'link' ? null : 'arrayItem.x', true, options);
|
|
835
|
+
info.help = stashedHelp;
|
|
836
|
+
template += formMarkupHelper.handleArrayInputAndControlDiv(inputHtml, controlDivClasses, info, options);
|
|
794
837
|
}
|
|
795
838
|
else {
|
|
796
839
|
// Single fields here
|
|
797
840
|
template += formMarkupHelper.label(scope, info, null, options);
|
|
798
|
-
template += formMarkupHelper.handleInputAndControlDiv(generateInput(info, null, options.required,
|
|
841
|
+
template += formMarkupHelper.handleInputAndControlDiv(generateInput(info, null, options.required, options), controlDivClasses);
|
|
799
842
|
}
|
|
800
843
|
}
|
|
801
844
|
template += fieldChrome.closeTag;
|
|
@@ -1950,7 +1993,7 @@ var fng;
|
|
|
1950
1993
|
angular.extend(formInstructions, mongooseType.options.form);
|
|
1951
1994
|
}
|
|
1952
1995
|
}
|
|
1953
|
-
if (mongooseType.instance === 'String') {
|
|
1996
|
+
if (mongooseType.instance === 'String' || (mongooseType.instance === 'ObjectID' && formInstructions.asText)) {
|
|
1954
1997
|
if (mongooseOptions.enum) {
|
|
1955
1998
|
formInstructions.type = formInstructions.type || 'select';
|
|
1956
1999
|
if (formInstructions.select2) {
|
|
@@ -2261,14 +2304,19 @@ var fng;
|
|
|
2261
2304
|
return forceNextTime;
|
|
2262
2305
|
},
|
|
2263
2306
|
add: function add(fieldName, $event, $scope, modelOverride) {
|
|
2264
|
-
var _a;
|
|
2307
|
+
var _a, _b;
|
|
2308
|
+
// for buttons, the click event won't fire if the disabled attribute exists, but the same is not true of
|
|
2309
|
+
// icons, so we need to check this for simple array item addition
|
|
2310
|
+
if (((_a = $event === null || $event === void 0 ? void 0 : $event.target) === null || _a === void 0 ? void 0 : _a.hasAttribute) && $event.target.hasAttribute("disabled")) {
|
|
2311
|
+
return $event.preventDefault();
|
|
2312
|
+
}
|
|
2265
2313
|
// check that target element is visible. May not be reliable - see https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
|
2266
2314
|
if ($event.target.offsetParent) {
|
|
2267
2315
|
var arrayField = getArrayFieldToExtend(fieldName, $scope, modelOverride);
|
|
2268
2316
|
var schemaElement = $scope.formSchema.find(function (f) { return f.name === fieldName; }); // In case someone is using the formSchema directly
|
|
2269
2317
|
var subSchema = schemaElement ? schemaElement.schema : null;
|
|
2270
2318
|
var obj = subSchema ? $scope.setDefaults(subSchema, fieldName + '.') : {};
|
|
2271
|
-
if (typeof ((
|
|
2319
|
+
if (typeof ((_b = $scope.dataEventFunctions) === null || _b === void 0 ? void 0 : _b.onInitialiseNewSubDoc) === "function") {
|
|
2272
2320
|
$scope.dataEventFunctions.onInitialiseNewSubDoc(fieldName, subSchema, obj);
|
|
2273
2321
|
}
|
|
2274
2322
|
arrayField.push(obj);
|
|
@@ -2281,6 +2329,12 @@ var fng;
|
|
|
2281
2329
|
$scope.setFormDirty($event);
|
|
2282
2330
|
},
|
|
2283
2331
|
remove: function remove(fieldName, value, $event, $scope, modelOverride) {
|
|
2332
|
+
var _a;
|
|
2333
|
+
// for buttons, the click event won't fire if the disabled attribute exists, but the same is not true of
|
|
2334
|
+
// icons, so we need to check this for simple array item removal
|
|
2335
|
+
if (((_a = $event === null || $event === void 0 ? void 0 : $event.target) === null || _a === void 0 ? void 0 : _a.hasAttribute) && $event.target.hasAttribute("disabled")) {
|
|
2336
|
+
return $event.preventDefault();
|
|
2337
|
+
}
|
|
2284
2338
|
// Remove an element from an array
|
|
2285
2339
|
var arrayField = getArrayFieldToExtend(fieldName, $scope, modelOverride);
|
|
2286
2340
|
var err;
|
|
@@ -2415,8 +2469,8 @@ var fng;
|
|
|
2415
2469
|
var services;
|
|
2416
2470
|
(function (services) {
|
|
2417
2471
|
/*@ngInject*/
|
|
2418
|
-
formMarkupHelper.$inject = ["cssFrameworkService", "inputSizeHelper", "addAllService", "$filter"];
|
|
2419
|
-
function formMarkupHelper(cssFrameworkService, inputSizeHelper, addAllService, $filter) {
|
|
2472
|
+
formMarkupHelper.$inject = ["cssFrameworkService", "inputSizeHelper", "addAllService", "$filter", "$rootScope"];
|
|
2473
|
+
function formMarkupHelper(cssFrameworkService, inputSizeHelper, addAllService, $filter, $rootScope) {
|
|
2420
2474
|
function generateNgShow(showWhen, model) {
|
|
2421
2475
|
function evaluateSide(side) {
|
|
2422
2476
|
var result = side;
|
|
@@ -2454,25 +2508,108 @@ var fng;
|
|
|
2454
2508
|
function glyphClass() {
|
|
2455
2509
|
return (cssFrameworkService.framework() === 'bs2' ? 'icon' : 'glyphicon glyphicon');
|
|
2456
2510
|
}
|
|
2511
|
+
function handleReadOnlyDisabled(fieldInfo) {
|
|
2512
|
+
if (fieldInfo.readonly && typeof fieldInfo.readonly === "boolean") {
|
|
2513
|
+
// if we have a true-valued readonly property then this trumps whatever security rule might apply to this field
|
|
2514
|
+
return " disabled ";
|
|
2515
|
+
}
|
|
2516
|
+
function wrapReadOnly() {
|
|
2517
|
+
return fieldInfo.readonly ? " ng-disabled=\"".concat(fieldInfo.readonly, "\" ") : "";
|
|
2518
|
+
}
|
|
2519
|
+
if (!fieldInfo.id || !fng.formsAngular.elemSecurityFuncBinding || !fng.formsAngular.elemSecurityFuncName || !$rootScope[fng.formsAngular.elemSecurityFuncName]) {
|
|
2520
|
+
// no security, so we're just concerned about what value fieldInfo.readonly has
|
|
2521
|
+
return wrapReadOnly();
|
|
2522
|
+
}
|
|
2523
|
+
if (fng.formsAngular.elemSecurityFuncBinding === "instant") {
|
|
2524
|
+
// "instant" security is evaluated now, and a positive result trumps whatever fieldInfo.readonly might be set to
|
|
2525
|
+
if ($rootScope.isSecurelyDisabled(fieldInfo.id)) {
|
|
2526
|
+
return " disabled ";
|
|
2527
|
+
}
|
|
2528
|
+
else {
|
|
2529
|
+
return wrapReadOnly();
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
var securityFuncStr = "".concat(fng.formsAngular.elemSecurityFuncName, "('").concat(fieldInfo.id, "', 'disabled')");
|
|
2533
|
+
var oneTimeBinding = fng.formsAngular.elemSecurityFuncBinding === "one-time";
|
|
2534
|
+
if (fieldInfo.readonly) {
|
|
2535
|
+
// we have both security and a read-only attribute to deal with
|
|
2536
|
+
if (oneTimeBinding) {
|
|
2537
|
+
// if our field has a string-typed readonly attribute *and* one-time binding is required by our securityFunc, we
|
|
2538
|
+
// cannot simply combine these into a single ng-disabled expression, because the readonly property is highly
|
|
2539
|
+
// likely to be model-dependent and therefore cannot use one-time-binding. the best we can do in this case is
|
|
2540
|
+
// to use ng-disabled for the field's readonly property, and a one-time-bound ng-readonly for the securityFunc.
|
|
2541
|
+
// this is not perfect, because in the case of selects, ng-readonly doesn't actually prevent the user from
|
|
2542
|
+
// making a selection. however, the select will be styled as if it is disabled (including the not-allowed
|
|
2543
|
+
// cursor), which should deter the user in most cases.
|
|
2544
|
+
return wrapReadOnly() + "ng-readonly=\"::".concat(securityFuncStr, "\" ");
|
|
2545
|
+
}
|
|
2546
|
+
else {
|
|
2547
|
+
// if we have both things and we are *NOT* required to use one-time binding for the securityFunc, then they can
|
|
2548
|
+
// simply be combined into a single ng-disabled expression
|
|
2549
|
+
return " ng-disabled=\"".concat(securityFuncStr, " || ").concat(fieldInfo.readonly, "\" ");
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
else {
|
|
2553
|
+
// we have security only
|
|
2554
|
+
return " ng-disabled=\"".concat(oneTimeBinding ? "::" : "").concat(securityFuncStr, "\" ");
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
function generateArrayElementIdString(idString, info, options) {
|
|
2558
|
+
if (options.subschema && options.model) {
|
|
2559
|
+
// for subschemas, it is possible that our model will begin with $parent., or $parent.$parent. (etc). though a bit of
|
|
2560
|
+
// a hack where this does occur (probably where a directive used by a sub-schema is using a nested <form-input>
|
|
2561
|
+
// directive), we need to look for the $index in the same place as our model is looking for data.
|
|
2562
|
+
var model = options.model;
|
|
2563
|
+
var nestedSteps = 0;
|
|
2564
|
+
var stepIndicator = "$parent.";
|
|
2565
|
+
while (model.startsWith(stepIndicator)) {
|
|
2566
|
+
nestedSteps++;
|
|
2567
|
+
model = model.substring(stepIndicator.length);
|
|
2568
|
+
}
|
|
2569
|
+
return "".concat(idString, "_{{").concat(stepIndicator.repeat(nestedSteps), "$index}}");
|
|
2570
|
+
}
|
|
2571
|
+
else {
|
|
2572
|
+
return "".concat(idString, "_{{$index}}");
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
function isArrayElement(scope, info, options) {
|
|
2576
|
+
return scope["$index"] !== undefined || !!options.subschema;
|
|
2577
|
+
}
|
|
2457
2578
|
return {
|
|
2458
2579
|
isHorizontalStyle: isHorizontalStyle,
|
|
2580
|
+
isArrayElement: isArrayElement,
|
|
2459
2581
|
fieldChrome: function fieldChrome(scope, info, options) {
|
|
2582
|
+
var insert = '';
|
|
2583
|
+
if (info.id && typeof info.id.replace === "function") {
|
|
2584
|
+
var idStr = "cg_".concat(info.id.replace(/\./g, '-'));
|
|
2585
|
+
insert += "id=\"".concat(isArrayElement(scope, info, options) ? generateArrayElementIdString(idStr, info, options) : idStr, "\"");
|
|
2586
|
+
if (fng.formsAngular.elemSecurityFuncBinding && fng.formsAngular.elemSecurityFuncName && $rootScope[fng.formsAngular.elemSecurityFuncName]) {
|
|
2587
|
+
if (fng.formsAngular.elemSecurityFuncBinding === "instant") {
|
|
2588
|
+
if ($rootScope.isSecurelyHidden(idStr)) {
|
|
2589
|
+
// if our securityFunc supports instant binding and evaluates to true, then nothing needs to be
|
|
2590
|
+
// added to the dom for this field, which we indicate to our caller as follows...
|
|
2591
|
+
return { omit: true };
|
|
2592
|
+
}
|
|
2593
|
+
;
|
|
2594
|
+
}
|
|
2595
|
+
else {
|
|
2596
|
+
var bindingStr = fng.formsAngular.elemSecurityFuncBinding === "one-time" ? "::" : "";
|
|
2597
|
+
insert += " data-ng-if=\"".concat(bindingStr, "!").concat(fng.formsAngular.elemSecurityFuncName, "('").concat(idStr, "', 'hidden')\"");
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2460
2601
|
var classes = info.classes || '';
|
|
2461
2602
|
var template = '';
|
|
2462
2603
|
var closeTag = '';
|
|
2463
|
-
var insert = '';
|
|
2464
2604
|
info.showWhen = info.showWhen || info.showwhen; // deal with use within a directive
|
|
2465
2605
|
if (info.showWhen) {
|
|
2466
2606
|
if (typeof info.showWhen === 'string') {
|
|
2467
|
-
insert += 'ng-show="' + info.showWhen + '"';
|
|
2607
|
+
insert += ' ng-show="' + info.showWhen + '"';
|
|
2468
2608
|
}
|
|
2469
2609
|
else {
|
|
2470
|
-
insert += 'ng-show="' + generateNgShow(info.showWhen, options.model) + '"';
|
|
2610
|
+
insert += ' ng-show="' + generateNgShow(info.showWhen, options.model) + '"';
|
|
2471
2611
|
}
|
|
2472
2612
|
}
|
|
2473
|
-
if (info.id && typeof info.id.replace === "function") {
|
|
2474
|
-
insert += ' id="cg_' + info.id.replace(/\./g, '-') + '"';
|
|
2475
|
-
}
|
|
2476
2613
|
if (cssFrameworkService.framework() === 'bs3') {
|
|
2477
2614
|
classes += ' form-group';
|
|
2478
2615
|
if (options.formstyle === 'vertical' && info.size !== 'block-level') {
|
|
@@ -2532,7 +2669,8 @@ var fng;
|
|
|
2532
2669
|
}
|
|
2533
2670
|
labelHTML += addAllService.addAll(scope, 'Label', null, options) + ' class="' + classes + '">' + fieldInfo.label;
|
|
2534
2671
|
if (addButtonMarkup) {
|
|
2535
|
-
|
|
2672
|
+
var disableCond = handleReadOnlyDisabled(fieldInfo);
|
|
2673
|
+
labelHTML += " <i ".concat(disableCond, " id=\"add_").concat(fieldInfo.id, "\" ng-click=\"add('").concat(fieldInfo.name, "', $event)\" class=\"").concat(glyphClass(), "-plus-sign\"></i>");
|
|
2536
2674
|
}
|
|
2537
2675
|
labelHTML += '</label>';
|
|
2538
2676
|
if (fieldInfo.linklabel) {
|
|
@@ -2568,13 +2706,24 @@ var fng;
|
|
|
2568
2706
|
if (['inline', 'stacked'].includes(options.formstyle)) {
|
|
2569
2707
|
placeHolder = placeHolder || fieldInfo.label;
|
|
2570
2708
|
}
|
|
2571
|
-
common = 'data-ng-model="' + modelString + '"'
|
|
2572
|
-
|
|
2709
|
+
common = 'data-ng-model="' + modelString + '"';
|
|
2710
|
+
if (idString) {
|
|
2711
|
+
common += " id=\"".concat(idString, "\"");
|
|
2712
|
+
}
|
|
2713
|
+
if (nameString) {
|
|
2714
|
+
common += " name=\"".concat(nameString, "\"");
|
|
2715
|
+
}
|
|
2716
|
+
else if (idString) {
|
|
2717
|
+
common += " name=\"".concat(idString, "\"");
|
|
2718
|
+
}
|
|
2719
|
+
if (placeHolder) {
|
|
2720
|
+
common += " placeholder=\"".concat(placeHolder, "\"");
|
|
2721
|
+
}
|
|
2573
2722
|
if (fieldInfo.popup) {
|
|
2574
|
-
common +=
|
|
2723
|
+
common += " title=\"".concat(fieldInfo.popup, "\"");
|
|
2575
2724
|
}
|
|
2576
2725
|
if (fieldInfo.ariaLabel) {
|
|
2577
|
-
common +=
|
|
2726
|
+
common += " aria-label=\"".concat(fieldInfo.ariaLabel, "\"");
|
|
2578
2727
|
}
|
|
2579
2728
|
common += addAllService.addAll(scope, 'Field', null, options);
|
|
2580
2729
|
return {
|
|
@@ -2595,6 +2744,9 @@ var fng;
|
|
|
2595
2744
|
var helpMarkup = cssFrameworkService.framework() === 'bs2' ? { el: 'span', cl: 'help-inline' } : { el: 'div', cl: 'help-block' };
|
|
2596
2745
|
value += "<".concat(helpMarkup.el, " class=\"").concat(helpMarkup.cl, "\">").concat(inlineHelp, "</").concat(helpMarkup.el, ">");
|
|
2597
2746
|
}
|
|
2747
|
+
// this is a dummy tag identifying where the input ends and the messages block (that is only visible when the form field is $dirty)
|
|
2748
|
+
// begins. our caller could replace this tag with anything it needs to insert between these two things.
|
|
2749
|
+
value += "<dms/>";
|
|
2598
2750
|
if (!options.noid) {
|
|
2599
2751
|
value += "<div ng-if=\"".concat((options.name || 'myForm'), "['").concat(fieldInfo.id, "'].$dirty\" class=\"help-block\">") +
|
|
2600
2752
|
" <div ng-messages=\"".concat((options.name || 'myForm'), "['").concat(fieldInfo.id, "'].$error\">") +
|
|
@@ -2636,17 +2788,20 @@ var fng;
|
|
|
2636
2788
|
return inputMarkup;
|
|
2637
2789
|
},
|
|
2638
2790
|
handleArrayInputAndControlDiv: function handleArrayInputAndControlDiv(inputMarkup, controlDivClasses, info, options) {
|
|
2639
|
-
var
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
}
|
|
2791
|
+
var indentStr = cssFrameworkService.framework() === 'bs3' ? 'ng-class="skipCols($index)" ' : "";
|
|
2792
|
+
var arrayStr = (options.model || 'record') + '.' + info.name;
|
|
2793
|
+
var result = "";
|
|
2794
|
+
result += '<div id="' + info.id + 'List" class="' + controlDivClasses.join(' ') + '" ' + indentStr + ' ng-repeat="arrayItem in ' + arrayStr + ' track by $index">';
|
|
2795
|
+
var disableCond = handleReadOnlyDisabled(info);
|
|
2796
|
+
var removeBtn = info.type !== 'link'
|
|
2797
|
+
? "<i ".concat(disableCond, " ng-click=\"remove('").concat(info.name, "', $index, $event)\" id=\"remove_").concat(info.id, "_{{$index}}\" class=\"").concat(glyphClass(), "-minus-sign\"></i>")
|
|
2798
|
+
: "";
|
|
2799
|
+
result += inputMarkup.replace("<dms/>", removeBtn);
|
|
2649
2800
|
result += '</div>';
|
|
2801
|
+
indentStr = cssFrameworkService.framework() === 'bs3' ? 'ng-class="skipCols(' + arrayStr + '.length)" ' : "";
|
|
2802
|
+
if (info.help) {
|
|
2803
|
+
result += '<div class="array-help-block ' + controlDivClasses.join(' ') + '" ' + indentStr + ' id="empty' + info.id + 'ListHelpBlock">' + info.help + '</div>';
|
|
2804
|
+
}
|
|
2650
2805
|
return result;
|
|
2651
2806
|
},
|
|
2652
2807
|
addTextInputMarkup: function addTextInputMarkup(allInputsVars, fieldInfo, requiredStr) {
|
|
@@ -2659,14 +2814,10 @@ var fng;
|
|
|
2659
2814
|
result += ' ' + fieldInfo.add + ' ';
|
|
2660
2815
|
}
|
|
2661
2816
|
result += requiredStr;
|
|
2662
|
-
if (fieldInfo.readonly) {
|
|
2663
|
-
result += " ".concat(typeof fieldInfo.readOnly === 'boolean' ? 'readonly' : 'ng-readonly="' + fieldInfo.readonly + '"', " ");
|
|
2664
|
-
}
|
|
2665
|
-
else {
|
|
2666
|
-
result += ' ';
|
|
2667
|
-
}
|
|
2668
2817
|
return result;
|
|
2669
|
-
}
|
|
2818
|
+
},
|
|
2819
|
+
handleReadOnlyDisabled: handleReadOnlyDisabled,
|
|
2820
|
+
generateArrayElementIdString: generateArrayElementIdString
|
|
2670
2821
|
};
|
|
2671
2822
|
}
|
|
2672
2823
|
services.formMarkupHelper = formMarkupHelper;
|
|
@@ -2705,106 +2856,187 @@ var fng;
|
|
|
2705
2856
|
/*@ngInject*/
|
|
2706
2857
|
pluginHelper.$inject = ["formMarkupHelper"];
|
|
2707
2858
|
function pluginHelper(formMarkupHelper) {
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2859
|
+
function internalGenDisabledStr(id, processedAttrs, forceNg) {
|
|
2860
|
+
var result = formMarkupHelper.handleReadOnlyDisabled({ id: id, readonly: processedAttrs.info.readonly }).trim();
|
|
2861
|
+
// some types of control (such as ui-select) don't deal correctly with a DISABLED attribute and
|
|
2862
|
+
// need ng-disabled, even when the expression is simply "true"
|
|
2863
|
+
if (forceNg && result.toLowerCase() === "disabled") {
|
|
2864
|
+
return 'ng-disabled="true"';
|
|
2865
|
+
}
|
|
2866
|
+
else {
|
|
2867
|
+
return result;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
function makeIdStringUniqueForArrayElements(scope, processedAttrs, idString) {
|
|
2871
|
+
if (formMarkupHelper.isArrayElement(scope, processedAttrs.info, processedAttrs.options)) {
|
|
2872
|
+
return formMarkupHelper.generateArrayElementIdString(idString, processedAttrs.info, processedAttrs.options);
|
|
2873
|
+
}
|
|
2874
|
+
else {
|
|
2875
|
+
return idString;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
function internalGenIdString(scope, processedAttrs, suffix, makeUniqueForArrayElements) {
|
|
2879
|
+
var result = processedAttrs.info.id;
|
|
2880
|
+
if (suffix) {
|
|
2881
|
+
if (!suffix.startsWith("_")) {
|
|
2882
|
+
result += "_";
|
|
2883
|
+
}
|
|
2884
|
+
result += suffix;
|
|
2885
|
+
}
|
|
2886
|
+
if (makeUniqueForArrayElements) {
|
|
2887
|
+
result = makeIdStringUniqueForArrayElements(scope, processedAttrs, result);
|
|
2888
|
+
}
|
|
2889
|
+
return result;
|
|
2890
|
+
}
|
|
2891
|
+
function internalGenDateTimePickerDisabledStr(processedAttrs, idString) {
|
|
2892
|
+
var rawDisabledStr = internalGenDisabledStr(idString, processedAttrs, true);
|
|
2893
|
+
var disabledStr = "";
|
|
2894
|
+
// disabledStr might now include an ng-disabled attribute. To disable both the date and time inputs, we need to
|
|
2895
|
+
// take the value of that attribute and wrap it up as two new attributes: "disabledDate" and "readonlyTime"
|
|
2896
|
+
// (which is what the datetimepicker directive is expecting to receive)
|
|
2897
|
+
if (rawDisabledStr) {
|
|
2898
|
+
// disabledStr should contain either 'ng-disabled="xxxx"' or 'ng-readonly="yyyy"', or both.
|
|
2899
|
+
// the values of xxxx and yyyy could be more-or-less anything, and certainly they could include = or ", which
|
|
2900
|
+
// makes parsing hard
|
|
2901
|
+
// our strategy will be to re-format disabledStr as if it was the string representation of an object, and
|
|
2902
|
+
// then parse it. we can then refer to the ng-disabled and ng-readonly attributes of the parsed object.
|
|
2903
|
+
// in the future, perhaps ng-disabled and ng-readonly will be changed to data-ng-disabled and data-ng-readonly
|
|
2904
|
+
rawDisabledStr = rawDisabledStr.replace("data-ng-disabled", "ng-disabled");
|
|
2905
|
+
rawDisabledStr = rawDisabledStr.replace("data-ng-readonly", "ng-readonly");
|
|
2906
|
+
rawDisabledStr = rawDisabledStr.replace("ng-disabled=", '"ng-disabled":');
|
|
2907
|
+
rawDisabledStr = rawDisabledStr.replace("ng-readonly=", '"ng-readonly":');
|
|
2908
|
+
try {
|
|
2909
|
+
rawDisabledStr = "{ ".concat(rawDisabledStr, " }");
|
|
2910
|
+
var disabledObj = JSON.parse(rawDisabledStr);
|
|
2911
|
+
rawDisabledStr = disabledObj["ng-disabled"];
|
|
2912
|
+
// cannot see a way to sensibly deal with both ng-disabled and ng-readonly. Let's just ignore the ng-readonly
|
|
2913
|
+
// for now - with the way handleReadOnlyDisabled is currently written, this means we'll be unable to fully
|
|
2914
|
+
// support a datetime field with a string-typed "readonly" attribute and where fngAngular's elemSecurityFuncBinding
|
|
2915
|
+
// option is set up to "one-time" or "normal".
|
|
2916
|
+
if (rawDisabledStr) {
|
|
2917
|
+
disabledStr = "disabledDate=\"".concat(rawDisabledStr, "\" readonlyTime=\"").concat(rawDisabledStr, "\"");
|
|
2714
2918
|
}
|
|
2715
|
-
|
|
2716
|
-
|
|
2919
|
+
}
|
|
2920
|
+
catch (e) {
|
|
2921
|
+
// give up
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
return disabledStr;
|
|
2925
|
+
}
|
|
2926
|
+
function extractFromAttr(attr, directiveName) {
|
|
2927
|
+
function deserialize(str) {
|
|
2928
|
+
var retVal = str.replace(/"/g, '"');
|
|
2929
|
+
if (retVal === "true") {
|
|
2930
|
+
return true;
|
|
2931
|
+
}
|
|
2932
|
+
else if (retVal === "false") {
|
|
2933
|
+
return false;
|
|
2934
|
+
}
|
|
2935
|
+
else {
|
|
2936
|
+
var num = parseFloat(retVal);
|
|
2937
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
2938
|
+
return num;
|
|
2717
2939
|
}
|
|
2718
|
-
else
|
|
2719
|
-
|
|
2940
|
+
else {
|
|
2941
|
+
return retVal;
|
|
2720
2942
|
}
|
|
2721
|
-
return retVal;
|
|
2722
2943
|
}
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2944
|
+
}
|
|
2945
|
+
var info = {};
|
|
2946
|
+
var options = { formStyle: attr.formstyle };
|
|
2947
|
+
var directiveOptions = {};
|
|
2948
|
+
var directiveNameLength = directiveName ? directiveName.length : 0;
|
|
2949
|
+
var lcDirectiveName = directiveName === null || directiveName === void 0 ? void 0 : directiveName.toLowerCase();
|
|
2950
|
+
for (var prop in attr) {
|
|
2951
|
+
if (attr.hasOwnProperty(prop)) {
|
|
2952
|
+
var lcProp = prop.toLowerCase();
|
|
2953
|
+
if (lcProp.slice(0, 6) === "fngfld") {
|
|
2954
|
+
info[lcProp.slice(6)] = deserialize(attr[prop]);
|
|
2955
|
+
}
|
|
2956
|
+
else if (lcProp.slice(0, 6) === "fngopt") {
|
|
2957
|
+
options[lcProp.slice(6)] = deserialize(attr[prop]);
|
|
2958
|
+
}
|
|
2959
|
+
else if (directiveName && lcProp.slice(0, directiveNameLength) === lcDirectiveName) {
|
|
2960
|
+
directiveOptions[_.kebabCase(prop.slice(directiveNameLength))] = deserialize(attr[prop]);
|
|
2740
2961
|
}
|
|
2741
2962
|
}
|
|
2742
|
-
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
var
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
nameString = info.name + '_{{$index}}';
|
|
2963
|
+
}
|
|
2964
|
+
return { info: info, options: options, directiveOptions: directiveOptions };
|
|
2965
|
+
}
|
|
2966
|
+
return {
|
|
2967
|
+
extractFromAttr: extractFromAttr,
|
|
2968
|
+
buildInputMarkup: function buildInputMarkup(scope, attrs, params, generateInputControl) {
|
|
2969
|
+
var processedAttrs = params.processedAttrs || extractFromAttr(attrs, "");
|
|
2970
|
+
var info = {};
|
|
2971
|
+
if (!params.ignoreFieldInfoFromAttrs) {
|
|
2972
|
+
Object.assign(info, processedAttrs.info);
|
|
2753
2973
|
}
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
idString = info.id;
|
|
2757
|
-
nameString = info.name;
|
|
2974
|
+
if (params.fieldInfoOverrides) {
|
|
2975
|
+
Object.assign(info, params.fieldInfoOverrides);
|
|
2758
2976
|
}
|
|
2759
|
-
|
|
2977
|
+
var options = Object.assign({}, processedAttrs.options, params.optionOverrides);
|
|
2978
|
+
var fieldChrome = formMarkupHelper.fieldChrome(scope, info, options);
|
|
2979
|
+
if (fieldChrome.omit) {
|
|
2980
|
+
return "";
|
|
2981
|
+
}
|
|
2982
|
+
var controlDivClasses = formMarkupHelper.controlDivClasses(options);
|
|
2983
|
+
var elementHtml = fieldChrome.template + formMarkupHelper.label(scope, info, params.addButtons, options);
|
|
2984
|
+
var idString = info.id;
|
|
2985
|
+
if (info.array || options.subschema) {
|
|
2986
|
+
idString = formMarkupHelper.generateArrayElementIdString(idString, info, options);
|
|
2987
|
+
}
|
|
2988
|
+
var modelString = params.addButtons
|
|
2989
|
+
? "arrayItem" + (params.needsX ? ".x" : "")
|
|
2990
|
+
: attrs.model + "." + info.name;
|
|
2991
|
+
var nameString = info.name;
|
|
2992
|
+
if (options.subschema && info.name.indexOf(".") !== -1) {
|
|
2760
2993
|
// Schema handling - need to massage the ngModel and the id
|
|
2761
|
-
var modelBase = model +
|
|
2762
|
-
var compoundName = info.name;
|
|
2994
|
+
var modelBase = attrs.model + ".";
|
|
2763
2995
|
var root = options.subschemaroot;
|
|
2764
|
-
var lastPart =
|
|
2765
|
-
modelString = modelBase;
|
|
2766
|
-
if (options.
|
|
2767
|
-
modelString
|
|
2768
|
-
|
|
2996
|
+
var lastPart = info.name.slice(root.length + 1);
|
|
2997
|
+
modelString = modelBase + root;
|
|
2998
|
+
if (options.subkey) {
|
|
2999
|
+
idString = modelString.slice(modelBase.length).replace(/\./g, "-") + "-subkey" + options.subkeyno + "-" + lastPart;
|
|
3000
|
+
modelString += "[" + "$_arrayOffset_" + root.replace(/\./g, "_") + "_" + options.subkeyno + "]." + lastPart;
|
|
2769
3001
|
}
|
|
2770
3002
|
else {
|
|
2771
|
-
modelString +=
|
|
2772
|
-
|
|
2773
|
-
idString = modelString.slice(modelBase.length).replace(/\./g, '-') + '-subkey' + options.subkeyno + '-' + lastPart;
|
|
2774
|
-
modelString += '[' + '$_arrayOffset_' + root.replace(/\./g, '_') + '_' + options.subkeyno + '].' + lastPart;
|
|
2775
|
-
}
|
|
2776
|
-
else {
|
|
2777
|
-
modelString += '[$index].' + lastPart;
|
|
2778
|
-
idString = null;
|
|
2779
|
-
nameString = compoundName.replace(/\./g, '-');
|
|
2780
|
-
}
|
|
3003
|
+
modelString += "[$index]." + lastPart;
|
|
3004
|
+
nameString = info.name.replace(/\./g, "-");
|
|
2781
3005
|
}
|
|
2782
3006
|
}
|
|
2783
3007
|
var buildingBlocks = formMarkupHelper.allInputsVars(scope, info, options, modelString, idString, nameString);
|
|
2784
3008
|
buildingBlocks.modelString = modelString;
|
|
2785
|
-
|
|
3009
|
+
// defer to the calling directive to generate the markup for the input(s)
|
|
3010
|
+
var inputHtml = generateInputControl(buildingBlocks);
|
|
3011
|
+
// wrap this in a div that puts it into the correct bootstrap 'column' and adds validation messages and help text
|
|
3012
|
+
var wrappedInputHtml = formMarkupHelper.inputChrome(inputHtml, info, options, buildingBlocks);
|
|
3013
|
+
// further wrap this to add the control div classes, and in the case of an array, the button that allows array elements to be removed
|
|
3014
|
+
var inputAndControlDivGenerator = params.addButtons
|
|
3015
|
+
? formMarkupHelper.handleArrayInputAndControlDiv
|
|
3016
|
+
: formMarkupHelper.handleInputAndControlDiv;
|
|
3017
|
+
elementHtml += inputAndControlDivGenerator(wrappedInputHtml, controlDivClasses, info, options);
|
|
2786
3018
|
elementHtml += fieldChrome.closeTag;
|
|
2787
3019
|
return elementHtml;
|
|
2788
3020
|
},
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
return
|
|
2807
|
-
}
|
|
3021
|
+
genIdString: function genIdString(scope, processedAttrs, idSuffix) {
|
|
3022
|
+
return internalGenIdString(scope, processedAttrs, idSuffix, true);
|
|
3023
|
+
},
|
|
3024
|
+
genDisabledStr: function genDisabledStr(scope, processedAttrs, idSuffix, forceNg) {
|
|
3025
|
+
var idString = internalGenIdString(scope, processedAttrs, idSuffix, false);
|
|
3026
|
+
return internalGenDisabledStr(idString, processedAttrs, forceNg);
|
|
3027
|
+
},
|
|
3028
|
+
genIdAndDisabledStr: function genIdAndDisabledStr(scope, processedAttrs, idSuffix, forceNg) {
|
|
3029
|
+
var idString = internalGenIdString(scope, processedAttrs, idSuffix, false);
|
|
3030
|
+
return "id=\"".concat(makeIdStringUniqueForArrayElements(scope, processedAttrs, idString), "\" ") + internalGenDisabledStr(idString, processedAttrs, forceNg);
|
|
3031
|
+
},
|
|
3032
|
+
genDateTimePickerDisabledStr: function genDateTimePickerDisabledStr(scope, processedAttrs, idSuffix) {
|
|
3033
|
+
var idString = internalGenIdString(scope, processedAttrs, idSuffix, false);
|
|
3034
|
+
return internalGenDateTimePickerDisabledStr(processedAttrs, idString);
|
|
3035
|
+
},
|
|
3036
|
+
genDateTimePickerIdAndDisabledStr: function genDateTimePickerIdAndDisabledStr(scope, processedAttrs, idSuffix) {
|
|
3037
|
+
var idString = internalGenIdString(scope, processedAttrs, idSuffix, false);
|
|
3038
|
+
return "id=\"".concat(makeIdStringUniqueForArrayElements(scope, processedAttrs, idString), "\" ") + internalGenDateTimePickerDisabledStr(processedAttrs, idString);
|
|
3039
|
+
},
|
|
2808
3040
|
};
|
|
2809
3041
|
}
|
|
2810
3042
|
services.pluginHelper = pluginHelper;
|
|
@@ -3076,18 +3308,12 @@ var fng;
|
|
|
3076
3308
|
var idList = $scope[suffixCleanId(schemaEntry, "_ids")];
|
|
3077
3309
|
var thisConversion = void 0;
|
|
3078
3310
|
if (fieldValue && idList && idList.length > 0) {
|
|
3079
|
-
if (fieldName.indexOf(".") !== -1) {
|
|
3080
|
-
throw new Error("Trying to directly assign to a nested field 332");
|
|
3081
|
-
} // Not sure that this can happen, but put in a runtime test
|
|
3082
3311
|
if (
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
/*
|
|
3089
|
-
We are not suppressing conversions
|
|
3090
|
-
*/
|
|
3312
|
+
// it's not a nested field
|
|
3313
|
+
!fieldName.includes(".") &&
|
|
3314
|
+
// Check we are starting with an ObjectId (ie not being called because of $watch on conversion, with a converted value, which would cause an exception)
|
|
3315
|
+
fieldValue.toString().match(/^[a-f0-9]{24}$/) &&
|
|
3316
|
+
// We are not suppressing conversions
|
|
3091
3317
|
(!schemaEntry.internalRef || !schemaEntry.internalRef.noConvert)) {
|
|
3092
3318
|
anObject[fieldName] = convertForeignKeys(schemaEntry, fieldValue, $scope[suffixCleanId(schemaEntry, "Options")], idList);
|
|
3093
3319
|
}
|
|
@@ -3438,18 +3664,20 @@ var fng;
|
|
|
3438
3664
|
return function (response) {
|
|
3439
3665
|
if ([200, 400].indexOf(response.status) !== -1) {
|
|
3440
3666
|
var errorMessage = "";
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3667
|
+
if (response.data && response.data.errors) {
|
|
3668
|
+
for (var errorField in response.data.errors) {
|
|
3669
|
+
if (response.data.errors.hasOwnProperty(errorField)) {
|
|
3670
|
+
errorMessage += "<li><b>" + $filter("titleCase")(errorField) + ": </b> ";
|
|
3671
|
+
switch (response.data.errors[errorField].type) {
|
|
3672
|
+
case "enum":
|
|
3673
|
+
errorMessage += "You need to select from the list of values";
|
|
3674
|
+
break;
|
|
3675
|
+
default:
|
|
3676
|
+
errorMessage += response.data.errors[errorField].message;
|
|
3677
|
+
break;
|
|
3678
|
+
}
|
|
3679
|
+
errorMessage += "</li>";
|
|
3451
3680
|
}
|
|
3452
|
-
errorMessage += "</li>";
|
|
3453
3681
|
}
|
|
3454
3682
|
}
|
|
3455
3683
|
if (errorMessage.length > 0) {
|
|
@@ -4088,11 +4316,25 @@ var fng;
|
|
|
4088
4316
|
//}
|
|
4089
4317
|
};
|
|
4090
4318
|
$scope.sortableOptions = {
|
|
4091
|
-
update: function () {
|
|
4092
|
-
if (
|
|
4319
|
+
update: function (e, ui) {
|
|
4320
|
+
if (e.target.hasAttribute("disabled")) {
|
|
4321
|
+
// where formsAngular.elemSecurityFuncBinding is set to "one-time" or "normal", the <ol> that the
|
|
4322
|
+
// ui-sortable directive has been used with will have an ng-disabled that may or may not have caused
|
|
4323
|
+
// a disabled attribute to be added to that element. in the case where this attribute has been
|
|
4324
|
+
// added, sorting should be prevented.
|
|
4325
|
+
// allowing the user to begin the drag, and then preventing it only once they release the mouse button,
|
|
4326
|
+
// doesn't seem like the best solution, but I've yet to find something that works better. the
|
|
4327
|
+
// cancel property (see commented-out code below) looks like it should work (and kind of does), but this
|
|
4328
|
+
// screws up mouse events on input fields hosted within the draggable <li> items, so you're
|
|
4329
|
+
// basically prevented from updating any form element in the nested schema
|
|
4330
|
+
ui.item.sortable.cancel();
|
|
4331
|
+
}
|
|
4332
|
+
else if ($scope.topLevelFormName) {
|
|
4093
4333
|
$scope[$scope.topLevelFormName].$setDirty();
|
|
4094
4334
|
}
|
|
4095
|
-
}
|
|
4335
|
+
},
|
|
4336
|
+
// don't do this (see comment above)
|
|
4337
|
+
//cancel: "ol[disabled]>li"
|
|
4096
4338
|
};
|
|
4097
4339
|
$scope.setUpCustomLookupOptions = function (schemaElement, ids, options, baseScope) {
|
|
4098
4340
|
for (var _i = 0, _a = [$scope, baseScope]; _i < _a.length; _i++) {
|
|
@@ -4412,8 +4654,17 @@ var fng;
|
|
|
4412
4654
|
function clearContextMenu() {
|
|
4413
4655
|
$scope.items = [];
|
|
4414
4656
|
$scope.contextMenu = undefined;
|
|
4657
|
+
$scope.contextMenuId = undefined;
|
|
4658
|
+
$scope.contextMenuHidden = undefined;
|
|
4659
|
+
$scope.contextMenuDisabled = undefined;
|
|
4415
4660
|
}
|
|
4416
4661
|
$rootScope.navScope = $scope; // Lets plugins access menus
|
|
4662
|
+
$rootScope.isSecurelyHidden = function (elemId) {
|
|
4663
|
+
return fng.formsAngular.elemSecurityFuncName && $rootScope[fng.formsAngular.elemSecurityFuncName](elemId, "hidden");
|
|
4664
|
+
};
|
|
4665
|
+
$rootScope.isSecurelyDisabled = function (elemId) {
|
|
4666
|
+
return fng.formsAngular.elemSecurityFuncName && $rootScope[fng.formsAngular.elemSecurityFuncName](elemId, "disabled");
|
|
4667
|
+
};
|
|
4417
4668
|
clearContextMenu();
|
|
4418
4669
|
$scope.toggleCollapsed = function () {
|
|
4419
4670
|
$scope.collapsed = !$scope.collapsed;
|
|
@@ -4489,11 +4740,21 @@ var fng;
|
|
|
4489
4740
|
}
|
|
4490
4741
|
return result;
|
|
4491
4742
|
};
|
|
4743
|
+
$scope.secureContextMenu = function () {
|
|
4744
|
+
$scope.contextMenuHidden = $rootScope.isSecurelyHidden($scope.contextMenuId);
|
|
4745
|
+
$scope.contextMenuDisabled = $rootScope.isSecurelyDisabled($scope.contextMenuId);
|
|
4746
|
+
};
|
|
4747
|
+
function initialiseContextMenu(menuCaption) {
|
|
4748
|
+
$scope.contextMenu = menuCaption;
|
|
4749
|
+
var menuId = "".concat(_.camelCase(menuCaption), "ContextMenu");
|
|
4750
|
+
$scope.contextMenuId = menuId;
|
|
4751
|
+
$scope.secureContextMenu();
|
|
4752
|
+
}
|
|
4492
4753
|
$scope.$on('fngControllersLoaded', function (evt, sharedData, modelName) {
|
|
4493
|
-
|
|
4754
|
+
initialiseContextMenu(sharedData.dropDownDisplay || sharedData.modelNameDisplay || $filter('titleCase')(modelName, false));
|
|
4494
4755
|
if (sharedData.dropDownDisplayPromise) {
|
|
4495
4756
|
sharedData.dropDownDisplayPromise.then(function (value) {
|
|
4496
|
-
|
|
4757
|
+
initialiseContextMenu(value);
|
|
4497
4758
|
});
|
|
4498
4759
|
}
|
|
4499
4760
|
});
|
|
@@ -4542,8 +4803,9 @@ var fng;
|
|
|
4542
4803
|
return item.isHidden ? item.isHidden() : false;
|
|
4543
4804
|
}
|
|
4544
4805
|
var dividerHide = false;
|
|
4806
|
+
var item = $scope.items[index];
|
|
4545
4807
|
// Hide a divider if it appears under another
|
|
4546
|
-
if (
|
|
4808
|
+
if (item.divider) {
|
|
4547
4809
|
if (index === 0) {
|
|
4548
4810
|
dividerHide = true;
|
|
4549
4811
|
}
|
|
@@ -4563,7 +4825,7 @@ var fng;
|
|
|
4563
4825
|
}
|
|
4564
4826
|
}
|
|
4565
4827
|
}
|
|
4566
|
-
return dividerHide || explicitlyHidden(
|
|
4828
|
+
return dividerHide || explicitlyHidden(item);
|
|
4567
4829
|
};
|
|
4568
4830
|
$scope.isDisabled = function (index) {
|
|
4569
4831
|
return $scope.items[index].isDisabled ? $scope.items[index].isDisabled() : false;
|