@memberjunction/ng-base-forms 5.38.0 → 5.39.0
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/README.md +53 -0
- package/dist/lib/base-form-component.d.ts +18 -0
- package/dist/lib/base-form-component.d.ts.map +1 -1
- package/dist/lib/base-form-component.js +31 -2
- package/dist/lib/base-form-component.js.map +1 -1
- package/dist/lib/container/record-form-container.component.d.ts +14 -0
- package/dist/lib/container/record-form-container.component.d.ts.map +1 -1
- package/dist/lib/container/record-form-container.component.js +59 -33
- package/dist/lib/container/record-form-container.component.js.map +1 -1
- package/dist/lib/field/fk-search-utils.d.ts +31 -0
- package/dist/lib/field/fk-search-utils.d.ts.map +1 -0
- package/dist/lib/field/fk-search-utils.js +47 -0
- package/dist/lib/field/fk-search-utils.js.map +1 -0
- package/dist/lib/field/form-field.component.d.ts +401 -6
- package/dist/lib/field/form-field.component.d.ts.map +1 -1
- package/dist/lib/field/form-field.component.js +1646 -214
- package/dist/lib/field/form-field.component.js.map +1 -1
- package/dist/lib/field/linked-field-options.d.ts +76 -0
- package/dist/lib/field/linked-field-options.d.ts.map +1 -0
- package/dist/lib/field/linked-field-options.js +80 -0
- package/dist/lib/field/linked-field-options.js.map +1 -0
- package/dist/lib/host/entity-form-host.component.d.ts +159 -0
- package/dist/lib/host/entity-form-host.component.d.ts.map +1 -0
- package/dist/lib/host/entity-form-host.component.js +539 -0
- package/dist/lib/host/entity-form-host.component.js.map +1 -0
- package/dist/lib/isa-related-panel/isa-related-card.component.js +2 -2
- package/dist/lib/overlays/base-form-overlay.d.ts +114 -0
- package/dist/lib/overlays/base-form-overlay.d.ts.map +1 -0
- package/dist/lib/overlays/base-form-overlay.js +227 -0
- package/dist/lib/overlays/base-form-overlay.js.map +1 -0
- package/dist/lib/overlays/form-dialog.component.d.ts +35 -0
- package/dist/lib/overlays/form-dialog.component.d.ts.map +1 -0
- package/dist/lib/overlays/form-dialog.component.js +92 -0
- package/dist/lib/overlays/form-dialog.component.js.map +1 -0
- package/dist/lib/overlays/form-presenter.service.d.ts +37 -0
- package/dist/lib/overlays/form-presenter.service.d.ts.map +1 -0
- package/dist/lib/overlays/form-presenter.service.js +130 -0
- package/dist/lib/overlays/form-presenter.service.js.map +1 -0
- package/dist/lib/overlays/form-presenter.types.d.ts +65 -0
- package/dist/lib/overlays/form-presenter.types.d.ts.map +1 -0
- package/dist/lib/overlays/form-presenter.types.js +25 -0
- package/dist/lib/overlays/form-presenter.types.js.map +1 -0
- package/dist/lib/overlays/form-slide-in.component.d.ts +38 -0
- package/dist/lib/overlays/form-slide-in.component.d.ts.map +1 -0
- package/dist/lib/overlays/form-slide-in.component.js +106 -0
- package/dist/lib/overlays/form-slide-in.component.js.map +1 -0
- package/dist/lib/overlays/form-window.component.d.ts +32 -0
- package/dist/lib/overlays/form-window.component.d.ts.map +1 -0
- package/dist/lib/overlays/form-window.component.js +93 -0
- package/dist/lib/overlays/form-window.component.js.map +1 -0
- package/dist/lib/panel/collapsible-panel.component.d.ts +19 -2
- package/dist/lib/panel/collapsible-panel.component.d.ts.map +1 -1
- package/dist/lib/panel/collapsible-panel.component.js +70 -13
- package/dist/lib/panel/collapsible-panel.component.js.map +1 -1
- package/dist/lib/resolver/form-resolver.service.d.ts +139 -0
- package/dist/lib/resolver/form-resolver.service.d.ts.map +1 -0
- package/dist/lib/resolver/form-resolver.service.js +235 -0
- package/dist/lib/resolver/form-resolver.service.js.map +1 -0
- package/dist/lib/section-manager/section-manager.component.js +2 -2
- package/dist/lib/toolbar/form-toolbar.component.js +2 -2
- package/dist/lib/types/entity-form-config.d.ts +125 -0
- package/dist/lib/types/entity-form-config.d.ts.map +1 -0
- package/dist/lib/types/entity-form-config.js +75 -0
- package/dist/lib/types/entity-form-config.js.map +1 -0
- package/dist/lib/types/form-types.d.ts +24 -0
- package/dist/lib/types/form-types.d.ts.map +1 -1
- package/dist/lib/types/form-types.js.map +1 -1
- package/dist/lib/types/navigation-events.d.ts +46 -2
- package/dist/lib/types/navigation-events.d.ts.map +1 -1
- package/dist/lib/types/navigation-events.js.map +1 -1
- package/dist/module.d.ts +12 -8
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +26 -7
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +11 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +14 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +17 -13
|
@@ -1,34 +1,57 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, inject } from '@angular/core';
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, inject, ElementRef, Renderer2 } from '@angular/core';
|
|
2
2
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
|
-
import { CompositeKey, KeyValuePair, RunView } from '@memberjunction/core';
|
|
4
|
-
import {
|
|
3
|
+
import { EntityFieldTSType, CompositeKey, KeyValuePair, RunView } from '@memberjunction/core';
|
|
4
|
+
import { BaseEngineRegistry } from '@memberjunction/core';
|
|
5
|
+
import { HighlightSearchMatches, detectRichTextFormat, UUIDsEqual } from '@memberjunction/global';
|
|
6
|
+
import { FormatFKCell, FilterCachedFKRows } from './fk-search-utils';
|
|
7
|
+
import { LinkedFieldOptionsStore } from './linked-field-options';
|
|
5
8
|
import * as i0 from "@angular/core";
|
|
6
9
|
import * as i1 from "@angular/common";
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
import * as i2 from "@memberjunction/ng-markdown";
|
|
11
|
+
import * as i3 from "@memberjunction/ng-code-editor";
|
|
12
|
+
import * as i4 from "@memberjunction/ng-shared-generic";
|
|
13
|
+
const _c0 = a0 => ({ $implicit: a0 });
|
|
14
|
+
const _forTrack0 = ($index, $item) => $item.FieldName;
|
|
15
|
+
const _forTrack1 = ($index, $item) => $item.PrimaryKeyValue;
|
|
16
|
+
const _forTrack2 = ($index, $item) => $item.Message;
|
|
9
17
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
10
|
-
i0.ɵɵelement(0, "label",
|
|
18
|
+
i0.ɵɵelement(0, "label", 4);
|
|
11
19
|
} if (rf & 2) {
|
|
12
20
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
13
21
|
i0.ɵɵproperty("innerHTML", ctx_r0.HighlightedDisplayName, i0.ɵɵsanitizeHtml);
|
|
14
22
|
} }
|
|
15
|
-
function
|
|
23
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
16
24
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
17
|
-
i0.ɵɵelementStart(0, "
|
|
18
|
-
i0.ɵɵlistener("click", function
|
|
19
|
-
i0.ɵɵtext(
|
|
20
|
-
i0.ɵɵelementEnd()
|
|
25
|
+
i0.ɵɵelementStart(0, "a", 8);
|
|
26
|
+
i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_1_Template_a_click_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnRecordLinkClick($event)); });
|
|
27
|
+
i0.ɵɵtext(1);
|
|
28
|
+
i0.ɵɵelementEnd();
|
|
21
29
|
} if (rf & 2) {
|
|
22
|
-
const ctx_r0 = i0.ɵɵnextContext(
|
|
23
|
-
i0.ɵɵadvance(
|
|
30
|
+
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
31
|
+
i0.ɵɵadvance();
|
|
32
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.FKDisplayName, " ");
|
|
33
|
+
} }
|
|
34
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
35
|
+
i0.ɵɵtext(0);
|
|
36
|
+
} if (rf & 2) {
|
|
37
|
+
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
24
38
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.FKDisplayName, " ");
|
|
25
39
|
} }
|
|
40
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
41
|
+
i0.ɵɵelementStart(0, "span", 6);
|
|
42
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_1_Template, 2, 1, "a", 7)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Conditional_2_Template, 1, 1);
|
|
43
|
+
i0.ɵɵelementEnd();
|
|
44
|
+
} if (rf & 2) {
|
|
45
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
46
|
+
i0.ɵɵadvance();
|
|
47
|
+
i0.ɵɵconditional(ctx_r0.RecordLinksEnabled ? 1 : 2);
|
|
48
|
+
} }
|
|
26
49
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template(rf, ctx) { if (rf & 1) {
|
|
27
50
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
28
|
-
i0.ɵɵelementStart(0, "span",
|
|
51
|
+
i0.ɵɵelementStart(0, "span", 6)(1, "a", 9);
|
|
29
52
|
i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template_a_click_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnEmailLinkClick($event)); });
|
|
30
53
|
i0.ɵɵtext(2);
|
|
31
|
-
i0.ɵɵelement(3, "i",
|
|
54
|
+
i0.ɵɵelement(3, "i", 10);
|
|
32
55
|
i0.ɵɵelementEnd()();
|
|
33
56
|
} if (rf & 2) {
|
|
34
57
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
@@ -37,31 +60,46 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_T
|
|
|
37
60
|
} }
|
|
38
61
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_1_Template(rf, ctx) { if (rf & 1) {
|
|
39
62
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
40
|
-
i0.ɵɵelementStart(0, "span",
|
|
63
|
+
i0.ɵɵelementStart(0, "span", 6)(1, "a", 11);
|
|
41
64
|
i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_1_Template_a_click_1_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnUrlLinkClick($event)); });
|
|
42
65
|
i0.ɵɵtext(2);
|
|
43
|
-
i0.ɵɵelement(3, "i",
|
|
66
|
+
i0.ɵɵelement(3, "i", 12);
|
|
44
67
|
i0.ɵɵelementEnd()();
|
|
45
68
|
} if (rf & 2) {
|
|
46
69
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
47
70
|
i0.ɵɵadvance(2);
|
|
48
71
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.FormatValue(), " ");
|
|
49
72
|
} }
|
|
50
|
-
function
|
|
73
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
51
74
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
52
|
-
i0.ɵɵelementStart(0, "
|
|
53
|
-
i0.ɵɵlistener("click", function
|
|
54
|
-
i0.ɵɵtext(
|
|
55
|
-
i0.ɵɵelement(
|
|
56
|
-
i0.ɵɵelementEnd()
|
|
75
|
+
i0.ɵɵelementStart(0, "a", 14);
|
|
76
|
+
i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_1_Template_a_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnRecordLinkClick($event)); });
|
|
77
|
+
i0.ɵɵtext(1);
|
|
78
|
+
i0.ɵɵelement(2, "i", 12);
|
|
79
|
+
i0.ɵɵelementEnd();
|
|
57
80
|
} if (rf & 2) {
|
|
58
|
-
const ctx_r0 = i0.ɵɵnextContext(
|
|
59
|
-
i0.ɵɵadvance(
|
|
81
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
82
|
+
i0.ɵɵadvance();
|
|
60
83
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.FormatValue(), " ");
|
|
61
84
|
} }
|
|
85
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
86
|
+
i0.ɵɵtext(0);
|
|
87
|
+
} if (rf & 2) {
|
|
88
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
89
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.FormatValue(), " ");
|
|
90
|
+
} }
|
|
91
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Template(rf, ctx) { if (rf & 1) {
|
|
92
|
+
i0.ɵɵelementStart(0, "span", 6);
|
|
93
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_1_Template, 3, 1, "a", 13)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Conditional_2_Template, 1, 1);
|
|
94
|
+
i0.ɵɵelementEnd();
|
|
95
|
+
} if (rf & 2) {
|
|
96
|
+
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
97
|
+
i0.ɵɵadvance();
|
|
98
|
+
i0.ɵɵconditional(ctx_r0.RecordLinksEnabled ? 1 : 2);
|
|
99
|
+
} }
|
|
62
100
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
63
|
-
i0.ɵɵelementStart(0, "span",
|
|
64
|
-
i0.ɵɵelement(2, "input",
|
|
101
|
+
i0.ɵɵelementStart(0, "span", 6)(1, "div", 19);
|
|
102
|
+
i0.ɵɵelement(2, "input", 20);
|
|
65
103
|
i0.ɵɵelementEnd()();
|
|
66
104
|
} if (rf & 2) {
|
|
67
105
|
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
@@ -69,7 +107,32 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_C
|
|
|
69
107
|
i0.ɵɵproperty("checked", !!ctx_r0.Value);
|
|
70
108
|
} }
|
|
71
109
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
72
|
-
i0.ɵɵelementStart(0, "
|
|
110
|
+
i0.ɵɵelementStart(0, "div", 15);
|
|
111
|
+
i0.ɵɵelement(1, "mj-markdown", 21);
|
|
112
|
+
i0.ɵɵelementEnd();
|
|
113
|
+
} if (rf & 2) {
|
|
114
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
115
|
+
i0.ɵɵadvance();
|
|
116
|
+
i0.ɵɵproperty("data", ctx_r0.FormatValue());
|
|
117
|
+
} }
|
|
118
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
119
|
+
i0.ɵɵelement(0, "div", 16);
|
|
120
|
+
i0.ɵɵpipe(1, "mjSafeRichHtml");
|
|
121
|
+
} if (rf & 2) {
|
|
122
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
123
|
+
i0.ɵɵproperty("innerHTML", i0.ɵɵpipeBind1(1, 1, ctx_r0.FormatValue()), i0.ɵɵsanitizeHtml);
|
|
124
|
+
} }
|
|
125
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
126
|
+
i0.ɵɵelementStart(0, "div", 17);
|
|
127
|
+
i0.ɵɵelement(1, "mj-code-editor", 22);
|
|
128
|
+
i0.ɵɵelementEnd();
|
|
129
|
+
} if (rf & 2) {
|
|
130
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
131
|
+
i0.ɵɵadvance();
|
|
132
|
+
i0.ɵɵproperty("value", ctx_r0.FormatValue())("language", ctx_r0.CodeEditorLanguage)("readonly", true);
|
|
133
|
+
} }
|
|
134
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
135
|
+
i0.ɵɵelementStart(0, "span", 18);
|
|
73
136
|
i0.ɵɵtext(1);
|
|
74
137
|
i0.ɵɵelementEnd();
|
|
75
138
|
} if (rf & 2) {
|
|
@@ -77,8 +140,8 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_C
|
|
|
77
140
|
i0.ɵɵadvance();
|
|
78
141
|
i0.ɵɵtextInterpolate(ctx_r0.FormatValue());
|
|
79
142
|
} }
|
|
80
|
-
function
|
|
81
|
-
i0.ɵɵelementStart(0, "span",
|
|
143
|
+
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
144
|
+
i0.ɵɵelementStart(0, "span", 6);
|
|
82
145
|
i0.ɵɵtext(1);
|
|
83
146
|
i0.ɵɵelementEnd();
|
|
84
147
|
} if (rf & 2) {
|
|
@@ -87,23 +150,23 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_C
|
|
|
87
150
|
i0.ɵɵtextInterpolate(ctx_r0.FormatValue());
|
|
88
151
|
} }
|
|
89
152
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Template(rf, ctx) { if (rf & 1) {
|
|
90
|
-
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_0_Template, 3, 1, "span",
|
|
153
|
+
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_0_Template, 3, 1, "span", 6)(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_1_Template, 2, 1, "div", 15)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_2_Template, 2, 3, "div", 16)(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_3_Template, 2, 3, "div", 17)(4, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_4_Template, 2, 1, "span", 18)(5, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Conditional_5_Template, 2, 1, "span", 6);
|
|
91
154
|
} if (rf & 2) {
|
|
92
155
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
93
|
-
i0.ɵɵconditional(ctx_r0.Type === "checkbox" ? 0 : ctx_r0.
|
|
156
|
+
i0.ɵɵconditional(ctx_r0.Type === "checkbox" ? 0 : ctx_r0.RichTextMode === "markdown" ? 1 : ctx_r0.RichTextMode === "html" ? 2 : ctx_r0.RichTextMode === "code" ? 3 : ctx_r0.IsLongText ? 4 : 5);
|
|
94
157
|
} }
|
|
95
158
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
96
|
-
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template, 4, 1, "span",
|
|
159
|
+
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_0_Template, 4, 1, "span", 6)(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_1_Template, 4, 1, "span", 6)(2, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_2_Template, 3, 1, "span", 6)(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Case_3_Template, 6, 1);
|
|
97
160
|
} if (rf & 2) {
|
|
98
161
|
let tmp_3_0;
|
|
99
162
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
100
163
|
i0.ɵɵconditional((tmp_3_0 = ctx_r0.LinkType) === "Email" ? 0 : tmp_3_0 === "URL" ? 1 : tmp_3_0 === "Record" ? 2 : 3);
|
|
101
164
|
} }
|
|
102
165
|
function MjFormFieldComponent_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
103
|
-
i0.ɵɵelementStart(0, "div",
|
|
104
|
-
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_1_Template, 1, 1, "label",
|
|
105
|
-
i0.ɵɵelementStart(2, "div",
|
|
106
|
-
i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template, 3, 1, "span",
|
|
166
|
+
i0.ɵɵelementStart(0, "div", 3);
|
|
167
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_1_Template, 1, 1, "label", 4);
|
|
168
|
+
i0.ɵɵelementStart(2, "div", 5);
|
|
169
|
+
i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_3_Template, 3, 1, "span", 6)(4, MjFormFieldComponent_Conditional_0_Conditional_0_Conditional_4_Template, 4, 1);
|
|
107
170
|
i0.ɵɵelementEnd()();
|
|
108
171
|
} if (rf & 2) {
|
|
109
172
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -114,123 +177,473 @@ function MjFormFieldComponent_Conditional_0_Conditional_0_Template(rf, ctx) { if
|
|
|
114
177
|
i0.ɵɵconditional(ctx_r0.IsFKWithNameField ? 3 : 4);
|
|
115
178
|
} }
|
|
116
179
|
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
117
|
-
i0.ɵɵelement(0, "label",
|
|
180
|
+
i0.ɵɵelement(0, "label", 4);
|
|
118
181
|
} if (rf & 2) {
|
|
119
182
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
120
183
|
i0.ɵɵproperty("innerHTML", ctx_r0.HighlightedDisplayName, i0.ɵɵsanitizeHtml);
|
|
121
184
|
} }
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
i0.ɵɵelementStart(0, "button", 24);
|
|
125
|
-
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_2_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnFKClearClick($event)); });
|
|
126
|
-
i0.ɵɵelement(1, "i", 25);
|
|
127
|
-
i0.ɵɵelementEnd();
|
|
185
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
186
|
+
i0.ɵɵelement(0, "i", 29);
|
|
128
187
|
} }
|
|
129
188
|
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
130
|
-
i0.ɵɵ
|
|
189
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
190
|
+
i0.ɵɵelementStart(0, "button", 35);
|
|
191
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_3_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnFKScopeToggle($event)); });
|
|
192
|
+
i0.ɵɵelement(1, "i", 36);
|
|
193
|
+
i0.ɵɵelementStart(2, "span", 37);
|
|
194
|
+
i0.ɵɵtext(3);
|
|
195
|
+
i0.ɵɵelementEnd();
|
|
196
|
+
i0.ɵɵelement(4, "i", 38);
|
|
197
|
+
i0.ɵɵelementEnd();
|
|
198
|
+
} if (rf & 2) {
|
|
199
|
+
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
200
|
+
i0.ɵɵclassProp("mj-fk-scope-pill--open", ctx_r0.FKShowScopeMenu);
|
|
201
|
+
i0.ɵɵproperty("title", "Searching " + ctx_r0.FKSearchFieldLabel + " \u2014 click to change");
|
|
202
|
+
i0.ɵɵadvance(3);
|
|
203
|
+
i0.ɵɵtextInterpolate(ctx_r0.FKSearchFieldLabel);
|
|
204
|
+
i0.ɵɵadvance();
|
|
205
|
+
i0.ɵɵclassProp("fa-chevron-up", ctx_r0.FKShowScopeMenu)("fa-chevron-down", !ctx_r0.FKShowScopeMenu);
|
|
131
206
|
} }
|
|
132
|
-
function
|
|
207
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
133
208
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
134
|
-
i0.ɵɵelementStart(0, "
|
|
135
|
-
i0.ɵɵlistener("mousedown", function
|
|
209
|
+
i0.ɵɵelementStart(0, "button", 39);
|
|
210
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnFKClearClick($event)); });
|
|
211
|
+
i0.ɵɵelement(1, "i", 40);
|
|
212
|
+
i0.ɵɵelementEnd();
|
|
213
|
+
} }
|
|
214
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
215
|
+
i0.ɵɵelement(0, "i", 33);
|
|
216
|
+
} }
|
|
217
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_ng_container_0_Template(rf, ctx) { if (rf & 1) {
|
|
218
|
+
i0.ɵɵelementContainer(0);
|
|
219
|
+
} }
|
|
220
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
221
|
+
i0.ɵɵtemplate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_ng_container_0_Template, 1, 0, "ng-container", 50);
|
|
222
|
+
} if (rf & 2) {
|
|
223
|
+
const f_r9 = i0.ɵɵnextContext().$implicit;
|
|
224
|
+
i0.ɵɵnextContext(2);
|
|
225
|
+
const scopeRow_r10 = i0.ɵɵreference(3);
|
|
226
|
+
i0.ɵɵproperty("ngTemplateOutlet", scopeRow_r10)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, f_r9));
|
|
227
|
+
} }
|
|
228
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
229
|
+
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Conditional_0_Template, 1, 4, "ng-container");
|
|
230
|
+
} if (rf & 2) {
|
|
231
|
+
const f_r9 = ctx.$implicit;
|
|
232
|
+
i0.ɵɵconditional(f_r9.Group === "shown" ? 0 : -1);
|
|
233
|
+
} }
|
|
234
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_ng_container_0_Template(rf, ctx) { if (rf & 1) {
|
|
235
|
+
i0.ɵɵelementContainer(0);
|
|
236
|
+
} }
|
|
237
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
238
|
+
i0.ɵɵtemplate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_ng_container_0_Template, 1, 0, "ng-container", 50);
|
|
239
|
+
} if (rf & 2) {
|
|
240
|
+
const f_r11 = i0.ɵɵnextContext().$implicit;
|
|
241
|
+
i0.ɵɵnextContext(3);
|
|
242
|
+
const scopeRow_r10 = i0.ɵɵreference(3);
|
|
243
|
+
i0.ɵɵproperty("ngTemplateOutlet", scopeRow_r10)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, f_r11));
|
|
244
|
+
} }
|
|
245
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
246
|
+
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Conditional_0_Template, 1, 4, "ng-container");
|
|
247
|
+
} if (rf & 2) {
|
|
248
|
+
const f_r11 = ctx.$implicit;
|
|
249
|
+
i0.ɵɵconditional(f_r11.Group === "other" ? 0 : -1);
|
|
250
|
+
} }
|
|
251
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
252
|
+
i0.ɵɵelement(0, "div", 51);
|
|
253
|
+
i0.ɵɵelementStart(1, "div", 49);
|
|
254
|
+
i0.ɵɵtext(2, "Other fields");
|
|
255
|
+
i0.ɵɵelementEnd();
|
|
256
|
+
i0.ɵɵrepeaterCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_For_4_Template, 1, 1, null, null, _forTrack0);
|
|
257
|
+
} if (rf & 2) {
|
|
258
|
+
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
259
|
+
i0.ɵɵadvance(3);
|
|
260
|
+
i0.ɵɵrepeater(ctx_r0.FKSearchableFields);
|
|
261
|
+
} }
|
|
262
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
263
|
+
i0.ɵɵelementStart(0, "div", 48)(1, "div", 49);
|
|
264
|
+
i0.ɵɵtext(2, "Columns shown");
|
|
265
|
+
i0.ɵɵelementEnd();
|
|
266
|
+
i0.ɵɵrepeaterCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_For_4_Template, 1, 1, null, null, _forTrack0);
|
|
267
|
+
i0.ɵɵconditionalCreate(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Conditional_5_Template, 5, 0);
|
|
268
|
+
i0.ɵɵelementEnd();
|
|
269
|
+
} if (rf & 2) {
|
|
270
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
271
|
+
i0.ɵɵclassProp("mj-fk-scope-menu--bottom", ctx_r0.OpenAbove);
|
|
272
|
+
i0.ɵɵadvance(3);
|
|
273
|
+
i0.ɵɵrepeater(ctx_r0.FKSearchableFields);
|
|
274
|
+
i0.ɵɵadvance(2);
|
|
275
|
+
i0.ɵɵconditional(ctx_r0.FKHasOtherSearchableFields ? 5 : -1);
|
|
276
|
+
} }
|
|
277
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
278
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
279
|
+
i0.ɵɵelementStart(0, "button", 57);
|
|
280
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r14); const f_r13 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.MoveFKColumn($event, f_r13.FieldName, -1)); });
|
|
281
|
+
i0.ɵɵelement(1, "i", 58);
|
|
282
|
+
i0.ɵɵelementEnd();
|
|
283
|
+
i0.ɵɵelementStart(2, "button", 59);
|
|
284
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template_button_mousedown_2_listener($event) { i0.ɵɵrestoreView(_r14); const f_r13 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.MoveFKColumn($event, f_r13.FieldName, 1)); });
|
|
285
|
+
i0.ɵɵelement(3, "i", 60);
|
|
286
|
+
i0.ɵɵelementEnd();
|
|
287
|
+
} if (rf & 2) {
|
|
288
|
+
const f_r13 = i0.ɵɵnextContext().$implicit;
|
|
289
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
290
|
+
i0.ɵɵproperty("disabled", !ctx_r0.CanMoveFKColumnUp(f_r13.FieldName));
|
|
291
|
+
i0.ɵɵadvance(2);
|
|
292
|
+
i0.ɵɵproperty("disabled", !ctx_r0.CanMoveFKColumnDown(f_r13.FieldName));
|
|
293
|
+
} }
|
|
294
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
295
|
+
const _r15 = i0.ɵɵgetCurrentView();
|
|
296
|
+
i0.ɵɵelementStart(0, "button", 61);
|
|
297
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_7_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r15); const f_r13 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKColumnToggle($event, f_r13)); });
|
|
298
|
+
i0.ɵɵelement(1, "i", 62);
|
|
299
|
+
i0.ɵɵelementEnd();
|
|
300
|
+
} if (rf & 2) {
|
|
301
|
+
const f_r13 = i0.ɵɵnextContext().$implicit;
|
|
302
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
303
|
+
i0.ɵɵclassProp("mj-fk-col-toggle--on", ctx_r0.IsFKColumnVisible(f_r13));
|
|
304
|
+
i0.ɵɵproperty("title", ctx_r0.IsFKColumnVisible(f_r13) ? "Hide this column" : "Show as a column");
|
|
305
|
+
i0.ɵɵadvance();
|
|
306
|
+
i0.ɵɵclassProp("fa-eye", ctx_r0.IsFKColumnVisible(f_r13))("fa-eye-slash", !ctx_r0.IsFKColumnVisible(f_r13));
|
|
307
|
+
} }
|
|
308
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Template(rf, ctx) { if (rf & 1) {
|
|
309
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
310
|
+
i0.ɵɵelementStart(0, "div", 52);
|
|
311
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Template_div_mousedown_0_listener($event) { const f_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKScopeSelect($event, f_r13)); });
|
|
312
|
+
i0.ɵɵelementStart(1, "span", 53);
|
|
313
|
+
i0.ɵɵconditionalCreate(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_2_Template, 4, 2);
|
|
314
|
+
i0.ɵɵelementEnd();
|
|
315
|
+
i0.ɵɵelement(3, "i");
|
|
316
|
+
i0.ɵɵelementStart(4, "span", 54);
|
|
317
|
+
i0.ɵɵtext(5);
|
|
318
|
+
i0.ɵɵelementEnd();
|
|
319
|
+
i0.ɵɵelementStart(6, "span", 55);
|
|
320
|
+
i0.ɵɵconditionalCreate(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Conditional_7_Template, 2, 7, "button", 56);
|
|
321
|
+
i0.ɵɵelementEnd()();
|
|
322
|
+
} if (rf & 2) {
|
|
323
|
+
const f_r13 = ctx.$implicit;
|
|
324
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
325
|
+
i0.ɵɵclassProp("mj-fk-scope-mi--on", ctx_r0.IsFKScopeActive(f_r13));
|
|
326
|
+
i0.ɵɵadvance(2);
|
|
327
|
+
i0.ɵɵconditional(f_r13.Group === "shown" ? 2 : -1);
|
|
328
|
+
i0.ɵɵadvance();
|
|
329
|
+
i0.ɵɵclassMap(f_r13.Icon + " mj-fk-scope-mi-icon");
|
|
330
|
+
i0.ɵɵadvance(2);
|
|
331
|
+
i0.ɵɵtextInterpolate(f_r13.Label);
|
|
332
|
+
i0.ɵɵadvance(2);
|
|
333
|
+
i0.ɵɵconditional(ctx_r0.CanToggleFKColumn(f_r13) ? 7 : -1);
|
|
334
|
+
} }
|
|
335
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
336
|
+
i0.ɵɵelement(0, "i", 70);
|
|
337
|
+
} if (rf & 2) {
|
|
338
|
+
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
339
|
+
i0.ɵɵclassMap(ctx_r0.FKSelectedSuggestion.Icon);
|
|
340
|
+
} }
|
|
341
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
342
|
+
i0.ɵɵelementStart(0, "span", 68);
|
|
136
343
|
i0.ɵɵtext(1);
|
|
137
344
|
i0.ɵɵelementEnd();
|
|
138
345
|
} if (rf & 2) {
|
|
139
|
-
const
|
|
346
|
+
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
140
347
|
i0.ɵɵadvance();
|
|
141
|
-
i0.ɵɵ
|
|
348
|
+
i0.ɵɵtextInterpolate(ctx_r0.FKSelectedSuggestion.ExtraColumns[0].Value);
|
|
142
349
|
} }
|
|
143
|
-
function
|
|
144
|
-
i0.ɵɵ
|
|
145
|
-
i0.ɵɵ
|
|
350
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
351
|
+
const _r16 = i0.ɵɵgetCurrentView();
|
|
352
|
+
i0.ɵɵelementStart(0, "div", 43)(1, "div", 63);
|
|
353
|
+
i0.ɵɵelement(2, "i", 64);
|
|
354
|
+
i0.ɵɵelementStart(3, "span");
|
|
355
|
+
i0.ɵɵtext(4, "Currently selected");
|
|
356
|
+
i0.ɵɵelementEnd()();
|
|
357
|
+
i0.ɵɵelementStart(5, "div", 65);
|
|
358
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template_div_mousedown_5_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKSelectItem(ctx_r0.FKSelectedSuggestion, $event)); });
|
|
359
|
+
i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_6_Template, 1, 2, "i", 66);
|
|
360
|
+
i0.ɵɵelement(7, "span", 67);
|
|
361
|
+
i0.ɵɵconditionalCreate(8, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Conditional_8_Template, 2, 1, "span", 68);
|
|
362
|
+
i0.ɵɵelementStart(9, "button", 69);
|
|
363
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template_button_mousedown_9_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKClearClick($event)); });
|
|
364
|
+
i0.ɵɵelement(10, "i", 40);
|
|
365
|
+
i0.ɵɵelementEnd()()();
|
|
366
|
+
} if (rf & 2) {
|
|
367
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
368
|
+
i0.ɵɵadvance(6);
|
|
369
|
+
i0.ɵɵconditional(ctx_r0.FKSelectedSuggestion.Icon ? 6 : -1);
|
|
370
|
+
i0.ɵɵadvance();
|
|
371
|
+
i0.ɵɵproperty("innerHTML", ctx_r0.FKSelectedSuggestion.HighlightedName, i0.ɵɵsanitizeHtml);
|
|
372
|
+
i0.ɵɵadvance();
|
|
373
|
+
i0.ɵɵconditional(ctx_r0.FKSelectedSuggestion.ExtraColumns.length && ctx_r0.FKSelectedSuggestion.ExtraColumns[0].Value ? 8 : -1);
|
|
374
|
+
} }
|
|
375
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
376
|
+
i0.ɵɵelementStart(0, "div", 44);
|
|
377
|
+
i0.ɵɵelement(1, "i", 71);
|
|
378
|
+
i0.ɵɵelementStart(2, "span");
|
|
379
|
+
i0.ɵɵtext(3, "Searching\u2026");
|
|
380
|
+
i0.ɵɵelementEnd()();
|
|
381
|
+
} }
|
|
382
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
383
|
+
i0.ɵɵelementStart(0, "div", 45);
|
|
384
|
+
i0.ɵɵelement(1, "i", 72);
|
|
385
|
+
i0.ɵɵelementStart(2, "span");
|
|
386
|
+
i0.ɵɵtext(3, "No matches");
|
|
387
|
+
i0.ɵɵelementEnd()();
|
|
388
|
+
} }
|
|
389
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
390
|
+
i0.ɵɵelement(0, "div", 75);
|
|
391
|
+
} }
|
|
392
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
393
|
+
const _r17 = i0.ɵɵgetCurrentView();
|
|
394
|
+
i0.ɵɵelementStart(0, "div", 78);
|
|
395
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template_div_mousedown_0_listener($event) { const col_r18 = i0.ɵɵrestoreView(_r17).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnFKHeaderSort($event, col_r18)); });
|
|
396
|
+
i0.ɵɵelementStart(1, "span", 79);
|
|
397
|
+
i0.ɵɵtext(2);
|
|
398
|
+
i0.ɵɵelementEnd();
|
|
399
|
+
i0.ɵɵelement(3, "i");
|
|
400
|
+
i0.ɵɵelementStart(4, "span", 80);
|
|
401
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template_span_mousedown_4_listener($event) { const col_r18 = i0.ɵɵrestoreView(_r17).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnFKColResizeStart($event, col_r18)); });
|
|
402
|
+
i0.ɵɵelementEnd()();
|
|
403
|
+
} if (rf & 2) {
|
|
404
|
+
const col_r18 = ctx.$implicit;
|
|
405
|
+
const ɵ$index_216_r19 = ctx.$index;
|
|
406
|
+
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
407
|
+
i0.ɵɵproperty("title", "Click to sort by " + ctx_r0.FKColumnHeaders[ɵ$index_216_r19]);
|
|
408
|
+
i0.ɵɵadvance(2);
|
|
409
|
+
i0.ɵɵtextInterpolate(ctx_r0.FKColumnHeaders[ɵ$index_216_r19]);
|
|
410
|
+
i0.ɵɵadvance();
|
|
411
|
+
i0.ɵɵclassMap(ctx_r0.FKSortIcon(col_r18));
|
|
412
|
+
} }
|
|
413
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
414
|
+
i0.ɵɵelement(0, "i");
|
|
415
|
+
} if (rf & 2) {
|
|
416
|
+
const suggestion_r21 = i0.ɵɵnextContext(2).$implicit;
|
|
417
|
+
i0.ɵɵclassMap(suggestion_r21.Icon);
|
|
418
|
+
} }
|
|
419
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
420
|
+
i0.ɵɵelementStart(0, "div", 82);
|
|
421
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Conditional_1_Template, 1, 2, "i", 83);
|
|
422
|
+
i0.ɵɵelementEnd();
|
|
423
|
+
} if (rf & 2) {
|
|
424
|
+
const suggestion_r21 = i0.ɵɵnextContext().$implicit;
|
|
425
|
+
i0.ɵɵadvance();
|
|
426
|
+
i0.ɵɵconditional(suggestion_r21.Icon ? 1 : -1);
|
|
427
|
+
} }
|
|
428
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
429
|
+
i0.ɵɵelement(0, "i", 87);
|
|
430
|
+
} }
|
|
431
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
432
|
+
i0.ɵɵelementStart(0, "div", 86);
|
|
433
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Conditional_1_Template, 1, 0, "i", 87);
|
|
434
|
+
i0.ɵɵelement(2, "span", 88);
|
|
435
|
+
i0.ɵɵelementEnd();
|
|
436
|
+
} if (rf & 2) {
|
|
437
|
+
const ctx_r22 = i0.ɵɵnextContext();
|
|
438
|
+
const col_r24 = ctx_r22.$implicit;
|
|
439
|
+
const ɵ$index_235_r25 = ctx_r22.$index;
|
|
440
|
+
const ɵ$count_235_r26 = ctx_r22.$count;
|
|
441
|
+
const suggestion_r21 = i0.ɵɵnextContext().$implicit;
|
|
442
|
+
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
443
|
+
i0.ɵɵclassProp("mj-fk-cell--fill", ctx_r0.FKColumnFillsTrack(col_r24, ɵ$index_235_r25 === ɵ$count_235_r26 - 1));
|
|
444
|
+
i0.ɵɵadvance();
|
|
445
|
+
i0.ɵɵconditional(ctx_r0.IsFKRowSelected(suggestion_r21) ? 1 : -1);
|
|
446
|
+
i0.ɵɵadvance();
|
|
447
|
+
i0.ɵɵproperty("innerHTML", suggestion_r21.HighlightedName, i0.ɵɵsanitizeHtml);
|
|
448
|
+
} }
|
|
449
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
450
|
+
i0.ɵɵelementStart(0, "div", 89);
|
|
451
|
+
i0.ɵɵelement(1, "span", 88);
|
|
452
|
+
i0.ɵɵelementEnd();
|
|
453
|
+
} if (rf & 2) {
|
|
454
|
+
let tmp_30_0;
|
|
455
|
+
let tmp_31_0;
|
|
456
|
+
const ctx_r22 = i0.ɵɵnextContext();
|
|
457
|
+
const col_r24 = ctx_r22.$implicit;
|
|
458
|
+
const ɵ$index_235_r25 = ctx_r22.$index;
|
|
459
|
+
const ɵ$count_235_r26 = ctx_r22.$count;
|
|
460
|
+
const suggestion_r21 = i0.ɵɵnextContext().$implicit;
|
|
461
|
+
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
462
|
+
i0.ɵɵclassProp("mj-fk-cell--fill", ctx_r0.FKColumnFillsTrack(col_r24, ɵ$index_235_r25 === ɵ$count_235_r26 - 1));
|
|
463
|
+
i0.ɵɵproperty("title", ((tmp_30_0 = ctx_r0.FKCellFor(suggestion_r21, col_r24)) == null ? null : tmp_30_0.Value) || "");
|
|
464
|
+
i0.ɵɵadvance();
|
|
465
|
+
i0.ɵɵproperty("innerHTML", ((tmp_31_0 = ctx_r0.FKCellFor(suggestion_r21, col_r24)) == null ? null : tmp_31_0.HighlightedValue) || "", i0.ɵɵsanitizeHtml);
|
|
466
|
+
} }
|
|
467
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
468
|
+
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_0_Template, 3, 4, "div", 84)(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Conditional_1_Template, 2, 4, "div", 85);
|
|
469
|
+
} if (rf & 2) {
|
|
470
|
+
const col_r24 = ctx.$implicit;
|
|
471
|
+
const ctx_r0 = i0.ɵɵnextContext(7);
|
|
472
|
+
i0.ɵɵconditional(col_r24 === ctx_r0.FKNameField ? 0 : 1);
|
|
473
|
+
} }
|
|
474
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template(rf, ctx) { if (rf & 1) {
|
|
475
|
+
const _r20 = i0.ɵɵgetCurrentView();
|
|
476
|
+
i0.ɵɵelementStart(0, "div", 81);
|
|
477
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template_div_mousedown_0_listener($event) { const suggestion_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnFKSelectItem(suggestion_r21, $event)); })("mouseenter", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template_div_mouseenter_0_listener() { const ɵ$index_226_r22 = i0.ɵɵrestoreView(_r20).$index; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.FKActiveIndex = ɵ$index_226_r22); });
|
|
478
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Conditional_1_Template, 2, 1, "div", 82);
|
|
479
|
+
i0.ɵɵrepeaterCreate(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_For_3_Template, 2, 1, null, null, i0.ɵɵrepeaterTrackByIdentity);
|
|
480
|
+
i0.ɵɵelementEnd();
|
|
481
|
+
} if (rf & 2) {
|
|
482
|
+
const suggestion_r21 = ctx.$implicit;
|
|
483
|
+
const ɵ$index_226_r22 = ctx.$index;
|
|
484
|
+
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
485
|
+
i0.ɵɵclassProp("mj-fk-grid-row--active", ɵ$index_226_r22 === ctx_r0.FKActiveIndex)("mj-fk-grid-row--selected", ctx_r0.IsFKRowSelected(suggestion_r21));
|
|
486
|
+
i0.ɵɵadvance();
|
|
487
|
+
i0.ɵɵconditional(ctx_r0.FKHasIconColumn ? 1 : -1);
|
|
488
|
+
i0.ɵɵadvance();
|
|
489
|
+
i0.ɵɵrepeater(ctx_r0.FKColumnFields);
|
|
490
|
+
} }
|
|
491
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
492
|
+
i0.ɵɵelementStart(0, "div", 46)(1, "div", 73)(2, "div", 74);
|
|
493
|
+
i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Conditional_3_Template, 1, 0, "div", 75);
|
|
494
|
+
i0.ɵɵrepeaterCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_5_Template, 5, 4, "div", 76, i0.ɵɵrepeaterTrackByIdentity);
|
|
495
|
+
i0.ɵɵelementEnd();
|
|
496
|
+
i0.ɵɵrepeaterCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_For_7_Template, 4, 5, "div", 77, _forTrack1);
|
|
497
|
+
i0.ɵɵelementEnd()();
|
|
498
|
+
} if (rf & 2) {
|
|
499
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
500
|
+
i0.ɵɵadvance();
|
|
501
|
+
i0.ɵɵstyleProp("grid-template-columns", ctx_r0.FKGridTemplateColumns);
|
|
502
|
+
i0.ɵɵadvance(2);
|
|
503
|
+
i0.ɵɵconditional(ctx_r0.FKHasIconColumn ? 3 : -1);
|
|
504
|
+
i0.ɵɵadvance();
|
|
505
|
+
i0.ɵɵrepeater(ctx_r0.FKColumnFields);
|
|
506
|
+
i0.ɵɵadvance(2);
|
|
507
|
+
i0.ɵɵrepeater(ctx_r0.FKSuggestions);
|
|
508
|
+
} }
|
|
509
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
510
|
+
const _r27 = i0.ɵɵgetCurrentView();
|
|
511
|
+
i0.ɵɵelementStart(0, "button", 90);
|
|
512
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_8_Template_button_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.OnFKCreateNew($event)); });
|
|
513
|
+
i0.ɵɵelement(1, "i", 91);
|
|
514
|
+
i0.ɵɵelementStart(2, "span", 92);
|
|
515
|
+
i0.ɵɵtext(3);
|
|
516
|
+
i0.ɵɵelementEnd()();
|
|
517
|
+
} if (rf & 2) {
|
|
518
|
+
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
519
|
+
i0.ɵɵproperty("title", ctx_r0.FKCreateLabel);
|
|
520
|
+
i0.ɵɵadvance(3);
|
|
521
|
+
i0.ɵɵtextInterpolate(ctx_r0.FKCreateLabel);
|
|
522
|
+
} }
|
|
523
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
524
|
+
i0.ɵɵelementStart(0, "div", 41);
|
|
525
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_1_Template, 6, 3, "div", 42);
|
|
526
|
+
i0.ɵɵtemplate(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_ng_template_2_Template, 8, 7, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
|
|
527
|
+
i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_4_Template, 11, 3, "div", 43);
|
|
528
|
+
i0.ɵɵconditionalCreate(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_5_Template, 4, 0, "div", 44);
|
|
529
|
+
i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_6_Template, 4, 0, "div", 45);
|
|
530
|
+
i0.ɵɵconditionalCreate(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_7_Template, 8, 3, "div", 46);
|
|
531
|
+
i0.ɵɵconditionalCreate(8, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Conditional_8_Template, 4, 2, "button", 47);
|
|
146
532
|
i0.ɵɵelementEnd();
|
|
147
533
|
} if (rf & 2) {
|
|
148
534
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
149
|
-
i0.ɵɵclassProp("mj-fk-dropdown--above", ctx_r0.OpenAbove);
|
|
535
|
+
i0.ɵɵclassProp("mj-fk-dropdown--above", ctx_r0.OpenAbove)("mj-fk-dropdown--scope-open", ctx_r0.FKShowScopeMenu);
|
|
150
536
|
i0.ɵɵproperty("ngStyle", ctx_r0.DropdownPositionStyle);
|
|
151
537
|
i0.ɵɵadvance();
|
|
152
|
-
i0.ɵɵ
|
|
538
|
+
i0.ɵɵconditional(ctx_r0.FKShowScopeMenu ? 1 : -1);
|
|
539
|
+
i0.ɵɵadvance(3);
|
|
540
|
+
i0.ɵɵconditional(ctx_r0.FKSelectedSuggestion && !ctx_r0.FKLoading ? 4 : -1);
|
|
541
|
+
i0.ɵɵadvance();
|
|
542
|
+
i0.ɵɵconditional(ctx_r0.FKLoading ? 5 : -1);
|
|
543
|
+
i0.ɵɵadvance();
|
|
544
|
+
i0.ɵɵconditional(!ctx_r0.FKLoading && ctx_r0.FKNoMatches ? 6 : -1);
|
|
545
|
+
i0.ɵɵadvance();
|
|
546
|
+
i0.ɵɵconditional(!ctx_r0.FKLoading && ctx_r0.FKSuggestions.length > 0 ? 7 : -1);
|
|
547
|
+
i0.ɵɵadvance();
|
|
548
|
+
i0.ɵɵconditional(ctx_r0.CanCreateFK ? 8 : -1);
|
|
153
549
|
} }
|
|
154
550
|
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
155
551
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
156
|
-
i0.ɵɵelementStart(0, "div",
|
|
157
|
-
i0.ɵɵ
|
|
552
|
+
i0.ɵɵelementStart(0, "div", 28);
|
|
553
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_1_Template, 1, 0, "i", 29);
|
|
554
|
+
i0.ɵɵelementStart(2, "input", 30);
|
|
555
|
+
i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_input_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKInput($event)); })("focus", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_focus_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKFocus($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_blur_2_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKBlur()); })("keydown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template_input_keydown_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnFKKeydown($event)); });
|
|
158
556
|
i0.ɵɵelementEnd();
|
|
159
|
-
i0.ɵɵconditionalCreate(
|
|
160
|
-
i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template,
|
|
557
|
+
i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_3_Template, 5, 8, "button", 31);
|
|
558
|
+
i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_4_Template, 2, 0, "button", 32)(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_5_Template, 1, 0, "i", 33);
|
|
559
|
+
i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Conditional_6_Template, 9, 11, "div", 34);
|
|
161
560
|
i0.ɵɵelementEnd();
|
|
162
561
|
} if (rf & 2) {
|
|
163
562
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
164
|
-
i0.ɵɵclassProp("mj-fk-search--matched", ctx_r0.
|
|
563
|
+
i0.ɵɵclassProp("mj-fk-search--matched", ctx_r0.FKHasLinkedValue)("mj-fk-search--scoped", ctx_r0.FKFocused && ctx_r0.FKSearchableFields.length > 1);
|
|
564
|
+
i0.ɵɵadvance();
|
|
565
|
+
i0.ɵɵconditional(ctx_r0.FKHasLinkedValue && !(ctx_r0.FKFocused && ctx_r0.FKSearchableFields.length > 1) ? 1 : -1);
|
|
165
566
|
i0.ɵɵadvance();
|
|
567
|
+
i0.ɵɵclassProp("mj-forms-field-input--linked", ctx_r0.FKHasLinkedValue);
|
|
166
568
|
i0.ɵɵproperty("value", ctx_r0.FKSearchText);
|
|
167
569
|
i0.ɵɵadvance();
|
|
168
|
-
i0.ɵɵconditional(ctx_r0.
|
|
570
|
+
i0.ɵɵconditional(ctx_r0.FKFocused && ctx_r0.FKSearchableFields.length > 1 ? 3 : -1);
|
|
571
|
+
i0.ɵɵadvance();
|
|
572
|
+
i0.ɵɵconditional(ctx_r0.FKSearchText ? 4 : 5);
|
|
169
573
|
i0.ɵɵadvance(2);
|
|
170
|
-
i0.ɵɵconditional(ctx_r0.ShowFKDropdown
|
|
574
|
+
i0.ɵɵconditional(ctx_r0.ShowFKDropdown ? 6 : -1);
|
|
575
|
+
} }
|
|
576
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
577
|
+
const _r28 = i0.ɵɵgetCurrentView();
|
|
578
|
+
i0.ɵɵelementStart(0, "mj-code-editor", 93);
|
|
579
|
+
i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template_mj_code_editor_change_0_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnCodeEditorChange($event)); });
|
|
580
|
+
i0.ɵɵelementEnd();
|
|
581
|
+
} if (rf & 2) {
|
|
582
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
583
|
+
i0.ɵɵproperty("value", ctx_r0.FormatValue())("language", ctx_r0.CodeEditorLanguage);
|
|
171
584
|
} }
|
|
172
|
-
function
|
|
173
|
-
const
|
|
174
|
-
i0.ɵɵelementStart(0, "input",
|
|
175
|
-
i0.ɵɵlistener("input", function
|
|
585
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_0_Template(rf, ctx) { if (rf & 1) {
|
|
586
|
+
const _r29 = i0.ɵɵgetCurrentView();
|
|
587
|
+
i0.ɵɵelementStart(0, "input", 98);
|
|
588
|
+
i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_0_Template_input_input_0_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
|
|
176
589
|
i0.ɵɵelementEnd();
|
|
177
590
|
} if (rf & 2) {
|
|
178
591
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
179
592
|
i0.ɵɵproperty("value", ctx_r0.FormatValue());
|
|
180
593
|
} }
|
|
181
|
-
function
|
|
182
|
-
const
|
|
183
|
-
i0.ɵɵelementStart(0, "textarea",
|
|
184
|
-
i0.ɵɵlistener("input", function
|
|
594
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_1_Template(rf, ctx) { if (rf & 1) {
|
|
595
|
+
const _r30 = i0.ɵɵgetCurrentView();
|
|
596
|
+
i0.ɵɵelementStart(0, "textarea", 99);
|
|
597
|
+
i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_1_Template_textarea_input_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
|
|
185
598
|
i0.ɵɵelementEnd();
|
|
186
599
|
} if (rf & 2) {
|
|
187
600
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
188
601
|
i0.ɵɵproperty("value", ctx_r0.FormatValue());
|
|
189
602
|
} }
|
|
190
|
-
function
|
|
191
|
-
const
|
|
192
|
-
i0.ɵɵelementStart(0, "input",
|
|
193
|
-
i0.ɵɵlistener("change", function
|
|
603
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_2_Template(rf, ctx) { if (rf & 1) {
|
|
604
|
+
const _r31 = i0.ɵɵgetCurrentView();
|
|
605
|
+
i0.ɵɵelementStart(0, "input", 100);
|
|
606
|
+
i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_2_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnNumberChange($event)); });
|
|
194
607
|
i0.ɵɵelementEnd();
|
|
195
608
|
} if (rf & 2) {
|
|
196
609
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
197
610
|
i0.ɵɵproperty("value", ctx_r0.Value);
|
|
198
611
|
} }
|
|
199
|
-
function
|
|
200
|
-
const
|
|
201
|
-
i0.ɵɵelementStart(0, "input",
|
|
202
|
-
i0.ɵɵlistener("change", function
|
|
612
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_3_Template(rf, ctx) { if (rf & 1) {
|
|
613
|
+
const _r32 = i0.ɵɵgetCurrentView();
|
|
614
|
+
i0.ɵɵelementStart(0, "input", 101);
|
|
615
|
+
i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_3_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnDateChange($event)); });
|
|
203
616
|
i0.ɵɵelementEnd();
|
|
204
617
|
} if (rf & 2) {
|
|
205
618
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
206
619
|
i0.ɵɵproperty("value", ctx_r0.DateInputValue);
|
|
207
620
|
} }
|
|
208
|
-
function
|
|
209
|
-
const
|
|
210
|
-
i0.ɵɵelementStart(0, "div",
|
|
211
|
-
i0.ɵɵlistener("change", function
|
|
621
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_4_Template(rf, ctx) { if (rf & 1) {
|
|
622
|
+
const _r33 = i0.ɵɵgetCurrentView();
|
|
623
|
+
i0.ɵɵelementStart(0, "div", 19)(1, "input", 102);
|
|
624
|
+
i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_4_Template_input_change_1_listener($event) { i0.ɵɵrestoreView(_r33); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnCheckboxChange($event)); });
|
|
212
625
|
i0.ɵɵelementEnd()();
|
|
213
626
|
} if (rf & 2) {
|
|
214
627
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
215
628
|
i0.ɵɵadvance();
|
|
216
629
|
i0.ɵɵproperty("checked", !!ctx_r0.Value);
|
|
217
630
|
} }
|
|
218
|
-
function
|
|
219
|
-
const
|
|
220
|
-
i0.ɵɵelementStart(0, "div",
|
|
221
|
-
i0.ɵɵlistener("mousedown", function
|
|
631
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
632
|
+
const _r35 = i0.ɵɵgetCurrentView();
|
|
633
|
+
i0.ɵɵelementStart(0, "div", 109);
|
|
634
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_For_2_Template_div_mousedown_0_listener($event) { const option_r36 = i0.ɵɵrestoreView(_r35).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnSelectOptionClick(option_r36, $event)); });
|
|
222
635
|
i0.ɵɵtext(1);
|
|
223
636
|
i0.ɵɵelementEnd();
|
|
224
637
|
} if (rf & 2) {
|
|
225
|
-
const
|
|
638
|
+
const option_r36 = ctx.$implicit;
|
|
226
639
|
const ctx_r0 = i0.ɵɵnextContext(6);
|
|
227
|
-
i0.ɵɵclassProp("mj-fk-option--selected", ctx_r0.FormatValue() ===
|
|
640
|
+
i0.ɵɵclassProp("mj-fk-option--selected", ctx_r0.FormatValue() === option_r36);
|
|
228
641
|
i0.ɵɵadvance();
|
|
229
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
642
|
+
i0.ɵɵtextInterpolate1(" ", option_r36, " ");
|
|
230
643
|
} }
|
|
231
|
-
function
|
|
232
|
-
i0.ɵɵelementStart(0, "div",
|
|
233
|
-
i0.ɵɵrepeaterCreate(1,
|
|
644
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
645
|
+
i0.ɵɵelementStart(0, "div", 107);
|
|
646
|
+
i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_For_2_Template, 2, 3, "div", 108, i0.ɵɵrepeaterTrackByIdentity);
|
|
234
647
|
i0.ɵɵelementEnd();
|
|
235
648
|
} if (rf & 2) {
|
|
236
649
|
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
@@ -239,16 +652,16 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_C
|
|
|
239
652
|
i0.ɵɵadvance();
|
|
240
653
|
i0.ɵɵrepeater(ctx_r0.PossibleValues);
|
|
241
654
|
} }
|
|
242
|
-
function
|
|
243
|
-
const
|
|
244
|
-
i0.ɵɵelementStart(0, "div",
|
|
245
|
-
i0.ɵɵlistener("click", function
|
|
246
|
-
i0.ɵɵelementStart(1, "span",
|
|
655
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template(rf, ctx) { if (rf & 1) {
|
|
656
|
+
const _r34 = i0.ɵɵgetCurrentView();
|
|
657
|
+
i0.ɵɵelementStart(0, "div", 103);
|
|
658
|
+
i0.ɵɵlistener("click", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnSelectTriggerClick($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template_div_blur_0_listener() { i0.ɵɵrestoreView(_r34); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnSelectTriggerBlur()); });
|
|
659
|
+
i0.ɵɵelementStart(1, "span", 104);
|
|
247
660
|
i0.ɵɵtext(2);
|
|
248
661
|
i0.ɵɵelementEnd();
|
|
249
|
-
i0.ɵɵelement(3, "i",
|
|
662
|
+
i0.ɵɵelement(3, "i", 105);
|
|
250
663
|
i0.ɵɵelementEnd();
|
|
251
|
-
i0.ɵɵconditionalCreate(4,
|
|
664
|
+
i0.ɵɵconditionalCreate(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Conditional_4_Template, 3, 3, "div", 106);
|
|
252
665
|
} if (rf & 2) {
|
|
253
666
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
254
667
|
i0.ɵɵadvance();
|
|
@@ -260,20 +673,20 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_5_T
|
|
|
260
673
|
i0.ɵɵadvance();
|
|
261
674
|
i0.ɵɵconditional(ctx_r0.ShowSelectDropdown && ctx_r0.PossibleValues.length > 0 ? 4 : -1);
|
|
262
675
|
} }
|
|
263
|
-
function
|
|
264
|
-
const
|
|
265
|
-
i0.ɵɵelementStart(0, "div",
|
|
266
|
-
i0.ɵɵlistener("mousedown", function
|
|
676
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
677
|
+
const _r38 = i0.ɵɵgetCurrentView();
|
|
678
|
+
i0.ɵɵelementStart(0, "div", 109);
|
|
679
|
+
i0.ɵɵlistener("mousedown", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_For_2_Template_div_mousedown_0_listener($event) { const option_r39 = i0.ɵɵrestoreView(_r38).$implicit; const ctx_r0 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r0.OnValueListSelect(option_r39, $event)); });
|
|
267
680
|
i0.ɵɵtext(1);
|
|
268
681
|
i0.ɵɵelementEnd();
|
|
269
682
|
} if (rf & 2) {
|
|
270
|
-
const
|
|
683
|
+
const option_r39 = ctx.$implicit;
|
|
271
684
|
i0.ɵɵadvance();
|
|
272
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
685
|
+
i0.ɵɵtextInterpolate1(" ", option_r39, " ");
|
|
273
686
|
} }
|
|
274
|
-
function
|
|
275
|
-
i0.ɵɵelementStart(0, "div",
|
|
276
|
-
i0.ɵɵrepeaterCreate(1,
|
|
687
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
688
|
+
i0.ɵɵelementStart(0, "div", 107);
|
|
689
|
+
i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_For_2_Template, 2, 1, "div", 111, i0.ɵɵrepeaterTrackByIdentity);
|
|
277
690
|
i0.ɵɵelementEnd();
|
|
278
691
|
} if (rf & 2) {
|
|
279
692
|
const ctx_r0 = i0.ɵɵnextContext(5);
|
|
@@ -282,13 +695,13 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_C
|
|
|
282
695
|
i0.ɵɵadvance();
|
|
283
696
|
i0.ɵɵrepeater(ctx_r0.FilteredPossibleValues);
|
|
284
697
|
} }
|
|
285
|
-
function
|
|
286
|
-
const
|
|
287
|
-
i0.ɵɵelementStart(0, "div",
|
|
288
|
-
i0.ɵɵlistener("input", function
|
|
698
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template(rf, ctx) { if (rf & 1) {
|
|
699
|
+
const _r37 = i0.ɵɵgetCurrentView();
|
|
700
|
+
i0.ɵɵelementStart(0, "div", 28)(1, "input", 110);
|
|
701
|
+
i0.ɵɵlistener("input", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template_input_input_1_listener($event) { i0.ɵɵrestoreView(_r37); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListInput($event)); })("focus", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template_input_focus_1_listener($event) { i0.ɵɵrestoreView(_r37); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListFocus($event)); })("blur", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template_input_blur_1_listener() { i0.ɵɵrestoreView(_r37); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnValueListBlur()); });
|
|
289
702
|
i0.ɵɵelementEnd();
|
|
290
|
-
i0.ɵɵelement(2, "i",
|
|
291
|
-
i0.ɵɵconditionalCreate(3,
|
|
703
|
+
i0.ɵɵelement(2, "i", 33);
|
|
704
|
+
i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Conditional_3_Template, 3, 3, "div", 106);
|
|
292
705
|
i0.ɵɵelementEnd();
|
|
293
706
|
} if (rf & 2) {
|
|
294
707
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
@@ -297,56 +710,56 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Case_6_T
|
|
|
297
710
|
i0.ɵɵadvance(2);
|
|
298
711
|
i0.ɵɵconditional(ctx_r0.ShowValueListDropdown && ctx_r0.FilteredPossibleValues.length > 0 ? 3 : -1);
|
|
299
712
|
} }
|
|
300
|
-
function
|
|
301
|
-
const
|
|
302
|
-
i0.ɵɵelementStart(0, "input",
|
|
303
|
-
i0.ɵɵlistener("change", function
|
|
713
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_7_Template(rf, ctx) { if (rf & 1) {
|
|
714
|
+
const _r40 = i0.ɵɵgetCurrentView();
|
|
715
|
+
i0.ɵɵelementStart(0, "input", 112);
|
|
716
|
+
i0.ɵɵlistener("change", function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_7_Template_input_change_0_listener($event) { i0.ɵɵrestoreView(_r40); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnInputChange($event)); });
|
|
304
717
|
i0.ɵɵelementEnd();
|
|
305
718
|
} if (rf & 2) {
|
|
306
719
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
307
720
|
i0.ɵɵproperty("value", ctx_r0.FormatValue());
|
|
308
721
|
} }
|
|
309
|
-
function
|
|
310
|
-
i0.ɵɵconditionalCreate(0,
|
|
722
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
723
|
+
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_0_Template, 1, 1, "input", 94)(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_1_Template, 1, 1, "textarea", 95)(2, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_2_Template, 1, 1, "input", 96)(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_3_Template, 1, 1, "input", 97)(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_4_Template, 2, 1, "div", 19)(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_5_Template, 5, 6)(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_6_Template, 4, 2, "div", 28)(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Case_7_Template, 1, 1, "input", 94);
|
|
311
724
|
} if (rf & 2) {
|
|
312
725
|
let tmp_3_0;
|
|
313
726
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
314
727
|
i0.ɵɵconditional((tmp_3_0 = ctx_r0.Type) === "textbox" ? 0 : tmp_3_0 === "textarea" ? 1 : tmp_3_0 === "number" ? 2 : tmp_3_0 === "datepicker" ? 3 : tmp_3_0 === "checkbox" ? 4 : tmp_3_0 === "select" ? 5 : tmp_3_0 === "autocomplete" ? 6 : 7);
|
|
315
728
|
} }
|
|
316
|
-
function
|
|
317
|
-
i0.ɵɵelementStart(0, "div",
|
|
318
|
-
i0.ɵɵelement(1, "i",
|
|
729
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
730
|
+
i0.ɵɵelementStart(0, "div", 113);
|
|
731
|
+
i0.ɵɵelement(1, "i", 114);
|
|
319
732
|
i0.ɵɵelementStart(2, "span");
|
|
320
733
|
i0.ɵɵtext(3);
|
|
321
734
|
i0.ɵɵelementEnd()();
|
|
322
735
|
} if (rf & 2) {
|
|
323
|
-
const
|
|
736
|
+
const error_r41 = ctx.$implicit;
|
|
324
737
|
i0.ɵɵadvance(3);
|
|
325
|
-
i0.ɵɵtextInterpolate(
|
|
738
|
+
i0.ɵɵtextInterpolate(error_r41.Message);
|
|
326
739
|
} }
|
|
327
|
-
function
|
|
328
|
-
i0.ɵɵelementStart(0, "div",
|
|
329
|
-
i0.ɵɵrepeaterCreate(1,
|
|
740
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
741
|
+
i0.ɵɵelementStart(0, "div", 26);
|
|
742
|
+
i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_For_2_Template, 4, 1, "div", 113, _forTrack2);
|
|
330
743
|
i0.ɵɵelementEnd();
|
|
331
744
|
} if (rf & 2) {
|
|
332
745
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
333
746
|
i0.ɵɵadvance();
|
|
334
747
|
i0.ɵɵrepeater(ctx_r0.DisplayErrors);
|
|
335
748
|
} }
|
|
336
|
-
function
|
|
337
|
-
i0.ɵɵelementStart(0, "div",
|
|
338
|
-
i0.ɵɵelement(1, "i",
|
|
749
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
750
|
+
i0.ɵɵelementStart(0, "div", 113);
|
|
751
|
+
i0.ɵɵelement(1, "i", 115);
|
|
339
752
|
i0.ɵɵelementStart(2, "span");
|
|
340
753
|
i0.ɵɵtext(3);
|
|
341
754
|
i0.ɵɵelementEnd()();
|
|
342
755
|
} if (rf & 2) {
|
|
343
|
-
const
|
|
756
|
+
const warning_r42 = ctx.$implicit;
|
|
344
757
|
i0.ɵɵadvance(3);
|
|
345
|
-
i0.ɵɵtextInterpolate(
|
|
758
|
+
i0.ɵɵtextInterpolate(warning_r42.Message);
|
|
346
759
|
} }
|
|
347
|
-
function
|
|
348
|
-
i0.ɵɵelementStart(0, "div",
|
|
349
|
-
i0.ɵɵrepeaterCreate(1,
|
|
760
|
+
function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
761
|
+
i0.ɵɵelementStart(0, "div", 27);
|
|
762
|
+
i0.ɵɵrepeaterCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_For_2_Template, 4, 1, "div", 113, _forTrack2);
|
|
350
763
|
i0.ɵɵelementEnd();
|
|
351
764
|
} if (rf & 2) {
|
|
352
765
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
@@ -354,13 +767,13 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template
|
|
|
354
767
|
i0.ɵɵrepeater(ctx_r0.DisplayWarnings);
|
|
355
768
|
} }
|
|
356
769
|
function MjFormFieldComponent_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
357
|
-
i0.ɵɵelementStart(0, "div",
|
|
358
|
-
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_1_Template, 1, 1, "label",
|
|
359
|
-
i0.ɵɵelementStart(2, "div",
|
|
360
|
-
i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template,
|
|
770
|
+
i0.ɵɵelementStart(0, "div", 23);
|
|
771
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_1_Template, 1, 1, "label", 4);
|
|
772
|
+
i0.ɵɵelementStart(2, "div", 5);
|
|
773
|
+
i0.ɵɵconditionalCreate(3, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_3_Template, 7, 11, "div", 24)(4, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_4_Template, 1, 2, "mj-code-editor", 25)(5, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_5_Template, 8, 1);
|
|
361
774
|
i0.ɵɵelementEnd();
|
|
362
|
-
i0.ɵɵconditionalCreate(
|
|
363
|
-
i0.ɵɵconditionalCreate(
|
|
775
|
+
i0.ɵɵconditionalCreate(6, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_6_Template, 3, 0, "div", 26);
|
|
776
|
+
i0.ɵɵconditionalCreate(7, MjFormFieldComponent_Conditional_0_Conditional_1_Conditional_7_Template, 3, 0, "div", 27);
|
|
364
777
|
i0.ɵɵelementEnd();
|
|
365
778
|
} if (rf & 2) {
|
|
366
779
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -368,15 +781,15 @@ function MjFormFieldComponent_Conditional_0_Conditional_1_Template(rf, ctx) { if
|
|
|
368
781
|
i0.ɵɵadvance();
|
|
369
782
|
i0.ɵɵconditional(ctx_r0.ShowLabel ? 1 : -1);
|
|
370
783
|
i0.ɵɵadvance(2);
|
|
371
|
-
i0.ɵɵconditional(ctx_r0.HasRelatedEntity ? 3 : 4);
|
|
372
|
-
i0.ɵɵadvance(
|
|
373
|
-
i0.ɵɵconditional(ctx_r0.DisplayErrors.length > 0 ?
|
|
784
|
+
i0.ɵɵconditional(ctx_r0.HasRelatedEntity ? 3 : ctx_r0.EditRichTextMode !== "plain" ? 4 : 5);
|
|
785
|
+
i0.ɵɵadvance(3);
|
|
786
|
+
i0.ɵɵconditional(ctx_r0.DisplayErrors.length > 0 ? 6 : -1);
|
|
374
787
|
i0.ɵɵadvance();
|
|
375
|
-
i0.ɵɵconditional(ctx_r0.DisplayWarnings.length > 0 ?
|
|
788
|
+
i0.ɵɵconditional(ctx_r0.DisplayWarnings.length > 0 ? 7 : -1);
|
|
376
789
|
} }
|
|
377
790
|
function MjFormFieldComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
378
|
-
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Template, 5, 6, "div",
|
|
379
|
-
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Template,
|
|
791
|
+
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Conditional_0_Template, 5, 6, "div", 1);
|
|
792
|
+
i0.ɵɵconditionalCreate(1, MjFormFieldComponent_Conditional_0_Conditional_1_Template, 8, 12, "div", 2);
|
|
380
793
|
} if (rf & 2) {
|
|
381
794
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
382
795
|
i0.ɵɵconditional((!ctx_r0.EditMode || ctx_r0.IsFieldReadOnly) && !ctx_r0.ShouldHideField ? 0 : -1);
|
|
@@ -412,6 +825,8 @@ function MjFormFieldComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
|
412
825
|
*/
|
|
413
826
|
export class MjFormFieldComponent extends BaseAngularComponent {
|
|
414
827
|
cdr = inject(ChangeDetectorRef);
|
|
828
|
+
renderer = inject(Renderer2);
|
|
829
|
+
hostRef = inject((ElementRef));
|
|
415
830
|
/** The entity record containing this field */
|
|
416
831
|
Record;
|
|
417
832
|
/** Whether the form is in edit mode */
|
|
@@ -456,6 +871,14 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
456
871
|
ShowLabel = true;
|
|
457
872
|
/** Form-level context (search filter, showEmptyFields) */
|
|
458
873
|
FormContext;
|
|
874
|
+
/**
|
|
875
|
+
* Whether FK / record links are interactive. Driven by
|
|
876
|
+
* `FormContext.enableRecordLinks`; false renders FK values as plain text
|
|
877
|
+
* (dialog/slide-in surfaces). Undefined / true means links are live.
|
|
878
|
+
*/
|
|
879
|
+
get RecordLinksEnabled() {
|
|
880
|
+
return this.FormContext?.enableRecordLinks !== false;
|
|
881
|
+
}
|
|
459
882
|
// ---- Deprecated camelCase aliases (backward compat) ----
|
|
460
883
|
/** @deprecated Use [Record] instead */
|
|
461
884
|
set _deprecatedRecord(value) { this.Record = value; }
|
|
@@ -711,19 +1134,51 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
711
1134
|
/** Calculated position for fixed-position dropdowns */
|
|
712
1135
|
DropdownTop = 0;
|
|
713
1136
|
DropdownLeft = 0;
|
|
714
|
-
|
|
1137
|
+
/** Computed: dropdown is at least the trigger width, at most {@link DropdownMaxWidth}. */
|
|
1138
|
+
DropdownMinWidth = 0;
|
|
1139
|
+
DropdownMaxWidth = 0;
|
|
715
1140
|
OpenAbove = false;
|
|
1141
|
+
/**
|
|
1142
|
+
* Max width (px) of the FK suggestion dropdown. The panel grows to fit its
|
|
1143
|
+
* columns up to this cap (then scrolls horizontally). When null, defaults to
|
|
1144
|
+
* 2× the trigger width so multi-column rows aren't cramped by a narrow field.
|
|
1145
|
+
* Always additionally bounded by the viewport's right edge.
|
|
1146
|
+
*/
|
|
1147
|
+
FKDropdownMaxWidth = null;
|
|
1148
|
+
/**
|
|
1149
|
+
* Whether to highlight the typed query substring within each suggestion's name
|
|
1150
|
+
* in the FK dropdown. On by default — uses the muted, theme-aware
|
|
1151
|
+
* `--mj-status-warning` highlight (not the old bright yellow). Set false for
|
|
1152
|
+
* plain, un-marked names.
|
|
1153
|
+
*/
|
|
1154
|
+
FKHighlightMatches = true;
|
|
1155
|
+
/**
|
|
1156
|
+
* Whether to offer inline "create new" for the related record when the one you need
|
|
1157
|
+
* isn't found. The affordance only renders when this is true AND the current user can
|
|
1158
|
+
* create records of the related entity (entity allows creation + role permits it).
|
|
1159
|
+
*/
|
|
1160
|
+
AllowFKCreate = true;
|
|
1161
|
+
/** Surface used for the inline create form: a modal dialog (default) or a slide-in. */
|
|
1162
|
+
FKCreatePresentation = 'dialog';
|
|
716
1163
|
/** Cleanup function for scroll/resize listeners */
|
|
717
1164
|
_scrollCleanup = null;
|
|
718
1165
|
/** Inline style for the fixed-position dropdown */
|
|
719
1166
|
get DropdownPositionStyle() {
|
|
1167
|
+
// min-width floors at the trigger width; max-width caps growth; the auto
|
|
1168
|
+
// intrinsic width then shrink-to-fits the columns between the two, and
|
|
1169
|
+
// `.mj-fk-options` scrolls horizontally once content exceeds the cap.
|
|
1170
|
+
const sizing = {
|
|
1171
|
+
'min-width': this.DropdownMinWidth + 'px',
|
|
1172
|
+
'max-width': this.DropdownMaxWidth + 'px',
|
|
1173
|
+
'width': 'max-content',
|
|
1174
|
+
};
|
|
720
1175
|
if (this.OpenAbove) {
|
|
721
1176
|
return {
|
|
722
1177
|
'position': 'fixed',
|
|
723
1178
|
'bottom': (window.innerHeight - this.DropdownTop) + 'px',
|
|
724
1179
|
'top': 'auto',
|
|
725
1180
|
'left': this.DropdownLeft + 'px',
|
|
726
|
-
|
|
1181
|
+
...sizing,
|
|
727
1182
|
'z-index': '10000'
|
|
728
1183
|
};
|
|
729
1184
|
}
|
|
@@ -732,7 +1187,7 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
732
1187
|
'top': this.DropdownTop + 'px',
|
|
733
1188
|
'bottom': 'auto',
|
|
734
1189
|
'left': this.DropdownLeft + 'px',
|
|
735
|
-
|
|
1190
|
+
...sizing,
|
|
736
1191
|
'z-index': '10000'
|
|
737
1192
|
};
|
|
738
1193
|
}
|
|
@@ -752,12 +1207,63 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
752
1207
|
this.DropdownTop = rect.bottom + gap;
|
|
753
1208
|
}
|
|
754
1209
|
this.DropdownLeft = rect.left;
|
|
755
|
-
|
|
1210
|
+
// At least the trigger width; up to FKDropdownMaxWidth (default 2×), but never
|
|
1211
|
+
// past the viewport's right edge. Content fills between min and max; overflow
|
|
1212
|
+
// scrolls horizontally.
|
|
1213
|
+
this.DropdownMinWidth = rect.width;
|
|
1214
|
+
const desiredMax = this.FKDropdownMaxWidth ?? rect.width * 2;
|
|
1215
|
+
this.DropdownMaxWidth = Math.max(rect.width, Math.min(desiredMax, window.innerWidth - rect.left - 8));
|
|
756
1216
|
}
|
|
1217
|
+
// ---- Dropdown portal (escape transformed ancestors) ----
|
|
1218
|
+
/**
|
|
1219
|
+
* The dropdown is `position: fixed` with viewport coords. Inside the slide-in /
|
|
1220
|
+
* dialog overlays (which use CSS `transform`), a `fixed` descendant is positioned
|
|
1221
|
+
* relative to the transformed ancestor instead of the viewport, so it renders
|
|
1222
|
+
* off-screen. Re-parenting the dropdown element to `document.body` removes it from
|
|
1223
|
+
* any transformed containing block, restoring true viewport-fixed positioning.
|
|
1224
|
+
*
|
|
1225
|
+
* Call after change detection has rendered the dropdown (microtask). Angular still
|
|
1226
|
+
* owns the node — when the structural `@if` tears it down it removes the node by
|
|
1227
|
+
* reference regardless of where it currently lives, so no manual cleanup is needed
|
|
1228
|
+
* beyond clearing our tracking pointer.
|
|
1229
|
+
*/
|
|
1230
|
+
portalDropdownToBody() {
|
|
1231
|
+
// Already portaled and still in the DOM → nothing to do (e.g. typing while open).
|
|
1232
|
+
if (this._portaledDropdownEl?.isConnected)
|
|
1233
|
+
return;
|
|
1234
|
+
// The dropdown is rendered by `@if (ShowFKDropdown)`. On the synchronous cached
|
|
1235
|
+
// path (focus → searchCachedEntity → applySuggestions) the element may not be in
|
|
1236
|
+
// the DOM yet when we first look, so retry across a few frames until it renders.
|
|
1237
|
+
// (The async DB path lands here post-render, so it succeeds on the first try.)
|
|
1238
|
+
const tryPortal = (retriesLeft) => {
|
|
1239
|
+
const host = this.hostRef?.nativeElement;
|
|
1240
|
+
if (!host)
|
|
1241
|
+
return;
|
|
1242
|
+
const dropdown = host.querySelector('.mj-fk-dropdown');
|
|
1243
|
+
if (dropdown) {
|
|
1244
|
+
if (dropdown.parentElement !== document.body) {
|
|
1245
|
+
this.renderer.appendChild(document.body, dropdown);
|
|
1246
|
+
this._portaledDropdownEl = dropdown;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
else if (retriesLeft > 0) {
|
|
1250
|
+
setTimeout(() => tryPortal(retriesLeft - 1), 0);
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
Promise.resolve().then(() => tryPortal(5));
|
|
1254
|
+
}
|
|
1255
|
+
/** Tracks a dropdown element we relocated to body so we can drop the reference on close. */
|
|
1256
|
+
_portaledDropdownEl = null;
|
|
757
1257
|
/** Start listening for scroll/resize to close dropdowns */
|
|
758
1258
|
startScrollListener() {
|
|
759
1259
|
this.stopScrollListener();
|
|
760
|
-
const onScroll = () => {
|
|
1260
|
+
const onScroll = (e) => {
|
|
1261
|
+
// Scrolling WITHIN the dropdown (vertical list or horizontal column scroll)
|
|
1262
|
+
// must not close it — only an ancestor/page scroll, which would detach the
|
|
1263
|
+
// fixed-position panel from its trigger, should.
|
|
1264
|
+
const target = e.target;
|
|
1265
|
+
if (this._portaledDropdownEl && target && this._portaledDropdownEl.contains(target))
|
|
1266
|
+
return;
|
|
761
1267
|
this.closeAllDropdowns();
|
|
762
1268
|
this.cdr.markForCheck();
|
|
763
1269
|
};
|
|
@@ -782,6 +1288,10 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
782
1288
|
/** Close all dropdown types */
|
|
783
1289
|
closeAllDropdowns() {
|
|
784
1290
|
this.ShowFKDropdown = false;
|
|
1291
|
+
this.FKActiveIndex = -1;
|
|
1292
|
+
this.FKLoading = false;
|
|
1293
|
+
this.FKNoMatches = false;
|
|
1294
|
+
this._portaledDropdownEl = null;
|
|
785
1295
|
this.ShowValueListDropdown = false;
|
|
786
1296
|
this.ShowSelectDropdown = false;
|
|
787
1297
|
this.stopScrollListener();
|
|
@@ -789,62 +1299,722 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
789
1299
|
// ============================================
|
|
790
1300
|
// FK AUTOCOMPLETE (custom implementation)
|
|
791
1301
|
// ============================================
|
|
1302
|
+
/** Max rows shown on an empty-input focus-show (cached fast path only). */
|
|
1303
|
+
static FK_FOCUS_SHOW_LIMIT = 50;
|
|
1304
|
+
/** Max rows returned from a DB search. */
|
|
1305
|
+
static FK_DB_SEARCH_LIMIT = 20;
|
|
792
1306
|
/** Suggestions returned from the FK entity search */
|
|
793
1307
|
FKSuggestions = [];
|
|
1308
|
+
/**
|
|
1309
|
+
* The currently-linked record, pinned as a sticky "Currently selected" section at the
|
|
1310
|
+
* top of the dropdown (browse mode only). Null when there's no selection or the user is
|
|
1311
|
+
* actively filtering. Removed from {@link FKSuggestions} so it isn't listed twice.
|
|
1312
|
+
*/
|
|
1313
|
+
FKSelectedSuggestion = null;
|
|
794
1314
|
/** Whether the current FK value is a confirmed match (user selected from dropdown) */
|
|
795
1315
|
FKIsMatched = false;
|
|
796
1316
|
/** Whether the FK dropdown is visible */
|
|
797
1317
|
ShowFKDropdown = false;
|
|
1318
|
+
/** Whether a DB search is currently in flight (drives the loading indicator). */
|
|
1319
|
+
FKLoading = false;
|
|
1320
|
+
/** True when a search completed with zero results (drives the "No matches" row). */
|
|
1321
|
+
FKNoMatches = false;
|
|
1322
|
+
/** Index of the keyboard-highlighted active suggestion (-1 = none). */
|
|
1323
|
+
FKActiveIndex = -1;
|
|
1324
|
+
/** Headers for the extra (DefaultInView) columns shown in the dropdown. */
|
|
1325
|
+
FKColumnHeaders = [];
|
|
1326
|
+
/** Field code names for the extra columns, index-aligned with {@link FKColumnHeaders}. */
|
|
1327
|
+
FKColumnFields = [];
|
|
1328
|
+
/** Code name of the name column (used as its sort key). */
|
|
1329
|
+
FKNameField = '';
|
|
1330
|
+
/** Whether rows render a leading icon column (drives the header's empty icon cell). */
|
|
1331
|
+
FKHasIconColumn = false;
|
|
1332
|
+
/** Active sort column (field code name), or null for natural (unsorted) order. */
|
|
1333
|
+
FKSortField = null;
|
|
1334
|
+
/** Active sort direction; only meaningful when {@link FKSortField} is set. */
|
|
1335
|
+
FKSortDir = 'asc';
|
|
1336
|
+
/** Unsorted snapshot of the current suggestions, used to restore natural order. */
|
|
1337
|
+
_fkSuggestionsNatural = [];
|
|
798
1338
|
/** Text the user is currently typing in the FK search input. null = use display name. */
|
|
799
1339
|
_fkInputText = null;
|
|
1340
|
+
/**
|
|
1341
|
+
* The active search query that produced the current results — `''` on a focus/clear
|
|
1342
|
+
* browse (full list), the typed text when filtering. Distinct from {@link _fkInputText},
|
|
1343
|
+
* which holds the *displayed* text (the selected record's name when not typing). This is
|
|
1344
|
+
* the correct signal for "browse mode" and for the create-footer label.
|
|
1345
|
+
*/
|
|
1346
|
+
_fkQuery = '';
|
|
800
1347
|
/** Debounce timer for FK search */
|
|
801
1348
|
_fkSearchTimeout = null;
|
|
802
1349
|
/** Last known FK input element for position recalculation */
|
|
803
1350
|
_lastFKInputEl = null;
|
|
1351
|
+
/** Monotonic token so a slow DB response from a stale query can't clobber a newer one. */
|
|
1352
|
+
_fkSearchSeq = 0;
|
|
1353
|
+
/** Cached column plan for the current related entity (rebuilt on demand). */
|
|
1354
|
+
_fkColumnPlan = null;
|
|
1355
|
+
// ---- Scope / search-field picker (Option B) ----
|
|
1356
|
+
/** Related-entity field code name currently searched against (defaults to the name field). */
|
|
1357
|
+
FKSearchField = '';
|
|
1358
|
+
/** Friendly label of {@link FKSearchField}, shown on the scope pill. */
|
|
1359
|
+
FKSearchFieldLabel = '';
|
|
1360
|
+
/** Whether the scope-picker menu is open. */
|
|
1361
|
+
FKShowScopeMenu = false;
|
|
1362
|
+
/** Whether the FK input is focused — the scope pill only appears while focused. */
|
|
1363
|
+
FKFocused = false;
|
|
1364
|
+
/** Fields the user can scope the search to (name + shown columns + other fields). */
|
|
1365
|
+
FKSearchableFields = [];
|
|
1366
|
+
// ---- Per-user persisted prefs (scope / sort / column widths) ----
|
|
1367
|
+
/** User-resized column widths in px, keyed by related-entity field code name. */
|
|
1368
|
+
_fkColWidths = {};
|
|
1369
|
+
/** The (host entity|field) pref key currently loaded; reload when it changes. */
|
|
1370
|
+
_fkPrefKey = null;
|
|
1371
|
+
/** Active column-resize drag, or null when not resizing. */
|
|
1372
|
+
_fkResize = null;
|
|
1373
|
+
_fkResizeMove = null;
|
|
1374
|
+
_fkResizeUp = null;
|
|
804
1375
|
/** The display text shown in the FK search input */
|
|
805
1376
|
get FKSearchText() {
|
|
806
1377
|
if (this._fkInputText !== null)
|
|
807
1378
|
return this._fkInputText;
|
|
808
1379
|
return this.FKDisplayName || '';
|
|
809
1380
|
}
|
|
1381
|
+
/**
|
|
1382
|
+
* True when this FK currently points at a real record (has a value AND we can show
|
|
1383
|
+
* its name). Drives the "linked" affordance — the chain icon + accent — so the user
|
|
1384
|
+
* can tell at a glance this is a resolved link, not free text.
|
|
1385
|
+
*/
|
|
1386
|
+
get FKHasLinkedValue() {
|
|
1387
|
+
return this.Value != null && this.Value !== '' && this.FKDisplayName != null;
|
|
1388
|
+
}
|
|
1389
|
+
/** Whether a dropdown row is the record currently linked by this FK (UUID-safe compare). */
|
|
1390
|
+
IsFKRowSelected(suggestion) {
|
|
1391
|
+
const v = this.Value;
|
|
1392
|
+
const pk = suggestion.PrimaryKeyValue;
|
|
1393
|
+
if (v == null || pk == null)
|
|
1394
|
+
return false;
|
|
1395
|
+
return UUIDsEqual(String(v), String(pk));
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Resolves the related `EntityInfo` for this FK field via the instance provider
|
|
1399
|
+
* (multi-provider safe — never the global `Metadata`).
|
|
1400
|
+
*/
|
|
1401
|
+
getRelatedEntityInfo() {
|
|
1402
|
+
const relatedName = this.FieldInfo?.RelatedEntity;
|
|
1403
|
+
if (!relatedName)
|
|
1404
|
+
return undefined;
|
|
1405
|
+
return this.ProviderToUse.EntityByName(relatedName);
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Returns the LIVE cached array of records for the related entity IF a loaded
|
|
1409
|
+
* engine holds the full (unfiltered) set; otherwise null. Records are read-only —
|
|
1410
|
+
* never mutate. Wraps {@link BaseEngineRegistry.TryGetCachedRecords}.
|
|
1411
|
+
*/
|
|
1412
|
+
getCachedRecordsForRelatedEntity() {
|
|
1413
|
+
const relatedName = this.FieldInfo?.RelatedEntity;
|
|
1414
|
+
if (!relatedName)
|
|
1415
|
+
return null;
|
|
1416
|
+
const registry = BaseEngineRegistry.Instance;
|
|
1417
|
+
const records = registry.TryGetCachedRecords(relatedName, { unfilteredOnly: true });
|
|
1418
|
+
// Treat an empty (or absent) cache as "no usable cache" so callers fall through
|
|
1419
|
+
// to the DB path and still show options on focus — never a blank dropdown.
|
|
1420
|
+
return records && records.length > 0 ? records : null;
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Builds (and memoizes) the column plan for the related entity: the name field,
|
|
1424
|
+
* the PK field used as the FK value, and the extra `DefaultInView` columns
|
|
1425
|
+
* (excluding the name + PK). Returns null when the related entity can't be resolved
|
|
1426
|
+
* or has no usable name/PK.
|
|
1427
|
+
*/
|
|
1428
|
+
buildColumnPlan() {
|
|
1429
|
+
if (this._fkColumnPlan) {
|
|
1430
|
+
this.ensureLinkedFieldPrefsLoaded(this._fkColumnPlan);
|
|
1431
|
+
return this._fkColumnPlan;
|
|
1432
|
+
}
|
|
1433
|
+
const relatedEntity = this.getRelatedEntityInfo();
|
|
1434
|
+
if (!relatedEntity)
|
|
1435
|
+
return null;
|
|
1436
|
+
const nameField = relatedEntity.NameField;
|
|
1437
|
+
const pkFields = relatedEntity.PrimaryKeys;
|
|
1438
|
+
if (!nameField && (!pkFields || pkFields.length !== 1))
|
|
1439
|
+
return null;
|
|
1440
|
+
const nameFieldName = nameField ? nameField.Name : pkFields[0].Name;
|
|
1441
|
+
const pkFieldName = this.FieldInfo?.RelatedEntityFieldName || (pkFields?.[0]?.Name ?? 'ID');
|
|
1442
|
+
// A field flagged ExtendedType='Icon' holds a per-row icon class — render it
|
|
1443
|
+
// as the row's leading glyph, not as a text column.
|
|
1444
|
+
const iconField = relatedEntity.Fields.find(f => f.ExtendedType === 'Icon');
|
|
1445
|
+
const iconFieldName = iconField?.Name ?? null;
|
|
1446
|
+
const columnFields = this.computeOrderedColumns(relatedEntity, nameFieldName, pkFieldName, iconFieldName);
|
|
1447
|
+
const extraFieldNames = columnFields.filter(c => c !== nameFieldName);
|
|
1448
|
+
this._fkColumnPlan = {
|
|
1449
|
+
NameFieldName: nameFieldName,
|
|
1450
|
+
PkFieldName: pkFieldName,
|
|
1451
|
+
ColumnFields: columnFields,
|
|
1452
|
+
ExtraFieldNames: extraFieldNames,
|
|
1453
|
+
ExtraHeaders: extraFieldNames.map(n => this.labelForRelatedField(n)),
|
|
1454
|
+
IconFieldName: iconFieldName,
|
|
1455
|
+
EntityIcon: relatedEntity.Icon || null
|
|
1456
|
+
};
|
|
1457
|
+
this.FKSearchableFields = this.buildSearchableFields(this._fkColumnPlan);
|
|
1458
|
+
this.ensureLinkedFieldPrefsLoaded(this._fkColumnPlan);
|
|
1459
|
+
return this._fkColumnPlan;
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Whether a `DefaultInView` field is worth showing as an extra dropdown column.
|
|
1463
|
+
* Excludes columns that read as opaque noise to a human picking a record:
|
|
1464
|
+
* • Primary keys (UUIDs/identities).
|
|
1465
|
+
* • Foreign-key columns — these hold the related record's raw ID (e.g. `ParentID`
|
|
1466
|
+
* → a GUID), not a human-readable label. The view's joined *name* field (if it's
|
|
1467
|
+
* itself `DefaultInView`) is the readable substitute and is kept.
|
|
1468
|
+
*/
|
|
1469
|
+
isUsefulExtraColumn(f) {
|
|
1470
|
+
if (f.IsPrimaryKey)
|
|
1471
|
+
return false;
|
|
1472
|
+
if (f.RelatedEntityID && f.RelatedEntityID.length > 0)
|
|
1473
|
+
return false; // foreign key → raw ID
|
|
1474
|
+
return true;
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* The ordered list of display columns INCLUDING the name field — the user-reorderable
|
|
1478
|
+
* column order. Honors a user `visibleFields` override (exact set + order, letting them
|
|
1479
|
+
* add fields like ID, drop defaults, or move the name field); otherwise falls back to
|
|
1480
|
+
* `[name, ...DefaultInView columns]`. The name field is always guaranteed present, and
|
|
1481
|
+
* the icon field is never a text column.
|
|
1482
|
+
*/
|
|
1483
|
+
computeOrderedColumns(relatedEntity, nameFieldName, pkFieldName, iconFieldName) {
|
|
1484
|
+
const exists = (n) => n !== iconFieldName && !!relatedEntity.Fields.find(f => f.Name === n);
|
|
1485
|
+
const saved = this.fkHostEntityName && this.fkFieldCodeName
|
|
1486
|
+
? LinkedFieldOptionsStore.Instance.Get(this.fkHostEntityName, this.fkFieldCodeName) : undefined;
|
|
1487
|
+
let cols;
|
|
1488
|
+
if (saved?.visibleFields) {
|
|
1489
|
+
cols = saved.visibleFields.filter(exists);
|
|
1490
|
+
// Migrate older prefs (stored extras-only, without the name field) and guarantee
|
|
1491
|
+
// the name field is always present.
|
|
1492
|
+
if (!cols.includes(nameFieldName))
|
|
1493
|
+
cols = [nameFieldName, ...cols];
|
|
1494
|
+
}
|
|
1495
|
+
else {
|
|
1496
|
+
const defaults = relatedEntity.Fields
|
|
1497
|
+
.filter(f => f.DefaultInView && f.Name !== nameFieldName && f.Name !== pkFieldName
|
|
1498
|
+
&& f.Name !== iconFieldName && this.isUsefulExtraColumn(f))
|
|
1499
|
+
.map(f => f.Name);
|
|
1500
|
+
cols = [nameFieldName, ...defaults];
|
|
1501
|
+
}
|
|
1502
|
+
// De-dupe (preserve order) and ensure the name field is present.
|
|
1503
|
+
const seen = new Set();
|
|
1504
|
+
const ordered = cols.filter(c => (seen.has(c) ? false : (seen.add(c), true)));
|
|
1505
|
+
if (!ordered.includes(nameFieldName))
|
|
1506
|
+
ordered.unshift(nameFieldName);
|
|
1507
|
+
return ordered;
|
|
1508
|
+
}
|
|
1509
|
+
// ============================================
|
|
1510
|
+
// SCOPE PICKER + PER-USER PREFS
|
|
1511
|
+
// ============================================
|
|
1512
|
+
/** Host entity name (the entity whose form this field belongs to), or null. */
|
|
1513
|
+
get fkHostEntityName() {
|
|
1514
|
+
return this.Record?.EntityInfo?.Name ?? null;
|
|
1515
|
+
}
|
|
1516
|
+
/** This FK field's code name on the host entity, or null. */
|
|
1517
|
+
get fkFieldCodeName() {
|
|
1518
|
+
return this.FieldInfo?.Name ?? null;
|
|
1519
|
+
}
|
|
1520
|
+
/** Whether the active search column is the name field (drives where we highlight). */
|
|
1521
|
+
isSearchingNameField(plan) {
|
|
1522
|
+
return !this.FKSearchField || this.FKSearchField === plan.NameFieldName;
|
|
1523
|
+
}
|
|
1524
|
+
/** A field is scope-searchable if it's a string column (LIKE-able) and not a system column. */
|
|
1525
|
+
isScopeSearchableField(f) {
|
|
1526
|
+
if (f.TSType !== EntityFieldTSType.String)
|
|
1527
|
+
return false;
|
|
1528
|
+
if (f.Name.startsWith('__mj_'))
|
|
1529
|
+
return false;
|
|
1530
|
+
return true;
|
|
1531
|
+
}
|
|
1532
|
+
/** Friendly label for a related-entity field code name. */
|
|
1533
|
+
labelForRelatedField(name) {
|
|
1534
|
+
return this.getRelatedEntityInfo()?.Fields.find(x => x.Name === name)?.DisplayNameOrName ?? name;
|
|
1535
|
+
}
|
|
1536
|
+
/** Whether a field code name exists on the related entity (guards stale saved prefs). */
|
|
1537
|
+
isValidRelatedField(name) {
|
|
1538
|
+
return !!this.getRelatedEntityInfo()?.Fields.find(x => x.Name === name);
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Build the scope-picker field list: the name + shown columns ('shown' group),
|
|
1542
|
+
* then any other searchable string fields like ID/Status ('other' group).
|
|
1543
|
+
*/
|
|
1544
|
+
buildSearchableFields(plan) {
|
|
1545
|
+
const re = this.getRelatedEntityInfo();
|
|
1546
|
+
if (!re)
|
|
1547
|
+
return [];
|
|
1548
|
+
const iconFor = (fieldName) => {
|
|
1549
|
+
if (fieldName === plan.NameFieldName)
|
|
1550
|
+
return 'fa-solid fa-font';
|
|
1551
|
+
return re.Fields.find(x => x.Name === fieldName)?.IsPrimaryKey ? 'fa-solid fa-hashtag' : 'fa-solid fa-tag';
|
|
1552
|
+
};
|
|
1553
|
+
// 'shown' group rendered in the actual column order so the menu matches the grid
|
|
1554
|
+
// (and so the up/down arrows hide correctly on the true first/last columns).
|
|
1555
|
+
const shown = new Set(plan.ColumnFields);
|
|
1556
|
+
const list = plan.ColumnFields.map(fieldName => ({
|
|
1557
|
+
FieldName: fieldName,
|
|
1558
|
+
Label: this.labelForRelatedField(fieldName),
|
|
1559
|
+
Icon: iconFor(fieldName),
|
|
1560
|
+
Group: 'shown'
|
|
1561
|
+
}));
|
|
1562
|
+
for (const f of re.Fields) {
|
|
1563
|
+
if (shown.has(f.Name) || f.Name === plan.IconFieldName)
|
|
1564
|
+
continue;
|
|
1565
|
+
if (!this.isScopeSearchableField(f))
|
|
1566
|
+
continue;
|
|
1567
|
+
list.push({
|
|
1568
|
+
FieldName: f.Name,
|
|
1569
|
+
Label: f.DisplayNameOrName,
|
|
1570
|
+
Icon: f.IsPrimaryKey ? 'fa-solid fa-hashtag' : 'fa-solid fa-font',
|
|
1571
|
+
Group: 'other'
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
return list;
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Load this (host entity, FK field)'s saved prefs — search scope, sort, column
|
|
1578
|
+
* widths — once per field. No-ops when the field hasn't changed. Falls back to
|
|
1579
|
+
* defaults (search the name field, natural sort, content-sized columns) and only
|
|
1580
|
+
* applies a saved value when it still resolves to a real field.
|
|
1581
|
+
*/
|
|
1582
|
+
ensureLinkedFieldPrefsLoaded(plan) {
|
|
1583
|
+
const key = this.fkHostEntityName && this.fkFieldCodeName
|
|
1584
|
+
? `${this.fkHostEntityName}|${this.fkFieldCodeName}` : null;
|
|
1585
|
+
if (key === this._fkPrefKey)
|
|
1586
|
+
return;
|
|
1587
|
+
this._fkPrefKey = key;
|
|
1588
|
+
// Defaults
|
|
1589
|
+
this.FKSearchField = plan.NameFieldName;
|
|
1590
|
+
this._fkColWidths = {};
|
|
1591
|
+
const saved = this.fkHostEntityName && this.fkFieldCodeName
|
|
1592
|
+
? LinkedFieldOptionsStore.Instance.Get(this.fkHostEntityName, this.fkFieldCodeName) : undefined;
|
|
1593
|
+
if (saved) {
|
|
1594
|
+
if (saved.searchField && this.isValidRelatedField(saved.searchField)) {
|
|
1595
|
+
this.FKSearchField = saved.searchField;
|
|
1596
|
+
}
|
|
1597
|
+
if (saved.sortField !== undefined && (saved.sortField === null || this.isValidRelatedField(saved.sortField))) {
|
|
1598
|
+
this.FKSortField = saved.sortField;
|
|
1599
|
+
this.FKSortDir = saved.sortDir ?? 'asc';
|
|
1600
|
+
}
|
|
1601
|
+
if (saved.colWidths)
|
|
1602
|
+
this._fkColWidths = { ...saved.colWidths };
|
|
1603
|
+
}
|
|
1604
|
+
this.FKSearchFieldLabel = this.labelForRelatedField(this.FKSearchField);
|
|
1605
|
+
}
|
|
1606
|
+
/** Format a raw cell value for display in the dropdown (delegates to the pure helper). */
|
|
1607
|
+
formatCell(val) {
|
|
1608
|
+
return FormatFKCell(val);
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* Build the suggestion view-models from a set of plain rows (cached or DB),
|
|
1612
|
+
* applying the typed-query substring highlight to the name column.
|
|
1613
|
+
* `getField` abstracts cached BaseEntity rows (`.Get(name)`) vs simple objects.
|
|
1614
|
+
*/
|
|
1615
|
+
buildSuggestions(rows, plan, query) {
|
|
1616
|
+
const searchField = this.FKSearchField || plan.NameFieldName;
|
|
1617
|
+
// Only highlight the column actually being searched, and only when enabled.
|
|
1618
|
+
const nameQuery = (this.FKHighlightMatches && this.isSearchingNameField(plan)) ? query : '';
|
|
1619
|
+
return rows.map(row => {
|
|
1620
|
+
const name = this.formatCell(row.get(plan.NameFieldName));
|
|
1621
|
+
// Per-row icon from the entity's ExtendedType='Icon' field; else the
|
|
1622
|
+
// entity-level icon; else none.
|
|
1623
|
+
const rowIcon = plan.IconFieldName ? this.formatCell(row.get(plan.IconFieldName)).trim() : '';
|
|
1624
|
+
return {
|
|
1625
|
+
PrimaryKeyValue: row.get(plan.PkFieldName),
|
|
1626
|
+
DisplayName: name,
|
|
1627
|
+
// Empty query yields the (still HTML-escaped) plain name — no marks.
|
|
1628
|
+
HighlightedName: HighlightSearchMatches(name, nameQuery, 'mj-forms-search-highlight'),
|
|
1629
|
+
ExtraColumns: plan.ExtraFieldNames.map((fieldName, i) => {
|
|
1630
|
+
const value = this.formatCell(row.get(fieldName));
|
|
1631
|
+
const colQuery = (this.FKHighlightMatches && fieldName === searchField) ? query : '';
|
|
1632
|
+
return {
|
|
1633
|
+
FieldName: fieldName,
|
|
1634
|
+
Header: plan.ExtraHeaders[i],
|
|
1635
|
+
Value: value,
|
|
1636
|
+
HighlightedValue: HighlightSearchMatches(value, colQuery, 'mj-forms-search-highlight')
|
|
1637
|
+
};
|
|
1638
|
+
}),
|
|
1639
|
+
Icon: (rowIcon || plan.EntityIcon) || null
|
|
1640
|
+
};
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
/** Apply a freshly-built suggestion list to the dropdown state + reposition + portal. */
|
|
1644
|
+
applySuggestions(suggestions, plan) {
|
|
1645
|
+
// Pinned "currently selected" row: in browse mode (empty query) with a valid linked
|
|
1646
|
+
// value, lift the selected record into a sticky section and remove it from the list so
|
|
1647
|
+
// the user can keep it or pick another without clearing first.
|
|
1648
|
+
this.FKSelectedSuggestion = null;
|
|
1649
|
+
const browseMode = this._fkQuery.trim().length === 0;
|
|
1650
|
+
if (browseMode && this.FKHasLinkedValue) {
|
|
1651
|
+
const idx = suggestions.findIndex(s => this.IsFKRowSelected(s));
|
|
1652
|
+
if (idx >= 0) {
|
|
1653
|
+
this.FKSelectedSuggestion = suggestions[idx];
|
|
1654
|
+
suggestions = suggestions.filter((_, i) => i !== idx);
|
|
1655
|
+
}
|
|
1656
|
+
else {
|
|
1657
|
+
// Selected record isn't in the (first-N) result — show a lightweight pinned row.
|
|
1658
|
+
this.FKSelectedSuggestion = this.buildSelectedFallbackSuggestion(plan);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
this._fkSuggestionsNatural = suggestions;
|
|
1662
|
+
this.FKNameField = plan.NameFieldName;
|
|
1663
|
+
// Full ordered column list (incl. the name field) + matching headers.
|
|
1664
|
+
this.FKColumnFields = plan.ColumnFields;
|
|
1665
|
+
this.FKColumnHeaders = plan.ColumnFields.map(c => c === plan.NameFieldName ? 'Name' : this.labelForRelatedField(c));
|
|
1666
|
+
this.FKHasIconColumn = (this.FKSelectedSuggestion?.Icon != null) || suggestions.some(s => s.Icon != null);
|
|
1667
|
+
this.FKSuggestions = this.sortSuggestions(suggestions);
|
|
1668
|
+
this.FKActiveIndex = this.FKSuggestions.length > 0 ? 0 : -1;
|
|
1669
|
+
this.FKNoMatches = suggestions.length === 0 && !this.FKSelectedSuggestion;
|
|
1670
|
+
// Show the dropdown for rows, a "no matches" state, or just the pinned selection.
|
|
1671
|
+
this.ShowFKDropdown = suggestions.length > 0 || this.FKNoMatches || !!this.FKSelectedSuggestion;
|
|
1672
|
+
if (this.ShowFKDropdown && this._lastFKInputEl) {
|
|
1673
|
+
this.updateDropdownPosition(this._lastFKInputEl);
|
|
1674
|
+
this.startScrollListener();
|
|
1675
|
+
this.portalDropdownToBody();
|
|
1676
|
+
}
|
|
1677
|
+
this.cdr.markForCheck();
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* Build a lightweight pinned row for the selected record when it isn't present in the
|
|
1681
|
+
* current result set (DB beyond first-N, or cached beyond the focus-show limit). We have
|
|
1682
|
+
* its display name from the FK name resolution; extra-column values are left blank.
|
|
1683
|
+
*/
|
|
1684
|
+
buildSelectedFallbackSuggestion(plan) {
|
|
1685
|
+
const name = this.FKDisplayName;
|
|
1686
|
+
if (this.Value == null || this.Value === '' || !name)
|
|
1687
|
+
return null;
|
|
1688
|
+
return {
|
|
1689
|
+
PrimaryKeyValue: this.Value,
|
|
1690
|
+
DisplayName: name,
|
|
1691
|
+
HighlightedName: HighlightSearchMatches(name, '', 'mj-forms-search-highlight'),
|
|
1692
|
+
ExtraColumns: plan.ExtraFieldNames.map((fn, i) => ({
|
|
1693
|
+
FieldName: fn, Header: plan.ExtraHeaders[i], Value: '', HighlightedValue: ''
|
|
1694
|
+
})),
|
|
1695
|
+
Icon: plan.EntityIcon ?? null
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Returns a sorted copy of the suggestions per the active sort column/direction.
|
|
1700
|
+
* Null sort field → natural order (original array, untouched). Sorts on the name
|
|
1701
|
+
* column's `DisplayName` or the matching extra column's formatted `Value`,
|
|
1702
|
+
* case-insensitively.
|
|
1703
|
+
*/
|
|
1704
|
+
sortSuggestions(suggestions) {
|
|
1705
|
+
const field = this.FKSortField;
|
|
1706
|
+
if (!field)
|
|
1707
|
+
return suggestions;
|
|
1708
|
+
const keyOf = (s) => {
|
|
1709
|
+
if (field === this.FKNameField)
|
|
1710
|
+
return s.DisplayName ?? '';
|
|
1711
|
+
return s.ExtraColumns.find(c => c.FieldName === field)?.Value ?? '';
|
|
1712
|
+
};
|
|
1713
|
+
const dir = this.FKSortDir === 'desc' ? -1 : 1;
|
|
1714
|
+
return [...suggestions].sort((a, b) => dir * keyOf(a).localeCompare(keyOf(b), undefined, { numeric: true, sensitivity: 'base' }));
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Toggle the sort on a column header: same column cycles asc → desc → none;
|
|
1718
|
+
* a new column starts at asc. Re-derives the visible list from the natural snapshot.
|
|
1719
|
+
*/
|
|
1720
|
+
OnFKSortToggle(fieldName) {
|
|
1721
|
+
if (this.FKSortField === fieldName) {
|
|
1722
|
+
if (this.FKSortDir === 'asc')
|
|
1723
|
+
this.FKSortDir = 'desc';
|
|
1724
|
+
else {
|
|
1725
|
+
this.FKSortField = null;
|
|
1726
|
+
this.FKSortDir = 'asc';
|
|
1727
|
+
} // desc → cleared
|
|
1728
|
+
}
|
|
1729
|
+
else {
|
|
1730
|
+
this.FKSortField = fieldName;
|
|
1731
|
+
this.FKSortDir = 'asc';
|
|
1732
|
+
}
|
|
1733
|
+
this.FKSuggestions = this.sortSuggestions(this._fkSuggestionsNatural);
|
|
1734
|
+
this.FKActiveIndex = this.FKSuggestions.length > 0 ? 0 : -1;
|
|
1735
|
+
this.persistLinkedFieldSort();
|
|
1736
|
+
this.cdr.markForCheck();
|
|
1737
|
+
}
|
|
1738
|
+
/** Persist the active sort for this (host entity, FK field) pair. */
|
|
1739
|
+
persistLinkedFieldSort() {
|
|
1740
|
+
if (this.fkHostEntityName && this.fkFieldCodeName) {
|
|
1741
|
+
LinkedFieldOptionsStore.Instance.SetSort(this.fkHostEntityName, this.fkFieldCodeName, this.FKSortField, this.FKSortDir);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
/** FontAwesome class for a column header's sort indicator (idle / asc / desc). */
|
|
1745
|
+
FKSortIcon(fieldName) {
|
|
1746
|
+
if (this.FKSortField !== fieldName)
|
|
1747
|
+
return 'fa-solid fa-sort mj-fk-sort-icon mj-fk-sort-icon--idle';
|
|
1748
|
+
return this.FKSortDir === 'asc'
|
|
1749
|
+
? 'fa-solid fa-sort-up mj-fk-sort-icon'
|
|
1750
|
+
: 'fa-solid fa-sort-down mj-fk-sort-icon';
|
|
1751
|
+
}
|
|
1752
|
+
// ---- Scope pill (search-field picker) ----
|
|
1753
|
+
/** Toggle the scope-picker menu. mousedown+preventDefault keeps the input focused. */
|
|
1754
|
+
OnFKScopeToggle(event) {
|
|
1755
|
+
event.preventDefault();
|
|
1756
|
+
event.stopPropagation();
|
|
1757
|
+
this.FKShowScopeMenu = !this.FKShowScopeMenu;
|
|
1758
|
+
this.cdr.markForCheck();
|
|
1759
|
+
}
|
|
1760
|
+
/** Whether a scope-menu row is the active search field. */
|
|
1761
|
+
IsFKScopeActive(field) {
|
|
1762
|
+
return field.FieldName === (this.FKSearchField || this.FKNameField);
|
|
1763
|
+
}
|
|
1764
|
+
/** Whether there are non-visible searchable fields (drives the "Other fields" group). */
|
|
1765
|
+
get FKHasOtherSearchableFields() {
|
|
1766
|
+
return this.FKSearchableFields.some(f => f.Group === 'other');
|
|
1767
|
+
}
|
|
1768
|
+
/** User picked a field to search by — persist the override and re-run the search. */
|
|
1769
|
+
OnFKScopeSelect(event, field) {
|
|
1770
|
+
event.preventDefault();
|
|
1771
|
+
this.selectScope(field);
|
|
1772
|
+
}
|
|
1773
|
+
/** Set the active search field (used by click + the no-drag path of menu drag). */
|
|
1774
|
+
selectScope(field) {
|
|
1775
|
+
this.FKSearchField = field.FieldName;
|
|
1776
|
+
this.FKSearchFieldLabel = field.Label;
|
|
1777
|
+
this.FKShowScopeMenu = false;
|
|
1778
|
+
if (this.fkHostEntityName && this.fkFieldCodeName) {
|
|
1779
|
+
LinkedFieldOptionsStore.Instance.SetSearchField(this.fkHostEntityName, this.fkFieldCodeName, field.FieldName);
|
|
1780
|
+
}
|
|
1781
|
+
this.rerunCurrentFKSearch();
|
|
1782
|
+
this.cdr.markForCheck();
|
|
1783
|
+
}
|
|
1784
|
+
/** Re-run the active query against the (possibly newly-chosen) search field. */
|
|
1785
|
+
rerunCurrentFKSearch() {
|
|
1786
|
+
const query = this._fkQuery;
|
|
1787
|
+
const cached = this.getCachedRecordsForRelatedEntity();
|
|
1788
|
+
if (cached)
|
|
1789
|
+
this.searchCachedEntity(cached, query);
|
|
1790
|
+
else
|
|
1791
|
+
void this.searchRelatedEntity(query);
|
|
1792
|
+
}
|
|
1793
|
+
// ---- Column visibility (show/hide a field as a column) ----
|
|
1794
|
+
/** Whether a field is currently rendered as a column (the Name column is always shown). */
|
|
1795
|
+
IsFKColumnVisible(field) {
|
|
1796
|
+
return field.FieldName === this.FKNameField || this.FKColumnFields.includes(field.FieldName);
|
|
1797
|
+
}
|
|
1798
|
+
/** Whether this field's column visibility can be toggled (Name is always shown). */
|
|
1799
|
+
CanToggleFKColumn(field) {
|
|
1800
|
+
return field.FieldName !== this.FKNameField;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Toggle whether a field shows as a column. Persists the full visible set, then
|
|
1804
|
+
* rebuilds the column plan + re-runs the search so the grid reflects it live.
|
|
1805
|
+
* stopPropagation so the row's search-scope click doesn't also fire.
|
|
1806
|
+
*/
|
|
1807
|
+
OnFKColumnToggle(event, field) {
|
|
1808
|
+
event.preventDefault();
|
|
1809
|
+
event.stopPropagation();
|
|
1810
|
+
if (!this.CanToggleFKColumn(field))
|
|
1811
|
+
return;
|
|
1812
|
+
const next = [...this.FKColumnFields];
|
|
1813
|
+
const idx = next.indexOf(field.FieldName);
|
|
1814
|
+
if (idx >= 0)
|
|
1815
|
+
next.splice(idx, 1);
|
|
1816
|
+
else
|
|
1817
|
+
next.push(field.FieldName);
|
|
1818
|
+
this.applyVisibleColumns(next);
|
|
1819
|
+
}
|
|
1820
|
+
/** Persist a new visible-column set/order and rebuild the grid live. */
|
|
1821
|
+
applyVisibleColumns(cols) {
|
|
1822
|
+
if (this.fkHostEntityName && this.fkFieldCodeName) {
|
|
1823
|
+
LinkedFieldOptionsStore.Instance.SetVisibleFields(this.fkHostEntityName, this.fkFieldCodeName, cols);
|
|
1824
|
+
}
|
|
1825
|
+
this._fkColumnPlan = null; // force rebuild with the new column set/order
|
|
1826
|
+
this.rerunCurrentFKSearch();
|
|
1827
|
+
this.cdr.markForCheck();
|
|
1828
|
+
}
|
|
1829
|
+
// ---- Column reorder (up/down arrows in the field-selector menu) ----
|
|
1830
|
+
/** Whether the column can move up (it's a column and not already first). */
|
|
1831
|
+
CanMoveFKColumnUp(field) {
|
|
1832
|
+
return this.FKColumnFields.indexOf(field) > 0;
|
|
1833
|
+
}
|
|
1834
|
+
/** Whether the column can move down (it's a column and not already last). */
|
|
1835
|
+
CanMoveFKColumnDown(field) {
|
|
1836
|
+
const i = this.FKColumnFields.indexOf(field);
|
|
1837
|
+
return i >= 0 && i < this.FKColumnFields.length - 1;
|
|
1838
|
+
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Move a column one slot up (delta -1) or down (delta +1) and persist. mousedown +
|
|
1841
|
+
* stopPropagation so the row's select-scope handler doesn't fire and the menu stays open.
|
|
1842
|
+
*/
|
|
1843
|
+
MoveFKColumn(event, field, delta) {
|
|
1844
|
+
event.preventDefault();
|
|
1845
|
+
event.stopPropagation();
|
|
1846
|
+
const cols = [...this.FKColumnFields];
|
|
1847
|
+
const i = cols.indexOf(field);
|
|
1848
|
+
const j = i + delta;
|
|
1849
|
+
if (i < 0 || j < 0 || j >= cols.length)
|
|
1850
|
+
return;
|
|
1851
|
+
[cols[i], cols[j]] = [cols[j], cols[i]];
|
|
1852
|
+
this.applyVisibleColumns(cols);
|
|
1853
|
+
}
|
|
1854
|
+
/**
|
|
1855
|
+
* CSS `grid-template-columns` for the dropdown grid: optional icon column, then one
|
|
1856
|
+
* track per ordered column. The LAST column grows to fill any remaining width (`1fr`)
|
|
1857
|
+
* so the grid never leaves dead space on the right; earlier columns size to content.
|
|
1858
|
+
* A user-resized column uses its saved pixel width as the floor.
|
|
1859
|
+
*/
|
|
1860
|
+
get FKGridTemplateColumns() {
|
|
1861
|
+
const cols = [];
|
|
1862
|
+
if (this.FKHasIconColumn)
|
|
1863
|
+
cols.push('min-content');
|
|
1864
|
+
const lastIdx = this.FKColumnFields.length - 1;
|
|
1865
|
+
this.FKColumnFields.forEach((field, i) => cols.push(this.fkColumnTrack(field, i === lastIdx)));
|
|
1866
|
+
return cols.join(' ');
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Track sizing for one column. Resized → fixed px (the last column still grows past it
|
|
1870
|
+
* via `1fr` when there's room). Default → content-sized, except the last column which
|
|
1871
|
+
* fills remaining space.
|
|
1872
|
+
*/
|
|
1873
|
+
fkColumnTrack(field, isLast) {
|
|
1874
|
+
const w = this._fkColWidths[field];
|
|
1875
|
+
const min = field === this.FKNameField ? 120 : 80;
|
|
1876
|
+
if (w)
|
|
1877
|
+
return isLast ? `minmax(${w}px, 1fr)` : `${w}px`;
|
|
1878
|
+
return isLast ? `minmax(${min}px, 1fr)` : `minmax(${min}px, max-content)`;
|
|
1879
|
+
}
|
|
1880
|
+
/** Whether a column's cells should stretch to fill their track (last column or resized). */
|
|
1881
|
+
FKColumnFillsTrack(field, isLast) {
|
|
1882
|
+
return isLast || this._fkColWidths[field] != null;
|
|
1883
|
+
}
|
|
1884
|
+
/** The built cell (value + highlighted html) for a non-name column of a suggestion. */
|
|
1885
|
+
FKCellFor(suggestion, field) {
|
|
1886
|
+
return suggestion.ExtraColumns.find(c => c.FieldName === field);
|
|
1887
|
+
}
|
|
1888
|
+
/** Header sort handler (grid headers click-to-sort only; drag-reorder is menu-only). */
|
|
1889
|
+
OnFKHeaderSort(event, field) {
|
|
1890
|
+
event.preventDefault(); // keep input focus so the body-portaled dropdown stays open
|
|
1891
|
+
this.OnFKSortToggle(field);
|
|
1892
|
+
}
|
|
1893
|
+
// ---- Column resize (drag a header's right edge) ----
|
|
1894
|
+
/** Begin resizing a column. stopPropagation so the header's sort handler doesn't fire. */
|
|
1895
|
+
OnFKColResizeStart(event, field) {
|
|
1896
|
+
event.preventDefault();
|
|
1897
|
+
event.stopPropagation();
|
|
1898
|
+
const headerCell = event.target.closest('.mj-fk-hcell');
|
|
1899
|
+
const startWidth = headerCell ? headerCell.offsetWidth : 120;
|
|
1900
|
+
this._fkResize = { field, startX: event.clientX, startWidth };
|
|
1901
|
+
this._fkResizeMove = (e) => this.onFKColResizeMove(e);
|
|
1902
|
+
this._fkResizeUp = () => this.onFKColResizeEnd();
|
|
1903
|
+
document.addEventListener('mousemove', this._fkResizeMove);
|
|
1904
|
+
document.addEventListener('mouseup', this._fkResizeUp);
|
|
1905
|
+
}
|
|
1906
|
+
onFKColResizeMove(e) {
|
|
1907
|
+
if (!this._fkResize)
|
|
1908
|
+
return;
|
|
1909
|
+
const width = Math.max(60, Math.round(this._fkResize.startWidth + (e.clientX - this._fkResize.startX)));
|
|
1910
|
+
this._fkColWidths = { ...this._fkColWidths, [this._fkResize.field]: width };
|
|
1911
|
+
this.cdr.markForCheck();
|
|
1912
|
+
}
|
|
1913
|
+
onFKColResizeEnd() {
|
|
1914
|
+
if (this._fkResize) {
|
|
1915
|
+
const width = this._fkColWidths[this._fkResize.field];
|
|
1916
|
+
if (width && this.fkHostEntityName && this.fkFieldCodeName) {
|
|
1917
|
+
LinkedFieldOptionsStore.Instance.SetColWidth(this.fkHostEntityName, this.fkFieldCodeName, this._fkResize.field, width);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
this.teardownFKResizeListeners();
|
|
1921
|
+
this.cdr.markForCheck();
|
|
1922
|
+
}
|
|
1923
|
+
teardownFKResizeListeners() {
|
|
1924
|
+
if (this._fkResizeMove)
|
|
1925
|
+
document.removeEventListener('mousemove', this._fkResizeMove);
|
|
1926
|
+
if (this._fkResizeUp)
|
|
1927
|
+
document.removeEventListener('mouseup', this._fkResizeUp);
|
|
1928
|
+
this._fkResize = null;
|
|
1929
|
+
this._fkResizeMove = null;
|
|
1930
|
+
this._fkResizeUp = null;
|
|
1931
|
+
}
|
|
810
1932
|
/** Handle typing in the FK search input */
|
|
811
1933
|
OnFKInput(event) {
|
|
812
1934
|
const input = event.target;
|
|
813
1935
|
this._fkInputText = input.value;
|
|
814
1936
|
this._lastFKInputEl = input;
|
|
815
1937
|
this.FKIsMatched = false;
|
|
816
|
-
|
|
1938
|
+
const query = this._fkInputText;
|
|
1939
|
+
// Cached fast path: filter the in-memory array immediately (no DB, no debounce).
|
|
1940
|
+
const cached = this.getCachedRecordsForRelatedEntity();
|
|
1941
|
+
if (cached) {
|
|
1942
|
+
if (this._fkSearchTimeout) {
|
|
1943
|
+
clearTimeout(this._fkSearchTimeout);
|
|
1944
|
+
this._fkSearchTimeout = null;
|
|
1945
|
+
}
|
|
1946
|
+
this.searchCachedEntity(cached, query);
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
// DB path: debounce a RunView search. Empty query (cleared field) → first N,
|
|
1950
|
+
// so clearing the field reveals the list rather than closing it.
|
|
817
1951
|
if (this._fkSearchTimeout)
|
|
818
1952
|
clearTimeout(this._fkSearchTimeout);
|
|
819
1953
|
this._fkSearchTimeout = setTimeout(() => {
|
|
820
|
-
|
|
821
|
-
this.searchRelatedEntity(this._fkInputText);
|
|
822
|
-
}
|
|
823
|
-
else {
|
|
824
|
-
this.FKSuggestions = [];
|
|
825
|
-
this.ShowFKDropdown = false;
|
|
826
|
-
this.stopScrollListener();
|
|
827
|
-
this.cdr.markForCheck();
|
|
828
|
-
}
|
|
1954
|
+
void this.searchRelatedEntity(this._fkInputText ?? '');
|
|
829
1955
|
}, 300);
|
|
830
1956
|
}
|
|
831
|
-
/**
|
|
1957
|
+
/**
|
|
1958
|
+
* Show dropdown on focus. With a cached-unfiltered entity we immediately show the
|
|
1959
|
+
* first N rows (sorted by name) even on empty input — zero DB round-trips. Without
|
|
1960
|
+
* a cache we keep prior behavior: only re-open if we already have suggestions.
|
|
1961
|
+
*/
|
|
832
1962
|
OnFKFocus(event) {
|
|
833
1963
|
const input = event.target;
|
|
834
1964
|
this._lastFKInputEl = input;
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
1965
|
+
this.FKFocused = true; // reveal the scope pill while focused
|
|
1966
|
+
// Select any pre-filled (linked) text so the first keystroke replaces it instead
|
|
1967
|
+
// of appending — matches how a searchable dropdown behaves.
|
|
1968
|
+
if (input.value)
|
|
1969
|
+
input.select();
|
|
1970
|
+
this.showInitialFKSuggestions();
|
|
1971
|
+
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Show the initial suggestion list (no/empty query): the full set from a cached
|
|
1974
|
+
* unfiltered engine, otherwise the first N rows via a DB query. Used on focus and
|
|
1975
|
+
* when the field is cleared, so the user always sees options without typing.
|
|
1976
|
+
*/
|
|
1977
|
+
showInitialFKSuggestions() {
|
|
1978
|
+
// Always show the FULL list (empty query) on focus/clear — even when a value is
|
|
1979
|
+
// already selected — so the user can browse and re-pick like a normal dropdown.
|
|
1980
|
+
// Filtering only kicks in once they actually type (OnFKInput).
|
|
1981
|
+
const cached = this.getCachedRecordsForRelatedEntity();
|
|
1982
|
+
if (cached) {
|
|
1983
|
+
if (this._fkSearchTimeout) {
|
|
1984
|
+
clearTimeout(this._fkSearchTimeout);
|
|
1985
|
+
this._fkSearchTimeout = null;
|
|
1986
|
+
}
|
|
1987
|
+
this.searchCachedEntity(cached, '');
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
void this.searchRelatedEntity('');
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* In-memory search over a cached-unfiltered entity array. Case-insensitive substring
|
|
1994
|
+
* on the name field. Empty query → first N rows sorted by name (focus-show). Instant,
|
|
1995
|
+
* no spinner, no DB.
|
|
1996
|
+
*/
|
|
1997
|
+
searchCachedEntity(records, query) {
|
|
1998
|
+
const plan = this.buildColumnPlan();
|
|
1999
|
+
if (!plan) {
|
|
2000
|
+
this.closeFKDropdown();
|
|
839
2001
|
this.cdr.markForCheck();
|
|
2002
|
+
return;
|
|
840
2003
|
}
|
|
2004
|
+
this._fkQuery = query;
|
|
2005
|
+
const accessor = (r) => ({ get: (field) => r.Get(field) });
|
|
2006
|
+
const searchField = this.FKSearchField || plan.NameFieldName;
|
|
2007
|
+
const matches = FilterCachedFKRows(records, query, MjFormFieldComponent.FK_FOCUS_SHOW_LIMIT, r => r.Get(searchField));
|
|
2008
|
+
this.FKLoading = false;
|
|
2009
|
+
this.applySuggestions(this.buildSuggestions(matches.map(accessor), plan, query), plan);
|
|
841
2010
|
}
|
|
842
2011
|
/** Hide dropdown on blur, revert to matched name if user didn't select */
|
|
843
2012
|
OnFKBlur() {
|
|
844
|
-
// Small delay so mousedown on dropdown items fires first
|
|
2013
|
+
// Small delay so mousedown on dropdown items / scope menu fires first
|
|
845
2014
|
setTimeout(() => {
|
|
846
|
-
this.
|
|
847
|
-
this.
|
|
2015
|
+
this.closeFKDropdown();
|
|
2016
|
+
this.FKShowScopeMenu = false;
|
|
2017
|
+
this.FKFocused = false; // hide the scope pill
|
|
848
2018
|
// If user was typing but didn't select, revert to display name
|
|
849
2019
|
if (!this.FKIsMatched && this._fkInputText !== null) {
|
|
850
2020
|
this._fkInputText = null;
|
|
@@ -852,14 +2022,66 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
852
2022
|
this.cdr.markForCheck();
|
|
853
2023
|
}, 200);
|
|
854
2024
|
}
|
|
855
|
-
/**
|
|
2025
|
+
/**
|
|
2026
|
+
* Keyboard navigation in the FK input: ArrowDown/ArrowUp move the active row,
|
|
2027
|
+
* Enter selects it, Escape closes the dropdown.
|
|
2028
|
+
*/
|
|
2029
|
+
OnFKKeydown(event) {
|
|
2030
|
+
if (!this.ShowFKDropdown || this.FKSuggestions.length === 0) {
|
|
2031
|
+
if (event.key === 'Escape') {
|
|
2032
|
+
this.closeFKDropdown();
|
|
2033
|
+
this.cdr.markForCheck();
|
|
2034
|
+
}
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
switch (event.key) {
|
|
2038
|
+
case 'ArrowDown':
|
|
2039
|
+
event.preventDefault();
|
|
2040
|
+
this.FKActiveIndex = Math.min(this.FKActiveIndex + 1, this.FKSuggestions.length - 1);
|
|
2041
|
+
this.scrollActiveOptionIntoView();
|
|
2042
|
+
this.cdr.markForCheck();
|
|
2043
|
+
break;
|
|
2044
|
+
case 'ArrowUp':
|
|
2045
|
+
event.preventDefault();
|
|
2046
|
+
this.FKActiveIndex = Math.max(this.FKActiveIndex - 1, 0);
|
|
2047
|
+
this.scrollActiveOptionIntoView();
|
|
2048
|
+
this.cdr.markForCheck();
|
|
2049
|
+
break;
|
|
2050
|
+
case 'Enter': {
|
|
2051
|
+
const active = this.FKSuggestions[this.FKActiveIndex];
|
|
2052
|
+
if (active) {
|
|
2053
|
+
event.preventDefault();
|
|
2054
|
+
this.selectFKSuggestion(active);
|
|
2055
|
+
}
|
|
2056
|
+
break;
|
|
2057
|
+
}
|
|
2058
|
+
case 'Escape':
|
|
2059
|
+
event.preventDefault();
|
|
2060
|
+
this.closeFKDropdown();
|
|
2061
|
+
this.cdr.markForCheck();
|
|
2062
|
+
break;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
/** Scroll the keyboard-active option into view inside the (possibly portaled) dropdown. */
|
|
2066
|
+
scrollActiveOptionIntoView() {
|
|
2067
|
+
Promise.resolve().then(() => {
|
|
2068
|
+
const dropdown = this._portaledDropdownEl
|
|
2069
|
+
?? this.hostRef?.nativeElement?.querySelector('.mj-fk-dropdown');
|
|
2070
|
+
const active = dropdown?.querySelectorAll('.mj-fk-option')[this.FKActiveIndex];
|
|
2071
|
+
active?.scrollIntoView({ block: 'nearest' });
|
|
2072
|
+
});
|
|
2073
|
+
}
|
|
2074
|
+
/** Select an item from the FK dropdown (mouse) */
|
|
856
2075
|
OnFKSelectItem(suggestion, event) {
|
|
857
2076
|
event.preventDefault();
|
|
2077
|
+
this.selectFKSuggestion(suggestion);
|
|
2078
|
+
}
|
|
2079
|
+
/** Shared selection logic for mouse-click and keyboard-Enter. */
|
|
2080
|
+
selectFKSuggestion(suggestion) {
|
|
858
2081
|
this._fkInputText = suggestion.DisplayName;
|
|
859
2082
|
this.Value = suggestion.PrimaryKeyValue;
|
|
860
2083
|
this.FKIsMatched = true;
|
|
861
|
-
this.
|
|
862
|
-
this.stopScrollListener();
|
|
2084
|
+
this.closeFKDropdown();
|
|
863
2085
|
// Update virtual name field for visual consistency after save
|
|
864
2086
|
const nameFieldMap = this.FieldInfo?.RelatedEntityNameFieldMap;
|
|
865
2087
|
if (nameFieldMap) {
|
|
@@ -867,72 +2089,150 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
867
2089
|
}
|
|
868
2090
|
this.cdr.markForCheck();
|
|
869
2091
|
}
|
|
2092
|
+
// ---- Inline "create new related record" ----
|
|
2093
|
+
/**
|
|
2094
|
+
* Whether to show the inline-create affordance: the field opts in (`AllowFKCreate`),
|
|
2095
|
+
* the related entity resolves, and the current user can create records of it (entity
|
|
2096
|
+
* allows creation + role permits — `GetUserPermisions().CanCreate` folds in `AllowCreateAPI`).
|
|
2097
|
+
*/
|
|
2098
|
+
get CanCreateFK() {
|
|
2099
|
+
if (!this.AllowFKCreate)
|
|
2100
|
+
return false;
|
|
2101
|
+
const re = this.getRelatedEntityInfo();
|
|
2102
|
+
const user = this.ProviderToUse?.CurrentUser;
|
|
2103
|
+
if (!re || !user)
|
|
2104
|
+
return false;
|
|
2105
|
+
return re.GetUserPermisions(user)?.CanCreate === true;
|
|
2106
|
+
}
|
|
2107
|
+
/** Footer label: prefilled with the typed text when present, else generic "create new". */
|
|
2108
|
+
get FKCreateLabel() {
|
|
2109
|
+
const entityLabel = this.getRelatedEntityInfo()?.DisplayName || this.FieldInfo?.RelatedEntity || 'record';
|
|
2110
|
+
const query = this._fkQuery.trim();
|
|
2111
|
+
return query ? `Create "${query}"` : `Create new ${entityLabel}`;
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Ask the host (app layer) to create a new related record, prefilled with the typed
|
|
2115
|
+
* text as the name. We only EMIT the request — opening the form is the app's job (the
|
|
2116
|
+
* generic forms layer must not depend on the app-level form presenter). The host calls
|
|
2117
|
+
* `Complete(record)` when saved and we select it.
|
|
2118
|
+
*/
|
|
2119
|
+
OnFKCreateNew(event) {
|
|
2120
|
+
event.preventDefault(); // don't blur the input before we capture the query
|
|
2121
|
+
const plan = this.buildColumnPlan();
|
|
2122
|
+
const relatedEntity = this.FieldInfo?.RelatedEntity;
|
|
2123
|
+
if (!plan || !relatedEntity)
|
|
2124
|
+
return;
|
|
2125
|
+
const query = this._fkQuery.trim();
|
|
2126
|
+
this.FKShowScopeMenu = false;
|
|
2127
|
+
this.FKFocused = false;
|
|
2128
|
+
this.closeFKDropdown();
|
|
2129
|
+
this.cdr.markForCheck();
|
|
2130
|
+
const newRecordValues = {};
|
|
2131
|
+
if (query)
|
|
2132
|
+
newRecordValues[plan.NameFieldName] = query;
|
|
2133
|
+
this.Navigate.emit({
|
|
2134
|
+
Kind: 'create-related',
|
|
2135
|
+
EntityName: relatedEntity,
|
|
2136
|
+
NewRecordValues: Object.keys(newRecordValues).length ? newRecordValues : undefined,
|
|
2137
|
+
Presentation: this.FKCreatePresentation,
|
|
2138
|
+
Provider: this.Provider ?? undefined,
|
|
2139
|
+
Complete: (created) => { if (created)
|
|
2140
|
+
this.selectCreatedFKRecord(created, plan); },
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
/** Select a freshly-created related record as this field's value. */
|
|
2144
|
+
selectCreatedFKRecord(created, plan) {
|
|
2145
|
+
const pk = created.Get(plan.PkFieldName);
|
|
2146
|
+
if (pk == null)
|
|
2147
|
+
return;
|
|
2148
|
+
const name = this.formatCell(created.Get(plan.NameFieldName));
|
|
2149
|
+
this._fkInputText = name;
|
|
2150
|
+
this.Value = pk;
|
|
2151
|
+
this.FKIsMatched = true;
|
|
2152
|
+
const nameFieldMap = this.FieldInfo?.RelatedEntityNameFieldMap;
|
|
2153
|
+
if (nameFieldMap)
|
|
2154
|
+
this.Record.Set(nameFieldMap, name);
|
|
2155
|
+
this.closeFKDropdown();
|
|
2156
|
+
this.cdr.markForCheck();
|
|
2157
|
+
}
|
|
870
2158
|
/** Clear FK value via the X button */
|
|
871
2159
|
OnFKClearClick(event) {
|
|
2160
|
+
// preventDefault keeps focus on the input (the button never steals it), so the
|
|
2161
|
+
// freshly-opened dropdown stays open for the user to pick a replacement.
|
|
872
2162
|
event.preventDefault();
|
|
873
2163
|
this.Value = null;
|
|
874
2164
|
this._fkInputText = null;
|
|
875
2165
|
this.FKIsMatched = false;
|
|
876
|
-
this.FKSuggestions = [];
|
|
877
|
-
this.ShowFKDropdown = false;
|
|
878
|
-
this.stopScrollListener();
|
|
879
2166
|
this._resolvedFKName = undefined;
|
|
880
2167
|
this._resolvedFKValue = undefined;
|
|
881
2168
|
const nameFieldMap = this.FieldInfo?.RelatedEntityNameFieldMap;
|
|
882
2169
|
if (nameFieldMap) {
|
|
883
2170
|
this.Record.Set(nameFieldMap, '');
|
|
884
2171
|
}
|
|
2172
|
+
// Re-open the full list — clearing almost always precedes picking something else.
|
|
2173
|
+
this.showInitialFKSuggestions();
|
|
885
2174
|
this.cdr.markForCheck();
|
|
886
2175
|
}
|
|
2176
|
+
/** Close the FK dropdown and reset its transient view state. */
|
|
2177
|
+
closeFKDropdown() {
|
|
2178
|
+
this.ShowFKDropdown = false;
|
|
2179
|
+
this.FKLoading = false;
|
|
2180
|
+
this.FKNoMatches = false;
|
|
2181
|
+
this.FKActiveIndex = -1;
|
|
2182
|
+
this.FKSelectedSuggestion = null;
|
|
2183
|
+
this._portaledDropdownEl = null;
|
|
2184
|
+
this.stopScrollListener();
|
|
2185
|
+
}
|
|
887
2186
|
/**
|
|
888
|
-
* Perform a RunView search on the related entity's name field
|
|
2187
|
+
* Perform a RunView search on the related entity's name field (DB path — used only
|
|
2188
|
+
* when no loaded engine caches the related entity unfiltered).
|
|
889
2189
|
* Falls back to searching by primary key when no NameField exists (single-field PKs only).
|
|
890
2190
|
*/
|
|
891
2191
|
async searchRelatedEntity(query) {
|
|
2192
|
+
const plan = this.buildColumnPlan();
|
|
892
2193
|
const fieldInfo = this.FieldInfo;
|
|
893
|
-
if (!fieldInfo?.RelatedEntity)
|
|
894
|
-
return;
|
|
895
|
-
const md = this.ProviderToUse;
|
|
896
|
-
const relatedEntity = md.Entities.find(e => e.Name === fieldInfo.RelatedEntity);
|
|
897
|
-
if (!relatedEntity)
|
|
2194
|
+
if (!plan || !fieldInfo?.RelatedEntity)
|
|
898
2195
|
return;
|
|
899
|
-
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
2196
|
+
this._fkQuery = query;
|
|
2197
|
+
const seq = ++this._fkSearchSeq;
|
|
2198
|
+
this.FKLoading = true;
|
|
2199
|
+
this.FKNoMatches = false;
|
|
2200
|
+
this.ShowFKDropdown = true;
|
|
2201
|
+
if (this._lastFKInputEl) {
|
|
2202
|
+
this.updateDropdownPosition(this._lastFKInputEl);
|
|
2203
|
+
this.startScrollListener();
|
|
2204
|
+
this.portalDropdownToBody();
|
|
905
2205
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
//
|
|
909
|
-
const
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
2206
|
+
this.cdr.markForCheck();
|
|
2207
|
+
// Build Fields: PK + name + extra DefaultInView columns + the searched field +
|
|
2208
|
+
// the per-row icon field (when present), deduped via Set.
|
|
2209
|
+
const searchField = this.FKSearchField || plan.NameFieldName;
|
|
2210
|
+
const fields = Array.from(new Set([
|
|
2211
|
+
plan.PkFieldName, plan.NameFieldName, ...plan.ExtraFieldNames, searchField,
|
|
2212
|
+
...(plan.IconFieldName ? [plan.IconFieldName] : [])
|
|
2213
|
+
]));
|
|
2214
|
+
const escapedQuery = query.replace(/'/g, "''").trim();
|
|
913
2215
|
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
914
2216
|
const result = await rv.RunView({
|
|
915
2217
|
EntityName: fieldInfo.RelatedEntity,
|
|
916
|
-
|
|
917
|
-
|
|
2218
|
+
// Empty query (focus / cleared field) → no filter → first N rows.
|
|
2219
|
+
ExtraFilter: escapedQuery ? `[${searchField}] LIKE '%${escapedQuery}%'` : '',
|
|
2220
|
+
MaxRows: MjFormFieldComponent.FK_DB_SEARCH_LIMIT,
|
|
918
2221
|
ResultType: 'simple',
|
|
919
2222
|
Fields: fields
|
|
920
2223
|
});
|
|
2224
|
+
// Ignore stale responses (a newer keystroke already fired).
|
|
2225
|
+
if (seq !== this._fkSearchSeq)
|
|
2226
|
+
return;
|
|
2227
|
+
this.FKLoading = false;
|
|
921
2228
|
if (result.Success) {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
DisplayName: String(r[nameFieldName] || '')
|
|
925
|
-
}));
|
|
926
|
-
if (this.FKSuggestions.length > 0 && this._lastFKInputEl) {
|
|
927
|
-
this.updateDropdownPosition(this._lastFKInputEl);
|
|
928
|
-
this.startScrollListener();
|
|
929
|
-
}
|
|
930
|
-
this.ShowFKDropdown = this.FKSuggestions.length > 0;
|
|
2229
|
+
const accessor = (r) => ({ get: (field) => r[field] });
|
|
2230
|
+
this.applySuggestions(this.buildSuggestions(result.Results.map(accessor), plan, query), plan);
|
|
931
2231
|
}
|
|
932
2232
|
else {
|
|
933
2233
|
this.FKSuggestions = [];
|
|
934
|
-
this.
|
|
935
|
-
this.
|
|
2234
|
+
this.FKNoMatches = true;
|
|
2235
|
+
this.ShowFKDropdown = true;
|
|
936
2236
|
}
|
|
937
2237
|
this.cdr.markForCheck();
|
|
938
2238
|
}
|
|
@@ -1025,10 +2325,101 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
1025
2325
|
// ============================================
|
|
1026
2326
|
// GENERAL PROPERTIES
|
|
1027
2327
|
// ============================================
|
|
1028
|
-
/** Whether the field's varchar(max) - long text that gets
|
|
2328
|
+
/** Whether the field's varchar(max) - long text that gets the wide read-only style */
|
|
1029
2329
|
get IsLongText() {
|
|
1030
2330
|
return this.FieldInfo?.Length === -1;
|
|
1031
2331
|
}
|
|
2332
|
+
/**
|
|
2333
|
+
* Whether this field is large enough to be a candidate for rich-text (markdown/html)
|
|
2334
|
+
* auto-detection. Generic & multi-platform: keys off the TS type and character length
|
|
2335
|
+
* rather than a specific SQL type, so nvarchar(max)/ntext (MaxLength === 0 means
|
|
2336
|
+
* unlimited) and longer fixed fields (nvarchar(400)/varchar(500)/...) all qualify,
|
|
2337
|
+
* while short strings, UUIDs, numbers, dates, etc. do not.
|
|
2338
|
+
*/
|
|
2339
|
+
get IsRichTextEligible() {
|
|
2340
|
+
const fi = this.FieldInfo;
|
|
2341
|
+
if (!fi || fi.TSType !== EntityFieldTSType.String)
|
|
2342
|
+
return false;
|
|
2343
|
+
const maxLen = fi.MaxLength;
|
|
2344
|
+
return maxLen === 0 || maxLen >= 255;
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* Resolved rendering mode for this field. Honors an explicit `ExtendedType` first
|
|
2348
|
+
* ('Markdown' | 'HTML' | 'Code'); when `ExtendedType` is null, falls back to lightweight
|
|
2349
|
+
* client-side content detection — but only for {@link IsRichTextEligible} long-text fields.
|
|
2350
|
+
*/
|
|
2351
|
+
get RichTextMode() {
|
|
2352
|
+
const fi = this.FieldInfo;
|
|
2353
|
+
if (!fi)
|
|
2354
|
+
return 'plain';
|
|
2355
|
+
switch (fi.ExtendedType) {
|
|
2356
|
+
case 'Markdown': return 'markdown';
|
|
2357
|
+
case 'HTML': return 'html';
|
|
2358
|
+
case 'Code': return 'code';
|
|
2359
|
+
}
|
|
2360
|
+
// Any other explicit ExtendedType (Email, URL, Geo*, Tel, ...) is not rich text here.
|
|
2361
|
+
if (fi.ExtendedType != null)
|
|
2362
|
+
return 'plain';
|
|
2363
|
+
// ExtendedType is null → auto-detect, but only on eligible long-text fields.
|
|
2364
|
+
if (!this.IsRichTextEligible)
|
|
2365
|
+
return 'plain';
|
|
2366
|
+
return this.detectFormat();
|
|
2367
|
+
}
|
|
2368
|
+
/** Backing snapshot for {@link EditRichTextMode}; null until first computed for the session. */
|
|
2369
|
+
_editRichTextMode = null;
|
|
2370
|
+
/**
|
|
2371
|
+
* Stable rendering mode for EDIT mode. Unlike {@link RichTextMode} (which re-detects on the
|
|
2372
|
+
* live value), this is snapshotted when edit mode is entered so that typing markdown/html into
|
|
2373
|
+
* a plain textarea doesn't swap the control out from under the user mid-keystroke. Explicit
|
|
2374
|
+
* ExtendedType always wins regardless; only the auto-detect branch is frozen for the session.
|
|
2375
|
+
*/
|
|
2376
|
+
get EditRichTextMode() {
|
|
2377
|
+
if (this._editRichTextMode === null) {
|
|
2378
|
+
this._editRichTextMode = this.RichTextMode;
|
|
2379
|
+
}
|
|
2380
|
+
return this._editRichTextMode;
|
|
2381
|
+
}
|
|
2382
|
+
/** Cached detection result, keyed by the exact string value it was computed from. */
|
|
2383
|
+
_detectCacheValue = null;
|
|
2384
|
+
_detectCacheResult = 'plain';
|
|
2385
|
+
/** Memoized content detection so the getter stays cheap under OnPush change detection. */
|
|
2386
|
+
detectFormat() {
|
|
2387
|
+
const raw = this.Value;
|
|
2388
|
+
const text = raw == null ? '' : String(raw);
|
|
2389
|
+
if (text !== this._detectCacheValue) {
|
|
2390
|
+
this._detectCacheValue = text;
|
|
2391
|
+
this._detectCacheResult = detectRichTextFormat(text);
|
|
2392
|
+
}
|
|
2393
|
+
return this._detectCacheResult;
|
|
2394
|
+
}
|
|
2395
|
+
/**
|
|
2396
|
+
* Editor language for the code editor. In edit mode it tracks the frozen
|
|
2397
|
+
* {@link EditRichTextMode}; in read mode it tracks the live {@link RichTextMode}.
|
|
2398
|
+
*/
|
|
2399
|
+
get CodeEditorLanguage() {
|
|
2400
|
+
const mode = this.EditMode ? this.EditRichTextMode : this.RichTextMode;
|
|
2401
|
+
switch (mode) {
|
|
2402
|
+
case 'markdown': return 'markdown';
|
|
2403
|
+
case 'html': return 'html';
|
|
2404
|
+
case 'code': return this.codeTypeToLanguage(this.FieldInfo?.CodeType);
|
|
2405
|
+
default: return '';
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
/** Map the field's CodeType metadata value to a CodeMirror language id. */
|
|
2409
|
+
codeTypeToLanguage(codeType) {
|
|
2410
|
+
switch (codeType) {
|
|
2411
|
+
case 'CSS': return 'css';
|
|
2412
|
+
case 'HTML': return 'html';
|
|
2413
|
+
case 'JavaScript': return 'javascript';
|
|
2414
|
+
case 'SQL': return 'sql';
|
|
2415
|
+
case 'TypeScript': return 'typescript';
|
|
2416
|
+
default: return ''; // 'Other' / null → plain code editing
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
/** Handle value changes coming from the embedded code editor (emits a plain string). */
|
|
2420
|
+
OnCodeEditorChange(value) {
|
|
2421
|
+
this.Value = value;
|
|
2422
|
+
}
|
|
1032
2423
|
/** Format a value for display */
|
|
1033
2424
|
FormatValue() {
|
|
1034
2425
|
const val = this.Value;
|
|
@@ -1045,20 +2436,45 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
1045
2436
|
if (changes['Record']) {
|
|
1046
2437
|
this._fkInputText = null;
|
|
1047
2438
|
this.FKIsMatched = false;
|
|
2439
|
+
this._fkQuery = '';
|
|
1048
2440
|
this.FKSuggestions = [];
|
|
2441
|
+
this.FKSelectedSuggestion = null;
|
|
1049
2442
|
this.ShowFKDropdown = false;
|
|
2443
|
+
this.FKActiveIndex = -1;
|
|
2444
|
+
this.FKLoading = false;
|
|
2445
|
+
this.FKNoMatches = false;
|
|
2446
|
+
this.FKColumnHeaders = [];
|
|
2447
|
+
this.FKColumnFields = [];
|
|
2448
|
+
this.FKSortField = null;
|
|
2449
|
+
this.FKSortDir = 'asc';
|
|
2450
|
+
this._fkSuggestionsNatural = [];
|
|
2451
|
+
this.FKSearchableFields = [];
|
|
2452
|
+
this.FKShowScopeMenu = false;
|
|
2453
|
+
this.FKFocused = false;
|
|
2454
|
+
this._fkColWidths = {};
|
|
2455
|
+
this._fkPrefKey = null; // force prefs reload for the new field
|
|
2456
|
+
this._portaledDropdownEl = null;
|
|
2457
|
+
this._fkColumnPlan = null;
|
|
1050
2458
|
this._resolvedFKName = undefined;
|
|
1051
2459
|
this._resolvedFKValue = undefined;
|
|
1052
2460
|
this._fkNameLoading = false;
|
|
1053
2461
|
// Reset validation state for new record
|
|
1054
2462
|
this._touched = false;
|
|
1055
2463
|
this._fieldErrors = [];
|
|
2464
|
+
// Invalidate cached rich-text detection (recomputed lazily for the new value)
|
|
2465
|
+
this._detectCacheValue = null;
|
|
2466
|
+
this._detectCacheResult = 'plain';
|
|
2467
|
+
this._editRichTextMode = null;
|
|
1056
2468
|
}
|
|
1057
2469
|
// Reset validation state when exiting edit mode
|
|
1058
2470
|
if (changes['EditMode'] && !this.EditMode) {
|
|
1059
2471
|
this._touched = false;
|
|
1060
2472
|
this._fieldErrors = [];
|
|
1061
2473
|
}
|
|
2474
|
+
// Re-snapshot the edit-mode rendering decision whenever edit mode toggles
|
|
2475
|
+
if (changes['EditMode']) {
|
|
2476
|
+
this._editRichTextMode = null;
|
|
2477
|
+
}
|
|
1062
2478
|
this.cdr.markForCheck();
|
|
1063
2479
|
}
|
|
1064
2480
|
}
|
|
@@ -1066,7 +2482,15 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
1066
2482
|
if (this._fkSearchTimeout) {
|
|
1067
2483
|
clearTimeout(this._fkSearchTimeout);
|
|
1068
2484
|
}
|
|
2485
|
+
this.teardownFKResizeListeners();
|
|
1069
2486
|
this.stopScrollListener();
|
|
2487
|
+
// If we relocated the dropdown to <body> and Angular tears us down while it's
|
|
2488
|
+
// still open, remove the orphaned node ourselves (Angular removes by reference,
|
|
2489
|
+
// but guard against a race where the view is destroyed before the @if updates).
|
|
2490
|
+
if (this._portaledDropdownEl && this._portaledDropdownEl.parentElement === document.body) {
|
|
2491
|
+
this.renderer.removeChild(document.body, this._portaledDropdownEl);
|
|
2492
|
+
}
|
|
2493
|
+
this._portaledDropdownEl = null;
|
|
1070
2494
|
}
|
|
1071
2495
|
// ---- Navigation Handlers ----
|
|
1072
2496
|
/**
|
|
@@ -1164,15 +2588,15 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
1164
2588
|
return date.toISOString().split('T')[0];
|
|
1165
2589
|
}
|
|
1166
2590
|
static ɵfac = /*@__PURE__*/ (() => { let ɵMjFormFieldComponent_BaseFactory; return function MjFormFieldComponent_Factory(__ngFactoryType__) { return (ɵMjFormFieldComponent_BaseFactory || (ɵMjFormFieldComponent_BaseFactory = i0.ɵɵgetInheritedFactory(MjFormFieldComponent)))(__ngFactoryType__ || MjFormFieldComponent); }; })();
|
|
1167
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MjFormFieldComponent, selectors: [["mj-form-field"]], inputs: { Record: "Record", EditMode: "EditMode", FieldName: "FieldName", Type: "Type", LinkType: "LinkType", ShowLabel: "ShowLabel", FormContext: "FormContext", _deprecatedRecord: [0, "record", "_deprecatedRecord"], _deprecatedFormContext: [0, "formContext", "_deprecatedFormContext"], HideWhenEmptyInReadOnlyMode: "HideWhenEmptyInReadOnlyMode", DisplayNameOverride: "DisplayNameOverride", PossibleValuesOverride: "PossibleValuesOverride" }, outputs: { ValueChange: "ValueChange", Navigate: "Navigate" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [[1, "mj-forms-field", 3, "mj-forms-field--readonly", "mj-forms-field--dirty"], [1, "mj-forms-field", "mj-forms-field--editing", 3, "mj-forms-field--dirty", "mj-forms-field--required-empty", "mj-forms-field--has-error", "mj-forms-field--has-warning"], [1, "mj-forms-field"], [1, "mj-forms-field-label", 3, "innerHTML"], [1, "mj-forms-field-control"], [1, "mj-forms-field-value"], ["title", "View related record", 1, "mj-forms-field-link", "mj-forms-field-link--fk", 3, "click"], ["title", "Send email", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-envelope", "mj-forms-field-link-icon"], ["title", "Open link", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square", "mj-forms-field-link-icon"], ["title", "View related record", 1, "mj-forms-field-link", 3, "click"], [1, "mj-forms-field-value", "mj-forms-field-value--long"], [1, "mj-forms-field-checkbox"], ["type", "checkbox", "disabled", "", 3, "checked"], [1, "mj-forms-field", "mj-forms-field--editing"], [1, "mj-fk-search", 3, "mj-fk-search--matched"], [1, "mj-forms-field-validation", "mj-forms-field-validation--error"], [1, "mj-forms-field-validation", "mj-forms-field-validation--warning"], [1, "mj-fk-search"], ["type", "text", "placeholder", "Search...", 1, "mj-forms-field-input", 3, "input", "focus", "blur", "value"], ["title", "Clear", 1, "mj-fk-clear"], [1, "fa-solid", "fa-magnifying-glass", "mj-fk-search-icon"], [1, "mj-fk-dropdown", 3, "ngStyle", "mj-fk-dropdown--above"], ["title", "Clear", 1, "mj-fk-clear", 3, "mousedown"], [1, "fa-solid", "fa-xmark"], [1, "mj-fk-dropdown", 3, "ngStyle"], [1, "mj-fk-
|
|
2591
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MjFormFieldComponent, selectors: [["mj-form-field"]], inputs: { Record: "Record", EditMode: "EditMode", FieldName: "FieldName", Type: "Type", LinkType: "LinkType", ShowLabel: "ShowLabel", FormContext: "FormContext", _deprecatedRecord: [0, "record", "_deprecatedRecord"], _deprecatedFormContext: [0, "formContext", "_deprecatedFormContext"], HideWhenEmptyInReadOnlyMode: "HideWhenEmptyInReadOnlyMode", DisplayNameOverride: "DisplayNameOverride", PossibleValuesOverride: "PossibleValuesOverride", FKDropdownMaxWidth: "FKDropdownMaxWidth", FKHighlightMatches: "FKHighlightMatches", AllowFKCreate: "AllowFKCreate", FKCreatePresentation: "FKCreatePresentation" }, outputs: { ValueChange: "ValueChange", Navigate: "Navigate" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [["scopeRow", ""], [1, "mj-forms-field", 3, "mj-forms-field--readonly", "mj-forms-field--dirty"], [1, "mj-forms-field", "mj-forms-field--editing", 3, "mj-forms-field--dirty", "mj-forms-field--required-empty", "mj-forms-field--has-error", "mj-forms-field--has-warning"], [1, "mj-forms-field"], [1, "mj-forms-field-label", 3, "innerHTML"], [1, "mj-forms-field-control"], [1, "mj-forms-field-value"], ["title", "View related record", 1, "mj-forms-field-link", "mj-forms-field-link--fk"], ["title", "View related record", 1, "mj-forms-field-link", "mj-forms-field-link--fk", 3, "click"], ["title", "Send email", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-envelope", "mj-forms-field-link-icon"], ["title", "Open link", 1, "mj-forms-field-link", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square", "mj-forms-field-link-icon"], ["title", "View related record", 1, "mj-forms-field-link"], ["title", "View related record", 1, "mj-forms-field-link", 3, "click"], [1, "mj-forms-field-value", "mj-forms-field-value--rich"], [1, "mj-forms-field-value", "mj-forms-field-value--rich", 3, "innerHTML"], [1, "mj-forms-field-value", "mj-forms-field-value--code"], [1, "mj-forms-field-value", "mj-forms-field-value--long"], [1, "mj-forms-field-checkbox"], ["type", "checkbox", "disabled", "", 3, "checked"], [3, "data"], [3, "value", "language", "readonly"], [1, "mj-forms-field", "mj-forms-field--editing"], [1, "mj-fk-search", 3, "mj-fk-search--matched", "mj-fk-search--scoped"], [1, "mj-forms-field-input--code", 3, "value", "language"], [1, "mj-forms-field-validation", "mj-forms-field-validation--error"], [1, "mj-forms-field-validation", "mj-forms-field-validation--warning"], [1, "mj-fk-search"], ["title", "Linked record", 1, "fa-solid", "fa-link", "mj-fk-link-icon"], ["type", "text", "placeholder", "Search...", 1, "mj-forms-field-input", 3, "input", "focus", "blur", "keydown", "value"], [1, "mj-fk-scope-pill", 3, "mj-fk-scope-pill--open", "title"], ["title", "Clear", 1, "mj-fk-clear"], [1, "fa-solid", "fa-magnifying-glass", "mj-fk-search-icon"], [1, "mj-fk-dropdown", "mj-fk-dropdown--multi", 3, "ngStyle", "mj-fk-dropdown--above", "mj-fk-dropdown--scope-open"], [1, "mj-fk-scope-pill", 3, "mousedown", "title"], [1, "fa-solid", "fa-magnifying-glass", "mj-fk-scope-pill-icon"], [1, "mj-fk-scope-pill-label"], [1, "fa-solid", "mj-fk-scope-pill-caret"], ["title", "Clear", 1, "mj-fk-clear", 3, "mousedown"], [1, "fa-solid", "fa-xmark"], [1, "mj-fk-dropdown", "mj-fk-dropdown--multi", 3, "ngStyle"], [1, "mj-fk-scope-menu", 3, "mj-fk-scope-menu--bottom"], [1, "mj-fk-current"], [1, "mj-fk-status"], [1, "mj-fk-status", "mj-fk-status--empty"], [1, "mj-fk-options"], ["type", "button", 1, "mj-fk-create-footer", 3, "title"], [1, "mj-fk-scope-menu"], [1, "mj-fk-scope-grp"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "mj-fk-scope-divider"], [1, "mj-fk-scope-mi", 3, "mousedown"], [1, "mj-fk-col-reorder"], [1, "mj-fk-scope-mi-label"], [1, "mj-fk-col-eye-slot"], ["type", "button", 1, "mj-fk-col-toggle", 3, "mj-fk-col-toggle--on", "title"], ["type", "button", "title", "Move column up", 1, "mj-fk-col-move", "mj-fk-col-move--up", 3, "mousedown", "disabled"], [1, "fa-solid", "fa-chevron-up"], ["type", "button", "title", "Move column down", 1, "mj-fk-col-move", "mj-fk-col-move--down", 3, "mousedown", "disabled"], [1, "fa-solid", "fa-chevron-down"], ["type", "button", 1, "mj-fk-col-toggle", 3, "mousedown", "title"], [1, "fa-solid"], [1, "mj-fk-current-head"], [1, "fa-solid", "fa-circle-check"], ["title", "Keep this selection", 1, "mj-fk-current-row", 3, "mousedown"], [1, "mj-fk-current-icon", 3, "class"], [1, "mj-fk-current-name", 3, "innerHTML"], [1, "mj-fk-current-detail"], ["type", "button", "title", "Clear selection", 1, "mj-fk-current-clear", 3, "mousedown"], [1, "mj-fk-current-icon"], [1, "fa-solid", "fa-circle-notch", "fa-spin"], [1, "fa-solid", "fa-magnifying-glass"], [1, "mj-fk-grid"], [1, "mj-fk-grid-row", "mj-fk-grid-row--header"], [1, "mj-fk-hcell", "mj-fk-hcell--icon"], [1, "mj-fk-hcell", 3, "title"], [1, "mj-fk-grid-row", 3, "mj-fk-grid-row--active", "mj-fk-grid-row--selected"], [1, "mj-fk-hcell", 3, "mousedown", "title"], [1, "mj-fk-hcell-label"], ["title", "Drag to resize", 1, "mj-fk-resizer", 3, "mousedown"], [1, "mj-fk-grid-row", 3, "mousedown", "mouseenter"], [1, "mj-fk-cell", "mj-fk-cell--icon"], [3, "class"], [1, "mj-fk-cell", "mj-fk-cell--name", 3, "mj-fk-cell--fill"], [1, "mj-fk-cell", 3, "mj-fk-cell--fill", "title"], [1, "mj-fk-cell", "mj-fk-cell--name"], ["title", "Currently selected", 1, "fa-solid", "fa-check", "mj-fk-selected-check"], [3, "innerHTML"], [1, "mj-fk-cell", 3, "title"], ["type", "button", 1, "mj-fk-create-footer", 3, "mousedown", "title"], [1, "fa-solid", "fa-plus", "mj-fk-create-icon"], [1, "mj-fk-create-label"], [1, "mj-forms-field-input--code", 3, "change", "value", "language"], ["type", "text", 1, "mj-forms-field-input", 3, "value"], [1, "mj-forms-field-input", "mj-forms-field-input--textarea", 3, "value"], ["type", "number", 1, "mj-forms-field-input", "mj-forms-field-input--number", 3, "value"], ["type", "date", 1, "mj-forms-field-input", "mj-forms-field-input--date", 3, "value"], ["type", "text", 1, "mj-forms-field-input", 3, "input", "value"], [1, "mj-forms-field-input", "mj-forms-field-input--textarea", 3, "input", "value"], ["type", "number", 1, "mj-forms-field-input", "mj-forms-field-input--number", 3, "change", "value"], ["type", "date", 1, "mj-forms-field-input", "mj-forms-field-input--date", 3, "change", "value"], ["type", "checkbox", 3, "change", "checked"], ["tabindex", "0", 1, "mj-custom-select-trigger", 3, "click", "blur"], [1, "mj-custom-select-value"], [1, "fa-solid", "fa-chevron-down", "mj-custom-select-chevron"], [1, "mj-fk-dropdown", 3, "ngStyle", "mj-fk-dropdown--above"], [1, "mj-fk-dropdown", 3, "ngStyle"], [1, "mj-fk-option", 3, "mj-fk-option--selected"], [1, "mj-fk-option", 3, "mousedown"], ["type", "text", "placeholder", "Type to search...", 1, "mj-forms-field-input", 3, "input", "focus", "blur", "value"], [1, "mj-fk-option"], ["type", "text", 1, "mj-forms-field-input", 3, "change", "value"], [1, "mj-forms-field-validation-item"], [1, "fa-solid", "fa-circle-exclamation"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function MjFormFieldComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1168
2592
|
i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Template, 2, 2);
|
|
1169
2593
|
} if (rf & 2) {
|
|
1170
2594
|
i0.ɵɵconditional(ctx.Record && (ctx.Record.IsSaved || !ctx.IsFieldReadOnly) ? 0 : -1);
|
|
1171
|
-
} }, dependencies: [i1.NgStyle], styles: ["\n\n\n\n[_nghost-%COMP%] {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n\n\n.mj-forms-field--editing[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n\n\n\n\n.mj-forms-field-control[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n\n\n\n.mj-forms-field--dirty[_ngcontent-%COMP%] .mj-forms-field-label[_ngcontent-%COMP%]::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n\n\n\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n\n\n\n\n.mj-forms-field-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] .mj-forms-field-value[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.mj-forms-field-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover .mj-forms-field-link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.mj-forms-field-link--fk[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 400;\n}\n\n\n\n\n\n.mj-forms-field-input[_ngcontent-%COMP%] {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n\n\n.mj-forms-field-input--number[_ngcontent-%COMP%] {\n max-width: 200px;\n}\n\n\n\n.mj-forms-field-input--date[_ngcontent-%COMP%] {\n max-width: 220px;\n}\n\n\n\n\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n\n\n\n\n.mj-custom-select-trigger[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n\n\n.mj-fk-search[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n\n\n.mj-fk-search--matched[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n\n\n\n\n.mj-fk-dropdown[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] [_ngcontent-%COMP%]:global(.mj-forms-search-highlight) {\n background-color: var(--mj-color-warning-200, #fef08a);\n color: var(--mj-color-warning-800, #854d0e);\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px var(--mj-color-warning-200, #fef08a);\n}\n\n\n\n\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: _ngcontent-%COMP%_mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-700);\n}\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n@keyframes _ngcontent-%COMP%_mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n\n\n\n\n@media (max-width: 640px) {\n .mj-forms-field[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 1;\n }\n}"], changeDetection: 0 });
|
|
2595
|
+
} }, dependencies: [i1.NgTemplateOutlet, i1.NgStyle, i2.MarkdownComponent, i3.CodeEditorComponent, i4.MJSafeRichHtmlPipe], styles: ["\n\n\n\n[_nghost-%COMP%] {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n\n\n.mj-forms-field--editing[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n\n\n\n\n.mj-forms-field-control[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n\n\n\n.mj-forms-field--dirty[_ngcontent-%COMP%] .mj-forms-field-label[_ngcontent-%COMP%]::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n\n\n\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n\n\n\n\n.mj-forms-field-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n\n\n.mj-forms-field-value--rich[_ngcontent-%COMP%] {\n display: block;\n align-items: initial;\n max-height: 480px;\n overflow: auto;\n width: 100%;\n}\n\n\n\n.mj-forms-field-value--code[_ngcontent-%COMP%] {\n display: block;\n align-items: initial;\n width: 100%;\n}\n\n.mj-forms-field-value--code[_ngcontent-%COMP%] mj-code-editor[_ngcontent-%COMP%], \n.mj-forms-field-input--code[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n min-height: 160px;\n max-height: 480px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius, 4px);\n overflow: auto;\n}\n\n\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] .mj-forms-field-value[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.mj-forms-field-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover .mj-forms-field-link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.mj-forms-field-link--fk[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 400;\n}\n\n\n\n\n\n.mj-forms-field-input[_ngcontent-%COMP%] {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n\n\n.mj-forms-field-input--number[_ngcontent-%COMP%] {\n max-width: 200px;\n}\n\n\n\n.mj-forms-field-input--date[_ngcontent-%COMP%] {\n max-width: 220px;\n}\n\n\n\n\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n\n\n\n\n.mj-custom-select-trigger[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n\n\n.mj-fk-search[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n\n\n\n.mj-fk-search--matched[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n\n\n\n.mj-fk-link-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 26px;\n color: var(--mj-brand-primary);\n font-size: 10px;\n pointer-events: none;\n z-index: 1;\n}\n\n\n\n.mj-forms-field-input--linked[_ngcontent-%COMP%] {\n padding-right: 46px;\n}\n\n\n\n\n\n\n\n.mj-fk-search--scoped[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 150px;\n}\n\n.mj-fk-scope-pill[_ngcontent-%COMP%] {\n position: absolute;\n right: 30px;\n \n\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 120px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n font-size: 10.5px;\n font-weight: 600;\n font-family: inherit;\n \n\n padding: 1px 7px;\n border-radius: 999px;\n cursor: pointer;\n white-space: nowrap;\n line-height: 1.35;\n transition: background var(--mj-transition-base), border-color var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-pill[_ngcontent-%COMP%]:hover, \n.mj-fk-scope-pill--open[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-primary);\n}\n\n.mj-fk-scope-pill-icon[_ngcontent-%COMP%] {\n font-size: 9px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-pill-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-scope-pill-caret[_ngcontent-%COMP%] {\n font-size: 8px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n\n\n\n\n.mj-fk-scope-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 8px;\n z-index: 5;\n min-width: 180px;\n max-width: calc(100vw - 24px);\n max-height: 260px;\n overflow-y: auto;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n box-shadow: var(--mj-shadow-lg);\n padding: 5px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 120ms ease;\n}\n\n\n\n\n.mj-fk-scope-menu--bottom[_ngcontent-%COMP%] {\n top: auto;\n bottom: 4px;\n}\n\n.mj-fk-scope-grp[_ngcontent-%COMP%] {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n padding: 7px 10px 4px;\n font-weight: 700;\n}\n\n.mj-fk-scope-mi[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 13px;\n border-radius: 5px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.mj-fk-scope-mi[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-scope-mi--on[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n.mj-fk-col-reorder[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 22px;\n flex-shrink: 0;\n}\n\n.mj-fk-col-move[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 10px;\n padding: 0;\n background: transparent;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 8px;\n opacity: 0; \n\n transition: opacity var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-mi[_ngcontent-%COMP%]:hover .mj-fk-col-move[_ngcontent-%COMP%]:not(:disabled) {\n opacity: 0.8;\n}\n\n.mj-fk-col-move[_ngcontent-%COMP%]:hover:not(:disabled) {\n opacity: 1;\n color: var(--mj-brand-primary);\n}\n\n\n\n.mj-fk-col-move[_ngcontent-%COMP%]:disabled {\n opacity: 0 !important;\n cursor: default;\n}\n\n.mj-fk-scope-mi-icon[_ngcontent-%COMP%] {\n width: 14px;\n font-size: 11px;\n opacity: 0.75;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-mi-label[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.mj-fk-col-eye-slot[_ngcontent-%COMP%] {\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n\n.mj-fk-col-toggle[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-col-toggle[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n}\n\n.mj-fk-col-toggle--on[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-scope-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--mj-border-subtle);\n margin: 4px 6px;\n}\n\n\n\n\n@media (max-width: 560px) {\n .mj-fk-search--scoped[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 116px;\n }\n .mj-fk-scope-pill[_ngcontent-%COMP%] {\n max-width: 88px;\n }\n .mj-fk-scope-menu[_ngcontent-%COMP%] {\n min-width: 160px;\n }\n .mj-fk-scope-mi[_ngcontent-%COMP%] {\n padding: 10px 10px;\n }\n}\n\n\n\n\n\n.mj-fk-dropdown[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n\n\n\n\n\n.mj-fk-dropdown--multi[_ngcontent-%COMP%] {\n padding: 4px;\n \n\n\n overflow: hidden;\n max-height: none;\n}\n\n\n\n\n\n.mj-fk-dropdown--multi[_ngcontent-%COMP%] .mj-fk-options[_ngcontent-%COMP%] {\n overflow: auto;\n max-height: 260px;\n}\n\n\n\n\n.mj-fk-dropdown--scope-open[_ngcontent-%COMP%] {\n overflow: visible;\n}\n\n\n\n\n\n\n\n.mj-fk-grid[_ngcontent-%COMP%] {\n display: grid;\n width: 100%;\n min-width: max-content;\n align-items: stretch;\n}\n\n\n\n\n\n.mj-fk-grid-row[_ngcontent-%COMP%] {\n display: contents;\n}\n\n\n\n.mj-fk-hcell[_ngcontent-%COMP%] {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n}\n\n.mj-fk-hcell[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-hcell--icon[_ngcontent-%COMP%] {\n cursor: default;\n padding: 7px 8px;\n}\n\n.mj-fk-hcell--icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-elevated);\n}\n\n.mj-fk-hcell-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-sort-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n\n\n.mj-fk-sort-icon--idle[_ngcontent-%COMP%] {\n opacity: 0.35;\n}\n\n\n\n.mj-fk-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 320px;\n cursor: pointer;\n}\n\n\n\n\n.mj-fk-cell--fill[_ngcontent-%COMP%] {\n max-width: none;\n}\n\n\n\n\n.mj-fk-cell[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.mj-fk-cell--icon[_ngcontent-%COMP%] {\n justify-content: center;\n padding: 8px;\n max-width: none;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.mj-fk-cell--name[_ngcontent-%COMP%] {\n font-weight: 500;\n font-size: 14px;\n color: var(--mj-text-primary);\n gap: 6px;\n}\n\n.mj-fk-selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 11px;\n flex-shrink: 0;\n}\n\n\n\n\n.mj-fk-grid-row--active[_ngcontent-%COMP%] > .mj-fk-cell[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n\n\n\n.mj-fk-grid-row--selected[_ngcontent-%COMP%] > .mj-fk-cell[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n}\n\n.mj-fk-grid-row--selected[_ngcontent-%COMP%] > .mj-fk-cell--name[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n\n\n.mj-fk-cell--name[_ngcontent-%COMP%] .mj-forms-search-highlight, \n.mj-fk-cell[_ngcontent-%COMP%] .mj-forms-search-highlight {\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n\n\n.mj-fk-resizer[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n width: 7px;\n height: 100%;\n cursor: col-resize;\n user-select: none;\n}\n\n.mj-fk-resizer[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n top: 20%;\n right: 2px;\n width: 2px;\n height: 60%;\n background: transparent;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-hcell[_ngcontent-%COMP%]:hover .mj-fk-resizer[_ngcontent-%COMP%]::after, \n.mj-fk-resizer[_ngcontent-%COMP%]:hover::after {\n background: var(--mj-border-strong);\n}\n\n\n\n.mj-fk-status[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-status[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.mj-fk-status--empty[_ngcontent-%COMP%] {\n font-style: italic;\n}\n\n\n\n\n.mj-fk-create-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border: none;\n border-top: 1px solid var(--mj-border-default);\n color: var(--mj-brand-primary);\n font-size: 13px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-create-footer[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-create-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.mj-fk-create-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n\n\n.mj-fk-current[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n background: color-mix(in srgb, var(--mj-brand-primary) 7%, var(--mj-bg-surface-card));\n animation: _ngcontent-%COMP%_mj-fk-current-in 220ms cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n@keyframes _ngcontent-%COMP%_mj-fk-current-in {\n from { opacity: 0; transform: translateY(-6px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.mj-fk-current-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px 3px;\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-current-head[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.mj-fk-current-row[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 6px 12px 10px;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n\n\n.mj-fk-current-row[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: 0;\n top: 4px;\n bottom: 8px;\n width: 3px;\n border-radius: 0 2px 2px 0;\n background: var(--mj-brand-primary);\n}\n\n.mj-fk-current-row[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.mj-fk-current-icon[_ngcontent-%COMP%] {\n flex-shrink: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-current-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-detail[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-clear[_ngcontent-%COMP%] {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-current-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-status-error);\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] .mj-forms-search-highlight {\n \n\n\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n\n\n\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: _ngcontent-%COMP%_mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-status-warning-text);\n}\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n@keyframes _ngcontent-%COMP%_mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n\n\n\n\n@media (max-width: 640px) {\n .mj-forms-field[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 1;\n }\n}"], changeDetection: 0 });
|
|
1172
2596
|
}
|
|
1173
2597
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjFormFieldComponent, [{
|
|
1174
2598
|
type: Component,
|
|
1175
|
-
args: [{ standalone: false, selector: 'mj-form-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Record && (Record.IsSaved || !IsFieldReadOnly)) {\n <!-- READ-ONLY MODE -->\n @if ((!EditMode || IsFieldReadOnly) && !ShouldHideField) {\n <div class=\"mj-forms-field\" [class.mj-forms-field--readonly]=\"EditMode && IsFieldReadOnly\" [class.mj-forms-field--dirty]=\"IsDirty\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- FK fields with a mapped name field: show the name as a hyperlink -->\n @if (IsFKWithNameField) {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link mj-forms-field-link--fk\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FKDisplayName }}\n </a>\n </span>\n }\n @else {\n @switch (LinkType) {\n @case ('Email') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnEmailLinkClick($event)\" title=\"Send email\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-envelope mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('URL') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnUrlLinkClick($event)\" title=\"Open link\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('Record') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @default {\n @if (Type === 'checkbox') {\n <span class=\"mj-forms-field-value\">\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\" [checked]=\"!!Value\" disabled>\n </div>\n </span>\n }\n @else if (IsLongText) {\n <span class=\"mj-forms-field-value mj-forms-field-value--long\">{{ FormatValue() }}</span>\n }\n @else {\n <span class=\"mj-forms-field-value\">{{ FormatValue() }}</span>\n }\n }\n }\n }\n </div>\n </div>\n }\n\n <!-- EDIT MODE -->\n @if (EditMode && !IsFieldReadOnly) {\n <div class=\"mj-forms-field mj-forms-field--editing\" [class.mj-forms-field--dirty]=\"IsDirty\" [class.mj-forms-field--required-empty]=\"IsRequiredEmpty\" [class.mj-forms-field--has-error]=\"ShowErrors\" [class.mj-forms-field--has-warning]=\"ShowWarnings\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- Foreign Key fields get custom search autocomplete -->\n @if (HasRelatedEntity) {\n <div class=\"mj-fk-search\" [class.mj-fk-search--matched]=\"FKIsMatched\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FKSearchText\"\n (input)=\"OnFKInput($event)\"\n (focus)=\"OnFKFocus($event)\"\n (blur)=\"OnFKBlur()\"\n placeholder=\"Search...\">\n @if (FKSearchText) {\n <button class=\"mj-fk-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n } @else {\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n }\n @if (ShowFKDropdown && FKSuggestions.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (suggestion of FKSuggestions; track suggestion.PrimaryKeyValue) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnFKSelectItem(suggestion, $event)\">\n {{ suggestion.DisplayName }}\n </div>\n }\n </div>\n }\n </div>\n }\n @else {\n @switch (Type) {\n @case ('textbox') {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\">\n }\n @case ('textarea') {\n <textarea\n class=\"mj-forms-field-input mj-forms-field-input--textarea\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\"></textarea>\n }\n @case ('number') {\n <input type=\"number\"\n class=\"mj-forms-field-input mj-forms-field-input--number\"\n [value]=\"Value\"\n (change)=\"OnNumberChange($event)\">\n }\n @case ('datepicker') {\n <input type=\"date\"\n class=\"mj-forms-field-input mj-forms-field-input--date\"\n [value]=\"DateInputValue\"\n (change)=\"OnDateChange($event)\">\n }\n @case ('checkbox') {\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\"\n [checked]=\"!!Value\"\n (change)=\"OnCheckboxChange($event)\">\n </div>\n }\n @case ('select') {\n <div class=\"mj-custom-select-trigger\"\n tabindex=\"0\"\n (click)=\"OnSelectTriggerClick($event)\"\n (blur)=\"OnSelectTriggerBlur()\">\n <span class=\"mj-custom-select-value\" [class.mj-custom-select-value--placeholder]=\"!FormatValue()\">\n {{ FormatValue() || '-- Select --' }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-custom-select-chevron\" [class.mj-custom-select-chevron--open]=\"ShowSelectDropdown\"></i>\n </div>\n @if (ShowSelectDropdown && PossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of PossibleValues; track option) {\n <div class=\"mj-fk-option\" [class.mj-fk-option--selected]=\"FormatValue() === option\" (mousedown)=\"OnSelectOptionClick(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n }\n @case ('autocomplete') {\n <div class=\"mj-fk-search\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnValueListInput($event)\"\n (focus)=\"OnValueListFocus($event)\"\n (blur)=\"OnValueListBlur()\"\n placeholder=\"Type to search...\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n @if (ShowValueListDropdown && FilteredPossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of FilteredPossibleValues; track option) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnValueListSelect(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n </div>\n }\n @default {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (change)=\"OnInputChange($event)\">\n }\n }\n }\n </div>\n <!-- Inline validation messages -->\n @if (DisplayErrors.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--error\">\n @for (error of DisplayErrors; track error.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n <span>{{ error.Message }}</span>\n </div>\n }\n </div>\n }\n @if (DisplayWarnings.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--warning\">\n @for (warning of DisplayWarnings; track warning.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ warning.Message }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: ["/* ============================================\n FORM FIELD - Shared styles for read and edit\n ============================================ */\n:host {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n/* Subtle row hover in edit mode */\n.mj-forms-field--editing:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n/* ============================================\n LABEL\n ============================================ */\n.mj-forms-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n/* ============================================\n FIELD CONTROL WRAPPER (value + dirty dot)\n ============================================ */\n.mj-forms-field-control {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control > * {\n flex: 1;\n min-width: 0;\n}\n\n/* ============================================\n DIRTY INDICATOR (solid amber dot after label)\n ============================================ */\n.mj-forms-field--dirty .mj-forms-field-label::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n/* ============================================\n REQUIRED FIELD - red underline when empty\n ============================================ */\n.mj-forms-field--required-empty .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n/* ============================================\n READ-ONLY VALUE\n ============================================ */\n.mj-forms-field-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n/* Read-only fields in edit mode */\n.mj-forms-field--readonly {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly .mj-forms-field-value {\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n LINKS (FK, email, URL)\n ============================================ */\n.mj-forms-field-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link:hover .mj-forms-field-link-icon {\n opacity: 1;\n}\n\n/* FK fields showing entity name instead of raw ID */\n.mj-forms-field-link--fk {\n font-size: 14px;\n font-weight: 400;\n}\n\n/* ============================================\n EDIT MODE INPUTS - Clean underline style\n ============================================ */\n.mj-forms-field-input {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* Textarea variant */\n.mj-forms-field-input--textarea {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n/* Number input - narrower */\n.mj-forms-field-input--number {\n max-width: 200px;\n}\n\n/* Date input - narrower */\n.mj-forms-field-input--date {\n max-width: 220px;\n}\n\n/* ============================================\n CHECKBOX (custom styled)\n ============================================ */\n.mj-forms-field-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* ============================================\n CUSTOM SELECT DROPDOWN (replaces native <select>)\n ============================================ */\n.mj-custom-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open {\n transform: rotate(180deg);\n}\n\n/* ============================================\n FK SEARCH (custom autocomplete)\n ============================================ */\n.mj-fk-search {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search .mj-forms-field-input {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n/* Matched state: solid accent underline */\n.mj-fk-search--matched .mj-forms-field-input {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n/* ============================================\n FLOATING DROPDOWN PANEL (position: fixed via ngStyle)\n ============================================ */\n.mj-fk-dropdown {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above {\n animation: mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n@keyframes mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ============================================\n SEARCH HIGHLIGHTING\n ============================================ */\n.mj-forms-field-label :global(.mj-forms-search-highlight) {\n background-color: var(--mj-color-warning-200, #fef08a);\n color: var(--mj-color-warning-800, #854d0e);\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px var(--mj-color-warning-200, #fef08a);\n}\n\n/* ============================================\n VALIDATION ERROR STATE\n ============================================ */\n.mj-forms-field--has-error .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION WARNING STATE\n ============================================ */\n.mj-forms-field--has-warning .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION MESSAGE AREA\n ============================================ */\n.mj-forms-field-validation {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item i {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n/* Error message colors */\n.mj-forms-field-validation--error .mj-forms-field-validation-item {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error .mj-forms-field-validation-item i {\n color: var(--mj-status-error);\n}\n\n/* Warning message colors */\n.mj-forms-field-validation--warning .mj-forms-field-validation-item {\n color: var(--mj-color-warning-700);\n}\n\n.mj-forms-field-validation--warning .mj-forms-field-validation-item i {\n color: var(--mj-status-warning);\n}\n\n@keyframes mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 640px) {\n .mj-forms-field {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label {\n font-size: 12px;\n }\n\n .mj-forms-field-validation {\n grid-column: 1;\n }\n}\n"] }]
|
|
2599
|
+
args: [{ standalone: false, selector: 'mj-form-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Record && (Record.IsSaved || !IsFieldReadOnly)) {\n <!-- READ-ONLY MODE -->\n @if ((!EditMode || IsFieldReadOnly) && !ShouldHideField) {\n <div class=\"mj-forms-field\" [class.mj-forms-field--readonly]=\"EditMode && IsFieldReadOnly\" [class.mj-forms-field--dirty]=\"IsDirty\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- FK fields with a mapped name field: show the name as a hyperlink -->\n @if (IsFKWithNameField) {\n <span class=\"mj-forms-field-value\">\n @if (RecordLinksEnabled) {\n <a class=\"mj-forms-field-link mj-forms-field-link--fk\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FKDisplayName }}\n </a>\n } @else {\n {{ FKDisplayName }}\n }\n </span>\n }\n @else {\n @switch (LinkType) {\n @case ('Email') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnEmailLinkClick($event)\" title=\"Send email\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-envelope mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('URL') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnUrlLinkClick($event)\" title=\"Open link\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('Record') {\n <span class=\"mj-forms-field-value\">\n @if (RecordLinksEnabled) {\n <a class=\"mj-forms-field-link\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n } @else {\n {{ FormatValue() }}\n }\n </span>\n }\n @default {\n @if (Type === 'checkbox') {\n <span class=\"mj-forms-field-value\">\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\" [checked]=\"!!Value\" disabled>\n </div>\n </span>\n }\n @else if (RichTextMode === 'markdown') {\n <div class=\"mj-forms-field-value mj-forms-field-value--rich\">\n <mj-markdown [data]=\"FormatValue()\"></mj-markdown>\n </div>\n }\n @else if (RichTextMode === 'html') {\n <!-- XSS: the mjSafeRichHtml pipe sanitizes with DOMPurify (HTML + SVG profiles)\n and then bypasses Angular's redundant re-sanitize. DOMPurify strips <script>,\n on* handlers, javascript:/data: URLs and <foreignObject> while KEEPING safe\n inline SVG + styles \u2014 richer than Angular's built-in sanitizer, still safe for\n untrusted content. -->\n <div class=\"mj-forms-field-value mj-forms-field-value--rich\" [innerHTML]=\"FormatValue() | mjSafeRichHtml\"></div>\n }\n @else if (RichTextMode === 'code') {\n <div class=\"mj-forms-field-value mj-forms-field-value--code\">\n <mj-code-editor [value]=\"FormatValue()\" [language]=\"CodeEditorLanguage\" [readonly]=\"true\"></mj-code-editor>\n </div>\n }\n @else if (IsLongText) {\n <span class=\"mj-forms-field-value mj-forms-field-value--long\">{{ FormatValue() }}</span>\n }\n @else {\n <span class=\"mj-forms-field-value\">{{ FormatValue() }}</span>\n }\n }\n }\n }\n </div>\n </div>\n }\n\n <!-- EDIT MODE -->\n @if (EditMode && !IsFieldReadOnly) {\n <div class=\"mj-forms-field mj-forms-field--editing\" [class.mj-forms-field--dirty]=\"IsDirty\" [class.mj-forms-field--required-empty]=\"IsRequiredEmpty\" [class.mj-forms-field--has-error]=\"ShowErrors\" [class.mj-forms-field--has-warning]=\"ShowWarnings\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- Foreign Key fields get custom search autocomplete -->\n @if (HasRelatedEntity) {\n <div class=\"mj-fk-search\"\n [class.mj-fk-search--matched]=\"FKHasLinkedValue\"\n [class.mj-fk-search--scoped]=\"FKFocused && FKSearchableFields.length > 1\">\n @if (FKHasLinkedValue && !(FKFocused && FKSearchableFields.length > 1)) {\n <i class=\"fa-solid fa-link mj-fk-link-icon\" title=\"Linked record\"></i>\n }\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [class.mj-forms-field-input--linked]=\"FKHasLinkedValue\"\n [value]=\"FKSearchText\"\n (input)=\"OnFKInput($event)\"\n (focus)=\"OnFKFocus($event)\"\n (blur)=\"OnFKBlur()\"\n (keydown)=\"OnFKKeydown($event)\"\n placeholder=\"Search...\">\n\n <!-- Scope pill: only while focused, only when there's more than one searchable field.\n The menu itself lives INSIDE the results dropdown (below) so it overlays the\n list and rides the same above/below flip. -->\n @if (FKFocused && FKSearchableFields.length > 1) {\n <button class=\"mj-fk-scope-pill\"\n [class.mj-fk-scope-pill--open]=\"FKShowScopeMenu\"\n (mousedown)=\"OnFKScopeToggle($event)\"\n [title]=\"'Searching ' + FKSearchFieldLabel + ' \u2014 click to change'\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-scope-pill-icon\"></i>\n <span class=\"mj-fk-scope-pill-label\">{{ FKSearchFieldLabel }}</span>\n <i class=\"fa-solid mj-fk-scope-pill-caret\" [class.fa-chevron-up]=\"FKShowScopeMenu\" [class.fa-chevron-down]=\"!FKShowScopeMenu\"></i>\n </button>\n }\n\n @if (FKSearchText) {\n <button class=\"mj-fk-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n } @else {\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n }\n @if (ShowFKDropdown) {\n <div class=\"mj-fk-dropdown mj-fk-dropdown--multi\"\n [ngStyle]=\"DropdownPositionStyle\"\n [class.mj-fk-dropdown--above]=\"OpenAbove\"\n [class.mj-fk-dropdown--scope-open]=\"FKShowScopeMenu\">\n\n <!-- Scope (search-field) picker + column toggles \u2014 overlays the list, anchored to the pill edge.\n Click a row to SEARCH that field; click the eye to SHOW/HIDE it as a column. -->\n @if (FKShowScopeMenu) {\n <div class=\"mj-fk-scope-menu\" [class.mj-fk-scope-menu--bottom]=\"OpenAbove\">\n <div class=\"mj-fk-scope-grp\">Columns shown</div>\n @for (f of FKSearchableFields; track f.FieldName) {\n @if (f.Group === 'shown') {\n <ng-container *ngTemplateOutlet=\"scopeRow; context: { $implicit: f }\"></ng-container>\n }\n }\n @if (FKHasOtherSearchableFields) {\n <div class=\"mj-fk-scope-divider\"></div>\n <div class=\"mj-fk-scope-grp\">Other fields</div>\n @for (f of FKSearchableFields; track f.FieldName) {\n @if (f.Group === 'other') {\n <ng-container *ngTemplateOutlet=\"scopeRow; context: { $implicit: f }\"></ng-container>\n }\n }\n }\n </div>\n }\n\n <!-- Shared scope-menu row, fixed-slot layout for clean alignment:\n [reorder \u25B2\u25BC \u2014 hover-reveal] [icon] [label] [eye].\n Click the row = search this field; the active search row is shown bold+accent. -->\n <ng-template #scopeRow let-f>\n <div class=\"mj-fk-scope-mi\"\n [class.mj-fk-scope-mi--on]=\"IsFKScopeActive(f)\"\n (mousedown)=\"OnFKScopeSelect($event, f)\">\n <span class=\"mj-fk-col-reorder\">\n @if (f.Group === 'shown') {\n <button type=\"button\" class=\"mj-fk-col-move mj-fk-col-move--up\" [disabled]=\"!CanMoveFKColumnUp(f.FieldName)\"\n (mousedown)=\"MoveFKColumn($event, f.FieldName, -1)\" title=\"Move column up\">\n <i class=\"fa-solid fa-chevron-up\"></i>\n </button>\n <button type=\"button\" class=\"mj-fk-col-move mj-fk-col-move--down\" [disabled]=\"!CanMoveFKColumnDown(f.FieldName)\"\n (mousedown)=\"MoveFKColumn($event, f.FieldName, 1)\" title=\"Move column down\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n </button>\n }\n </span>\n <i [class]=\"f.Icon + ' mj-fk-scope-mi-icon'\"></i>\n <span class=\"mj-fk-scope-mi-label\">{{ f.Label }}</span>\n <span class=\"mj-fk-col-eye-slot\">\n @if (CanToggleFKColumn(f)) {\n <button type=\"button\" class=\"mj-fk-col-toggle\"\n [class.mj-fk-col-toggle--on]=\"IsFKColumnVisible(f)\"\n (mousedown)=\"OnFKColumnToggle($event, f)\"\n [title]=\"IsFKColumnVisible(f) ? 'Hide this column' : 'Show as a column'\">\n <i class=\"fa-solid\" [class.fa-eye]=\"IsFKColumnVisible(f)\" [class.fa-eye-slash]=\"!IsFKColumnVisible(f)\"></i>\n </button>\n }\n </span>\n </div>\n </ng-template>\n\n <!-- Pinned \"currently selected\" \u2014 sticky at the top while browsing, so you can\n keep it or pick another without clearing first. -->\n @if (FKSelectedSuggestion && !FKLoading) {\n <div class=\"mj-fk-current\">\n <div class=\"mj-fk-current-head\">\n <i class=\"fa-solid fa-circle-check\"></i>\n <span>Currently selected</span>\n </div>\n <div class=\"mj-fk-current-row\" (mousedown)=\"OnFKSelectItem(FKSelectedSuggestion, $event)\" title=\"Keep this selection\">\n @if (FKSelectedSuggestion.Icon) { <i class=\"mj-fk-current-icon\" [class]=\"FKSelectedSuggestion.Icon\"></i> }\n <span class=\"mj-fk-current-name\" [innerHTML]=\"FKSelectedSuggestion.HighlightedName\"></span>\n @if (FKSelectedSuggestion.ExtraColumns.length && FKSelectedSuggestion.ExtraColumns[0].Value) {\n <span class=\"mj-fk-current-detail\">{{ FKSelectedSuggestion.ExtraColumns[0].Value }}</span>\n }\n <button type=\"button\" class=\"mj-fk-current-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear selection\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n </div>\n }\n\n @if (FKLoading) {\n <div class=\"mj-fk-status\">\n <i class=\"fa-solid fa-circle-notch fa-spin\"></i>\n <span>Searching\u2026</span>\n </div>\n }\n @if (!FKLoading && FKNoMatches) {\n <div class=\"mj-fk-status mj-fk-status--empty\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>No matches</span>\n </div>\n }\n @if (!FKLoading && FKSuggestions.length > 0) {\n <div class=\"mj-fk-options\">\n <div class=\"mj-fk-grid\" [style.grid-template-columns]=\"FKGridTemplateColumns\">\n <!-- Header row: click to sort, drag the right edge to resize.\n (Column reorder lives in the field-selector menu, not here.) -->\n <div class=\"mj-fk-grid-row mj-fk-grid-row--header\">\n @if (FKHasIconColumn) {\n <div class=\"mj-fk-hcell mj-fk-hcell--icon\"></div>\n }\n @for (col of FKColumnFields; track col; let i = $index) {\n <div class=\"mj-fk-hcell\"\n (mousedown)=\"OnFKHeaderSort($event, col)\"\n [title]=\"'Click to sort by ' + FKColumnHeaders[i]\">\n <span class=\"mj-fk-hcell-label\">{{ FKColumnHeaders[i] }}</span>\n <i [class]=\"FKSortIcon(col)\"></i>\n <span class=\"mj-fk-resizer\" (mousedown)=\"OnFKColResizeStart($event, col)\" title=\"Drag to resize\"></span>\n </div>\n }\n </div>\n <!-- Data rows -->\n @for (suggestion of FKSuggestions; track suggestion.PrimaryKeyValue; let i = $index) {\n <div class=\"mj-fk-grid-row\"\n [class.mj-fk-grid-row--active]=\"i === FKActiveIndex\"\n [class.mj-fk-grid-row--selected]=\"IsFKRowSelected(suggestion)\"\n (mousedown)=\"OnFKSelectItem(suggestion, $event)\"\n (mouseenter)=\"FKActiveIndex = i\">\n @if (FKHasIconColumn) {\n <div class=\"mj-fk-cell mj-fk-cell--icon\">\n @if (suggestion.Icon) { <i [class]=\"suggestion.Icon\"></i> }\n </div>\n }\n @for (col of FKColumnFields; track col; let last = $last) {\n @if (col === FKNameField) {\n <div class=\"mj-fk-cell mj-fk-cell--name\" [class.mj-fk-cell--fill]=\"FKColumnFillsTrack(col, last)\">\n @if (IsFKRowSelected(suggestion)) {\n <i class=\"fa-solid fa-check mj-fk-selected-check\" title=\"Currently selected\"></i>\n }\n <span [innerHTML]=\"suggestion.HighlightedName\"></span>\n </div>\n } @else {\n <div class=\"mj-fk-cell\" [class.mj-fk-cell--fill]=\"FKColumnFillsTrack(col, last)\" [title]=\"FKCellFor(suggestion, col)?.Value || ''\">\n <span [innerHTML]=\"FKCellFor(suggestion, col)?.HighlightedValue || ''\"></span>\n </div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Sticky \"create new\" footer \u2014 always visible at the bottom (no scrolling),\n prefilled with the typed text. Gated on create permission. -->\n @if (CanCreateFK) {\n <button type=\"button\" class=\"mj-fk-create-footer\" (mousedown)=\"OnFKCreateNew($event)\" [title]=\"FKCreateLabel\">\n <i class=\"fa-solid fa-plus mj-fk-create-icon\"></i>\n <span class=\"mj-fk-create-label\">{{ FKCreateLabel }}</span>\n </button>\n }\n </div>\n }\n </div>\n }\n @else if (EditRichTextMode !== 'plain') {\n <!-- Markdown / HTML / Code long-text: edit raw with a syntax-highlighted code editor -->\n <mj-code-editor\n class=\"mj-forms-field-input--code\"\n [value]=\"FormatValue()\"\n [language]=\"CodeEditorLanguage\"\n (change)=\"OnCodeEditorChange($event)\"></mj-code-editor>\n }\n @else {\n @switch (Type) {\n @case ('textbox') {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\">\n }\n @case ('textarea') {\n <textarea\n class=\"mj-forms-field-input mj-forms-field-input--textarea\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\"></textarea>\n }\n @case ('number') {\n <input type=\"number\"\n class=\"mj-forms-field-input mj-forms-field-input--number\"\n [value]=\"Value\"\n (change)=\"OnNumberChange($event)\">\n }\n @case ('datepicker') {\n <input type=\"date\"\n class=\"mj-forms-field-input mj-forms-field-input--date\"\n [value]=\"DateInputValue\"\n (change)=\"OnDateChange($event)\">\n }\n @case ('checkbox') {\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\"\n [checked]=\"!!Value\"\n (change)=\"OnCheckboxChange($event)\">\n </div>\n }\n @case ('select') {\n <div class=\"mj-custom-select-trigger\"\n tabindex=\"0\"\n (click)=\"OnSelectTriggerClick($event)\"\n (blur)=\"OnSelectTriggerBlur()\">\n <span class=\"mj-custom-select-value\" [class.mj-custom-select-value--placeholder]=\"!FormatValue()\">\n {{ FormatValue() || '-- Select --' }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-custom-select-chevron\" [class.mj-custom-select-chevron--open]=\"ShowSelectDropdown\"></i>\n </div>\n @if (ShowSelectDropdown && PossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of PossibleValues; track option) {\n <div class=\"mj-fk-option\" [class.mj-fk-option--selected]=\"FormatValue() === option\" (mousedown)=\"OnSelectOptionClick(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n }\n @case ('autocomplete') {\n <div class=\"mj-fk-search\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnValueListInput($event)\"\n (focus)=\"OnValueListFocus($event)\"\n (blur)=\"OnValueListBlur()\"\n placeholder=\"Type to search...\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n @if (ShowValueListDropdown && FilteredPossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of FilteredPossibleValues; track option) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnValueListSelect(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n </div>\n }\n @default {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (change)=\"OnInputChange($event)\">\n }\n }\n }\n </div>\n <!-- Inline validation messages -->\n @if (DisplayErrors.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--error\">\n @for (error of DisplayErrors; track error.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n <span>{{ error.Message }}</span>\n </div>\n }\n </div>\n }\n @if (DisplayWarnings.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--warning\">\n @for (warning of DisplayWarnings; track warning.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ warning.Message }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: ["/* ============================================\n FORM FIELD - Shared styles for read and edit\n ============================================ */\n:host {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n/* Subtle row hover in edit mode */\n.mj-forms-field--editing:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n/* ============================================\n LABEL\n ============================================ */\n.mj-forms-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n/* ============================================\n FIELD CONTROL WRAPPER (value + dirty dot)\n ============================================ */\n.mj-forms-field-control {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control > * {\n flex: 1;\n min-width: 0;\n}\n\n/* ============================================\n DIRTY INDICATOR (solid amber dot after label)\n ============================================ */\n.mj-forms-field--dirty .mj-forms-field-label::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n/* ============================================\n REQUIRED FIELD - red underline when empty\n ============================================ */\n.mj-forms-field--required-empty .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n/* ============================================\n READ-ONLY VALUE\n ============================================ */\n.mj-forms-field-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n/* Rich (markdown / html) read-only rendering \u2014 let content flow as a block, not a flex row */\n.mj-forms-field-value--rich {\n display: block;\n align-items: initial;\n max-height: 480px;\n overflow: auto;\n width: 100%;\n}\n\n/* Code read-only / edit rendering \u2014 the embedded code editor needs an explicit height */\n.mj-forms-field-value--code {\n display: block;\n align-items: initial;\n width: 100%;\n}\n\n.mj-forms-field-value--code mj-code-editor,\n.mj-forms-field-input--code {\n display: block;\n width: 100%;\n min-height: 160px;\n max-height: 480px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius, 4px);\n overflow: auto;\n}\n\n/* Read-only fields in edit mode */\n.mj-forms-field--readonly {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly .mj-forms-field-value {\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n LINKS (FK, email, URL)\n ============================================ */\n.mj-forms-field-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link:hover .mj-forms-field-link-icon {\n opacity: 1;\n}\n\n/* FK fields showing entity name instead of raw ID */\n.mj-forms-field-link--fk {\n font-size: 14px;\n font-weight: 400;\n}\n\n/* ============================================\n EDIT MODE INPUTS - Clean underline style\n ============================================ */\n.mj-forms-field-input {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* Textarea variant */\n.mj-forms-field-input--textarea {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n/* Number input - narrower */\n.mj-forms-field-input--number {\n max-width: 200px;\n}\n\n/* Date input - narrower */\n.mj-forms-field-input--date {\n max-width: 220px;\n}\n\n/* ============================================\n CHECKBOX (custom styled)\n ============================================ */\n.mj-forms-field-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* ============================================\n CUSTOM SELECT DROPDOWN (replaces native <select>)\n ============================================ */\n.mj-custom-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open {\n transform: rotate(180deg);\n}\n\n/* ============================================\n FK SEARCH (custom autocomplete)\n ============================================ */\n.mj-fk-search {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search .mj-forms-field-input {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n/* Linked state: solid accent underline + a leading chain icon, so it's obvious the\n field holds a resolved record reference rather than free-typed text. */\n.mj-fk-search--matched .mj-forms-field-input {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n/* Linked indicator sits on the RIGHT (just left of the clear button) so it never\n interrupts left-to-right reading of the value or overlaps the text. */\n.mj-fk-link-icon {\n position: absolute;\n right: 26px;\n color: var(--mj-brand-primary);\n font-size: 10px;\n pointer-events: none;\n z-index: 1;\n}\n\n/* Make room on the right for the link icon + the clear button. */\n.mj-forms-field-input--linked {\n padding-right: 46px;\n}\n\n/* ============================================\n SCOPE PILL + FIELD-PICKER MENU (search-field scope)\n ============================================ */\n/* When the pill is showing, reserve room on the right of the input for it. */\n.mj-fk-search--scoped .mj-forms-field-input {\n padding-right: 150px;\n}\n\n.mj-fk-scope-pill {\n position: absolute;\n right: 30px;\n /* Vertically centered in the input so it clears the focus underline below. */\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 120px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n font-size: 10.5px;\n font-weight: 600;\n font-family: inherit;\n /* Kept short so it clears the input's focus underline without making the row taller. */\n padding: 1px 7px;\n border-radius: 999px;\n cursor: pointer;\n white-space: nowrap;\n line-height: 1.35;\n transition: background var(--mj-transition-base), border-color var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-pill:hover,\n.mj-fk-scope-pill--open {\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-primary);\n}\n\n.mj-fk-scope-pill-icon {\n font-size: 9px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-pill-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-scope-pill-caret {\n font-size: 8px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n/* The menu is rendered INSIDE the results dropdown panel so it overlays the list\n (correct z-order, no extra real estate) and rides the dropdown's above/below\n flip. Anchored to the dropdown's top-right \u2014 right under the pill. */\n.mj-fk-scope-menu {\n position: absolute;\n top: 4px;\n right: 8px;\n z-index: 5;\n min-width: 180px;\n max-width: calc(100vw - 24px);\n max-height: 260px;\n overflow-y: auto;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n border-radius: var(--mj-radius-sm);\n box-shadow: var(--mj-shadow-lg);\n padding: 5px;\n animation: mj-dropdown-in 120ms ease;\n}\n\n/* When the dropdown opens ABOVE the input, anchor the menu to its bottom edge so it\n stays next to the pill (which is at the input/dropdown boundary). */\n.mj-fk-scope-menu--bottom {\n top: auto;\n bottom: 4px;\n}\n\n.mj-fk-scope-grp {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n padding: 7px 10px 4px;\n font-weight: 700;\n}\n\n.mj-fk-scope-mi {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 13px;\n border-radius: 5px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.mj-fk-scope-mi:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-scope-mi--on {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* Fixed-width LEFT slot: a compact stacked up/down reorder control that reveals on row\n hover. Reserved (same width) on every row so the field icons + labels stay aligned. */\n.mj-fk-col-reorder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 22px;\n flex-shrink: 0;\n}\n\n.mj-fk-col-move {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 10px;\n padding: 0;\n background: transparent;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 8px;\n opacity: 0; /* hover-reveal for a clean resting state */\n transition: opacity var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-scope-mi:hover .mj-fk-col-move:not(:disabled) {\n opacity: 0.8;\n}\n\n.mj-fk-col-move:hover:not(:disabled) {\n opacity: 1;\n color: var(--mj-brand-primary);\n}\n\n/* End-of-range arrows stay hidden (slot still reserved) rather than greyed. */\n.mj-fk-col-move:disabled {\n opacity: 0 !important;\n cursor: default;\n}\n\n.mj-fk-scope-mi-icon {\n width: 14px;\n font-size: 11px;\n opacity: 0.75;\n flex-shrink: 0;\n}\n\n.mj-fk-scope-mi-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Fixed-width RIGHT slot so the eye (or its empty space, for the name row) aligns. */\n.mj-fk-col-eye-slot {\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Eye toggle: show/hide a field as a grid column (independent of search scope). */\n.mj-fk-col-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-col-toggle:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n}\n\n.mj-fk-col-toggle--on {\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-scope-divider {\n height: 1px;\n background: var(--mj-border-subtle);\n margin: 4px 6px;\n}\n\n/* Narrow / mobile screens: shrink the pill + its reserved space, give menu rows a\n larger touch target, and keep the menu within the viewport. */\n@media (max-width: 560px) {\n .mj-fk-search--scoped .mj-forms-field-input {\n padding-right: 116px;\n }\n .mj-fk-scope-pill {\n max-width: 88px;\n }\n .mj-fk-scope-menu {\n min-width: 160px;\n }\n .mj-fk-scope-mi {\n padding: 10px 10px;\n }\n}\n\n/* ============================================\n FLOATING DROPDOWN PANEL (position: fixed via ngStyle)\n ============================================ */\n.mj-fk-dropdown {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above {\n animation: mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n/* ============================================\n MULTI-COLUMN FK DROPDOWN \u2014 aligned mini-grid (icon + name + extra cols)\n with sortable headers and horizontal scroll.\n ============================================ */\n.mj-fk-dropdown--multi {\n padding: 4px;\n /* The inner .mj-fk-options is the single scroll container (both axes) so the\n sticky header anchors correctly; the dropdown just clips to its rounded border. */\n overflow: hidden;\n max-height: none;\n}\n\n/* Single scroll region (both axes) for the grid: vertical for long lists, horizontal\n when many DefaultInView columns make rows wider than the dropdown. Being the sole\n scroller lets the sticky column headers anchor to its top edge. */\n.mj-fk-dropdown--multi .mj-fk-options {\n overflow: auto;\n max-height: 260px;\n}\n\n/* While the scope menu is open it must escape the panel's clip (the inner\n .mj-fk-options keeps its own scroll, so the grid still behaves). */\n.mj-fk-dropdown--scope-open {\n overflow: visible;\n}\n\n/* One CSS grid spans the header + all data rows so every column lines up.\n grid-template-columns is supplied inline from FKGridTemplateColumns.\n `width: 100%` (with `min-width: max-content`) lets the last column's `1fr` track\n absorb leftover width, while still overflowing \u2192 horizontal scroll when the columns\n are collectively wider than the dropdown. */\n.mj-fk-grid {\n display: grid;\n width: 100%;\n min-width: max-content;\n align-items: stretch;\n}\n\n/* Rows are layout-transparent so their cells become direct grid items (this is\n what makes columns align across rows). The row element still exists for click\n handling and for the active-state selector below. */\n.mj-fk-grid-row {\n display: contents;\n}\n\n/* Header cells: sticky to the top of the vertical scroll, clickable to sort. */\n.mj-fk-hcell {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n}\n\n.mj-fk-hcell:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-hcell--icon {\n cursor: default;\n padding: 7px 8px;\n}\n\n.mj-fk-hcell--icon:hover {\n background: var(--mj-bg-surface-elevated);\n}\n\n.mj-fk-hcell-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-sort-icon {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n/* Idle (unsorted) columns show a faded sort glyph to signal sortability. */\n.mj-fk-sort-icon--idle {\n opacity: 0.35;\n}\n\n/* Data cells */\n.mj-fk-cell {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 320px;\n cursor: pointer;\n}\n\n/* The fill column (last, or a user-resized one) drops the default content cap so its\n cells stretch to the full track width that the header already occupies. */\n.mj-fk-cell--fill {\n max-width: none;\n}\n\n/* Wrapping span keeps the highlighted text+<mark> as one inline run (so flex\n doesn't strip the space next to the mark) while still truncating with ellipsis. */\n.mj-fk-cell > span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.mj-fk-cell--icon {\n justify-content: center;\n padding: 8px;\n max-width: none;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.mj-fk-cell--name {\n font-weight: 500;\n font-size: 14px;\n color: var(--mj-text-primary);\n gap: 6px;\n}\n\n.mj-fk-selected-check {\n color: var(--mj-brand-primary);\n font-size: 11px;\n flex-shrink: 0;\n}\n\n/* Active (keyboard / hover) row \u2014 painted on the cells, since the row box is\n removed by display:contents. The child combinator still matches. */\n.mj-fk-grid-row--active > .mj-fk-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n/* Currently-linked row \u2014 a subtle persistent tint so the user sees which record\n is selected when they reopen the list (stacks under the brighter active tint). */\n.mj-fk-grid-row--selected > .mj-fk-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n}\n\n.mj-fk-grid-row--selected > .mj-fk-cell--name {\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n/* Matched-substring highlight inside the name column */\n/* ::ng-deep (not :global, which Angular's emulated encapsulation ignores) so the\n style reaches the <mark> injected via [innerHTML]. Color comes from the shared\n theme token so light/dark/white-label all control it centrally. */\n.mj-fk-cell--name ::ng-deep .mj-forms-search-highlight,\n.mj-fk-cell ::ng-deep .mj-forms-search-highlight {\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n/* Column resize handle \u2014 thin grab strip on the right edge of each header cell. */\n.mj-fk-resizer {\n position: absolute;\n top: 0;\n right: 0;\n width: 7px;\n height: 100%;\n cursor: col-resize;\n user-select: none;\n}\n\n.mj-fk-resizer::after {\n content: '';\n position: absolute;\n top: 20%;\n right: 2px;\n width: 2px;\n height: 60%;\n background: transparent;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-hcell:hover .mj-fk-resizer::after,\n.mj-fk-resizer:hover::after {\n background: var(--mj-border-strong);\n}\n\n/* Loading / empty status rows */\n.mj-fk-status {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-status i {\n font-size: 12px;\n}\n\n.mj-fk-status--empty {\n font-style: italic;\n}\n\n/* Sticky \"create new\" footer \u2014 sits below the (scrolling) options as a direct child of\n the dropdown panel, so it's always visible regardless of list length. */\n.mj-fk-create-footer {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border: none;\n border-top: 1px solid var(--mj-border-default);\n color: var(--mj-brand-primary);\n font-size: 13px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n.mj-fk-create-footer:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.mj-fk-create-icon {\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.mj-fk-create-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ============================================\n PINNED \"CURRENTLY SELECTED\" SECTION\n ============================================ */\n.mj-fk-current {\n border-bottom: 1px solid var(--mj-border-default);\n background: color-mix(in srgb, var(--mj-brand-primary) 7%, var(--mj-bg-surface-card));\n animation: mj-fk-current-in 220ms cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n@keyframes mj-fk-current-in {\n from { opacity: 0; transform: translateY(-6px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.mj-fk-current-head {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px 3px;\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-current-head i {\n font-size: 10px;\n}\n\n.mj-fk-current-row {\n position: relative;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 6px 12px 10px;\n cursor: pointer;\n transition: background var(--mj-transition-base);\n}\n\n/* Accent bar on the left for a bit of sizzle. */\n.mj-fk-current-row::before {\n content: '';\n position: absolute;\n left: 0;\n top: 4px;\n bottom: 8px;\n width: 3px;\n border-radius: 0 2px 2px 0;\n background: var(--mj-brand-primary);\n}\n\n.mj-fk-current-row:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.mj-fk-current-icon {\n flex-shrink: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.mj-fk-current-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-detail {\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-fk-current-clear {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 12px;\n transition: background var(--mj-transition-base), color var(--mj-transition-base);\n}\n\n.mj-fk-current-clear:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-status-error);\n}\n\n@keyframes mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ============================================\n SEARCH HIGHLIGHTING\n ============================================ */\n.mj-forms-field-label ::ng-deep .mj-forms-search-highlight {\n /* Shared search-highlight theme token. ::ng-deep (not :global) so it reaches\n innerHTML content. */\n background-color: var(--mj-search-highlight-bg);\n color: var(--mj-search-highlight-text);\n border-radius: 2px;\n padding: 0 1px;\n font-weight: 600;\n}\n\n/* ============================================\n VALIDATION ERROR STATE\n ============================================ */\n.mj-forms-field--has-error .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION WARNING STATE\n ============================================ */\n.mj-forms-field--has-warning .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION MESSAGE AREA\n ============================================ */\n.mj-forms-field-validation {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item i {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n/* Error message colors */\n.mj-forms-field-validation--error .mj-forms-field-validation-item {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error .mj-forms-field-validation-item i {\n color: var(--mj-status-error);\n}\n\n/* Warning message colors */\n.mj-forms-field-validation--warning .mj-forms-field-validation-item {\n color: var(--mj-status-warning-text);\n}\n\n.mj-forms-field-validation--warning .mj-forms-field-validation-item i {\n color: var(--mj-status-warning);\n}\n\n@keyframes mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 640px) {\n .mj-forms-field {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label {\n font-size: 12px;\n }\n\n .mj-forms-field-validation {\n grid-column: 1;\n }\n}\n"] }]
|
|
1176
2600
|
}], null, { Record: [{
|
|
1177
2601
|
type: Input
|
|
1178
2602
|
}], EditMode: [{
|
|
@@ -1203,6 +2627,14 @@ export class MjFormFieldComponent extends BaseAngularComponent {
|
|
|
1203
2627
|
type: Output
|
|
1204
2628
|
}], Navigate: [{
|
|
1205
2629
|
type: Output
|
|
2630
|
+
}], FKDropdownMaxWidth: [{
|
|
2631
|
+
type: Input
|
|
2632
|
+
}], FKHighlightMatches: [{
|
|
2633
|
+
type: Input
|
|
2634
|
+
}], AllowFKCreate: [{
|
|
2635
|
+
type: Input
|
|
2636
|
+
}], FKCreatePresentation: [{
|
|
2637
|
+
type: Input
|
|
1206
2638
|
}] }); })();
|
|
1207
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjFormFieldComponent, { className: "MjFormFieldComponent", filePath: "src/lib/field/form-field.component.ts", lineNumber:
|
|
2639
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjFormFieldComponent, { className: "MjFormFieldComponent", filePath: "src/lib/field/form-field.component.ts", lineNumber: 136 }); })();
|
|
1208
2640
|
//# sourceMappingURL=form-field.component.js.map
|