@acorex-platform/module-assessment-management-client 0.0.20
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/fesm2022/acorex-platform-module-assessment-management-client-acorex-platform-module-assessment-management-client-jljmsqNu.mjs +10593 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-acorex-platform-module-assessment-management-client-jljmsqNu.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-case-status.provider-i48XDX-I.mjs +83 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-case-status.provider-i48XDX-I.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-session-answers-view.util-42ZcOY2C.mjs +124 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-session-answers-view.util-42ZcOY2C.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-session-status.provider-Bk9hHj5V.mjs +97 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-session-status.provider-Bk9hHj5V.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-voice.commands-CduVfWQ-.mjs +134 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-assessment-voice.commands-CduVfWQ-.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-contracts.mjs +1171 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-fill-assessment-session.command-VF80DWQf.mjs +270 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-fill-assessment-session.command-VF80DWQf.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-list-question-difficulty-options.query-h3xT-MNd.mjs +59 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-list-question-difficulty-options.query-h3xT-MNd.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-preview-question.command-C1ODQxDn.mjs +123 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-preview-question.command-C1ODQxDn.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-preview-questionnaire.command-DBm7ve4w.mjs +165 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-preview-questionnaire.command-DBm7ve4w.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-preview-session-pdf.command-BsiJU6ep.mjs +178 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-preview-session-pdf.command-BsiJU6ep.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-question-bank-interface-editor-widget-edit.component-Bbl-efrl.mjs +489 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-question-bank-interface-editor-widget-edit.component-Bbl-efrl.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-questionnaire-viewer-popup.component-Djcfg0dv.mjs +609 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-questionnaire-viewer-popup.component-Djcfg0dv.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-review-assessment-session.command-CZ96KQ-l.mjs +228 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-review-assessment-session.command-CZ96KQ-l.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-view-session-answers.command-CCzJoJ4p.mjs +280 -0
- package/fesm2022/acorex-platform-module-assessment-management-client-view-session-answers.command-CCzJoJ4p.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-assessment-management-client.mjs +2 -0
- package/fesm2022/acorex-platform-module-assessment-management-client.mjs.map +1 -0
- package/package.json +28 -0
- package/types/acorex-platform-module-assessment-management-client-contracts.d.ts +752 -0
- package/types/acorex-platform-module-assessment-management-client.d.ts +1279 -0
|
@@ -0,0 +1,1171 @@
|
|
|
1
|
+
const AXMAssessmentManagementFeatureKeys = {
|
|
2
|
+
QuestionnaireManagement: 'AssessmentManagement:Feature:Questionnaire.Management',
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
const AXPAssessmentManagementMenuKeys = {
|
|
6
|
+
Questionnaires: 'AssessmentManagement:Menu:Questionnaires',
|
|
7
|
+
Cases: 'AssessmentManagement:Menu:Cases',
|
|
8
|
+
QuestionBankItems: 'AssessmentManagement:Menu:QuestionBankItems',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Safety & Risk capabilities used by this module.
|
|
13
|
+
* Domain capability keys for this module. Root groups live in `AXPCommonPermissionGroupKeys` (common contracts).
|
|
14
|
+
*/
|
|
15
|
+
const AXPSafetyRiskPermissionKeys = {
|
|
16
|
+
Access: 'SafetyRisk:Permission:Access',
|
|
17
|
+
MaintainSafety: 'SafetyRisk:Permission:MaintainSafety',
|
|
18
|
+
MaintainRisk: 'SafetyRisk:Permission:MaintainRisk',
|
|
19
|
+
MaintainHealth: 'SafetyRisk:Permission:MaintainHealth',
|
|
20
|
+
MaintainAssessments: 'SafetyRisk:Permission:MaintainAssessments',
|
|
21
|
+
Setup: 'SafetyRisk:Permission:Setup',
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Prefer {@link AXPSafetyRiskPermissionKeys}.
|
|
25
|
+
* Legacy nested shape kept so existing imports compile during migration.
|
|
26
|
+
*/
|
|
27
|
+
const AXMAssessmentManagementPermissionKeys = {
|
|
28
|
+
AssessmentManagement: {
|
|
29
|
+
QuestionBank: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
30
|
+
Questionnaire: {
|
|
31
|
+
Management: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
32
|
+
Create: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
33
|
+
Edit: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
34
|
+
Delete: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
35
|
+
},
|
|
36
|
+
Case: {
|
|
37
|
+
Management: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
38
|
+
},
|
|
39
|
+
Session: {
|
|
40
|
+
Management: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
41
|
+
},
|
|
42
|
+
Automation: {
|
|
43
|
+
Management: AXPSafetyRiskPermissionKeys.MaintainAssessments,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** Component key for the questionnaire Outcomes page tab. Register via AXP_PAGE_COMPONENT_PROVIDER. */
|
|
49
|
+
const QUESTIONNAIRE_OUTCOMES_PAGE_COMPONENT_KEY = 'questionnaire-outcomes-page';
|
|
50
|
+
|
|
51
|
+
/** Component key for the questionnaire Questions page tab. Register via AXP_PAGE_COMPONENT_PROVIDER. */
|
|
52
|
+
const QUESTIONNAIRE_QUESTIONS_PAGE_COMPONENT_KEY = 'questionnaire-questions-page';
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
|
|
56
|
+
//#region ---- Imports ----
|
|
57
|
+
//#endregion
|
|
58
|
+
|
|
59
|
+
//#region ---- Questionnaire print settings ----
|
|
60
|
+
const DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS = {
|
|
61
|
+
paperSize: 'A4',
|
|
62
|
+
orientation: 'portrait',
|
|
63
|
+
watermark: '',
|
|
64
|
+
showQuestionNumbers: true,
|
|
65
|
+
showWelcomeScreen: false,
|
|
66
|
+
showSummaryAfterSubmit: false,
|
|
67
|
+
showOutcomeResults: false,
|
|
68
|
+
showUnansweredQuestions: true,
|
|
69
|
+
showComments: true,
|
|
70
|
+
showAttachments: true,
|
|
71
|
+
showHints: true,
|
|
72
|
+
showNotes: true,
|
|
73
|
+
};
|
|
74
|
+
const PRINT_PAPER_SIZE_VALUES = ['A4', 'Letter', 'Legal'];
|
|
75
|
+
const PRINT_ORIENTATION_VALUES = ['portrait', 'landscape'];
|
|
76
|
+
const PRINT_PAGE_SIZE_MM = {
|
|
77
|
+
A4: { width: 210, height: 297 },
|
|
78
|
+
Letter: { width: 215.9, height: 279.4 },
|
|
79
|
+
Legal: { width: 215.9, height: 355.6 },
|
|
80
|
+
};
|
|
81
|
+
/** Side margin used by the print document and Chromium PDF engine. */
|
|
82
|
+
const PRINT_PAGE_SIDE_MARGIN_MM = 14;
|
|
83
|
+
/**
|
|
84
|
+
* Playwright paints repeating letterhead in the top/bottom margin box.
|
|
85
|
+
* These must stay large enough for the company header/footer; measuring
|
|
86
|
+
* chrome height under-reported and overlapped the questionnaire title.
|
|
87
|
+
*/
|
|
88
|
+
const PRINT_PAGE_LETTERHEAD_TOP_MARGIN_MM = 36;
|
|
89
|
+
const PRINT_PAGE_LETTERHEAD_BOTTOM_MARGIN_MM = 28;
|
|
90
|
+
function resolvePrintLetterheadPdfMargin() {
|
|
91
|
+
return {
|
|
92
|
+
top: `${PRINT_PAGE_LETTERHEAD_TOP_MARGIN_MM}mm`,
|
|
93
|
+
right: `${PRINT_PAGE_SIDE_MARGIN_MM}mm`,
|
|
94
|
+
bottom: `${PRINT_PAGE_LETTERHEAD_BOTTOM_MARGIN_MM}mm`,
|
|
95
|
+
left: `${PRINT_PAGE_SIDE_MARGIN_MM}mm`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function definedPartial(value) {
|
|
99
|
+
if (!value) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
103
|
+
}
|
|
104
|
+
function coerceSelectId(value) {
|
|
105
|
+
if (value != null && typeof value === 'object' && 'id' in value) {
|
|
106
|
+
return value.id;
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
function normalizePrintPaperSize(value) {
|
|
111
|
+
const raw = coerceSelectId(value);
|
|
112
|
+
if (typeof raw === 'string' && PRINT_PAPER_SIZE_VALUES.includes(raw)) {
|
|
113
|
+
return raw;
|
|
114
|
+
}
|
|
115
|
+
return DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS.paperSize;
|
|
116
|
+
}
|
|
117
|
+
function normalizePrintOrientation(value) {
|
|
118
|
+
const raw = coerceSelectId(value);
|
|
119
|
+
if (typeof raw === 'string' && PRINT_ORIENTATION_VALUES.includes(raw)) {
|
|
120
|
+
return raw;
|
|
121
|
+
}
|
|
122
|
+
return DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS.orientation;
|
|
123
|
+
}
|
|
124
|
+
function normalizePrintWatermark(value) {
|
|
125
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Merges questionnaire defaults with an optional per-call override.
|
|
129
|
+
* Undefined override fields keep the stored / built-in default.
|
|
130
|
+
*/
|
|
131
|
+
function resolvePrintSettings(stored, override) {
|
|
132
|
+
const merged = {
|
|
133
|
+
...DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS,
|
|
134
|
+
...definedPartial(stored),
|
|
135
|
+
...definedPartial(override),
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
...merged,
|
|
139
|
+
paperSize: normalizePrintPaperSize(merged.paperSize),
|
|
140
|
+
orientation: normalizePrintOrientation(merged.orientation),
|
|
141
|
+
watermark: normalizePrintWatermark(merged.watermark),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Resolves print page breaks from the Display view mode.
|
|
146
|
+
* `side-menu` prints as page-per-group (no sidebar).
|
|
147
|
+
*/
|
|
148
|
+
function resolvePrintPaging(displayViewMode) {
|
|
149
|
+
if (displayViewMode === 'page-per-question') {
|
|
150
|
+
return 'page-per-question';
|
|
151
|
+
}
|
|
152
|
+
if (displayViewMode === 'page-per-group' || displayViewMode === 'side-menu') {
|
|
153
|
+
return 'page-per-group';
|
|
154
|
+
}
|
|
155
|
+
return 'single-page';
|
|
156
|
+
}
|
|
157
|
+
/** Content width after side margins, for the off-screen print host and wrapped HTML. */
|
|
158
|
+
function resolvePrintContentWidthMm(print) {
|
|
159
|
+
const size = PRINT_PAGE_SIZE_MM[normalizePrintPaperSize(print.paperSize)];
|
|
160
|
+
const pageWidth = normalizePrintOrientation(print.orientation) === 'landscape' ? size.height : size.width;
|
|
161
|
+
return Math.round((pageWidth - PRINT_PAGE_SIDE_MARGIN_MM * 2) * 10) / 10;
|
|
162
|
+
}
|
|
163
|
+
function resolvePrintPdfPageOptions(print) {
|
|
164
|
+
return {
|
|
165
|
+
format: normalizePrintPaperSize(print.paperSize),
|
|
166
|
+
landscape: normalizePrintOrientation(print.orientation) === 'landscape',
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
|
|
171
|
+
//#region ---- Root Configuration ----
|
|
172
|
+
const config = { i18n: 'assessment-management', module: 'AssessmentManagement' };
|
|
173
|
+
const RootConfig = {
|
|
174
|
+
config,
|
|
175
|
+
module: {
|
|
176
|
+
module: 'assessment-management',
|
|
177
|
+
route: 'assessment-management',
|
|
178
|
+
name: 'AssessmentManagement',
|
|
179
|
+
title: '@assessment-management:module.title',
|
|
180
|
+
icon: 'fa-light fa-clipboard-list-check',
|
|
181
|
+
},
|
|
182
|
+
entities: {
|
|
183
|
+
questionBankItem: {
|
|
184
|
+
name: 'QuestionBankItem',
|
|
185
|
+
title: '@assessment-management:question-bank.entities.question-bank-item.title',
|
|
186
|
+
titlePlural: '@assessment-management:question-bank.entities.question-bank-item.plural',
|
|
187
|
+
icon: 'fa-light fa-question-circle',
|
|
188
|
+
},
|
|
189
|
+
questionnaire: {
|
|
190
|
+
name: 'Questionnaire',
|
|
191
|
+
title: '@assessment-management:questionnaires.entities.questionnaire.title',
|
|
192
|
+
titlePlural: '@assessment-management:questionnaires.entities.questionnaire.plural',
|
|
193
|
+
icon: 'fa-light fa-clipboard-list',
|
|
194
|
+
},
|
|
195
|
+
assessmentCase: {
|
|
196
|
+
name: 'AssessmentCase',
|
|
197
|
+
title: '@assessment-management:cases.entities.assessment-case.title',
|
|
198
|
+
titlePlural: '@assessment-management:cases.entities.assessment-case.plural',
|
|
199
|
+
icon: 'fa-light fa-briefcase',
|
|
200
|
+
},
|
|
201
|
+
assessmentSession: {
|
|
202
|
+
name: 'AssessmentSession',
|
|
203
|
+
title: '@assessment-management:sessions.entities.assessment-session.title',
|
|
204
|
+
titlePlural: '@assessment-management:sessions.entities.assessment-session.plural',
|
|
205
|
+
icon: 'fa-light fa-clipboard-check',
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
queries: {
|
|
209
|
+
dashboard: {
|
|
210
|
+
overdueAssessmentsKpi: `${config.module}:Dashboard:OverdueAssessmentsKpi`,
|
|
211
|
+
pendingAssessmentsKpi: `${config.module}:Dashboard:PendingAssessmentsKpi`,
|
|
212
|
+
myAssessmentsKpi: `${config.module}:Dashboard:MyAssessmentsKpi`,
|
|
213
|
+
assessmentsWeekLine: `${config.module}:Dashboard:AssessmentsWeekLine`,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
//#endregion
|
|
218
|
+
|
|
219
|
+
//#region ---- Assessment session PDF preview contracts ----
|
|
220
|
+
/** Server command that renders a filled assessment session to PDF. */
|
|
221
|
+
const AXM_ASSESSMENT_SESSION_PREVIEW_PDF_COMMAND_KEY = 'AssessmentManagement:AssessmentSession:PreviewPdf';
|
|
222
|
+
/** Client / entity-menu command that opens the PDF preview dialog. */
|
|
223
|
+
const AXM_ASSESSMENT_SESSION_PREVIEW_PDF_CLIENT_COMMAND_KEY = 'AssessmentManagement.AssessmentSession:PreviewPdf';
|
|
224
|
+
//#endregion
|
|
225
|
+
|
|
226
|
+
//#region ---- Assessment print merge keys ----
|
|
227
|
+
/**
|
|
228
|
+
* Event merge keys passed to `ContentManagement:TextTemplate:Render` (`channel: print`).
|
|
229
|
+
* Names must match `PlatformManagement.Tokens` Event rows.
|
|
230
|
+
*/
|
|
231
|
+
const AXM_ASSESSMENT_PRINT_MERGE_KEYS = {
|
|
232
|
+
questionnaireTitle: 'questionnaireTitle',
|
|
233
|
+
caseTitle: 'caseTitle',
|
|
234
|
+
sessionDate: 'sessionDate',
|
|
235
|
+
generatedAt: 'generatedAt',
|
|
236
|
+
status: 'status',
|
|
237
|
+
statusLabel: 'statusLabel',
|
|
238
|
+
sessionBody: 'sessionBody',
|
|
239
|
+
};
|
|
240
|
+
//#endregion
|
|
241
|
+
|
|
242
|
+
//#region ---- Print HTML snapshot helpers ----
|
|
243
|
+
const ASSESSMENT_PRINT_PAGE_FORMAT = DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS.paperSize;
|
|
244
|
+
/** A4 portrait content width after 14mm side margins (210 - 14 - 14). */
|
|
245
|
+
const ASSESSMENT_PRINT_CONTENT_WIDTH_MM = resolvePrintContentWidthMm(DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS);
|
|
246
|
+
const ASSESSMENT_PRINT_HTML_GZIP_ENCODING = 'gzip-base64';
|
|
247
|
+
function resolveWatermarkFontMm(watermark, contentWidthMm) {
|
|
248
|
+
const chars = Math.max(watermark.trim().length, 1);
|
|
249
|
+
const fitted = (contentWidthMm * 0.78) / (chars * 0.62);
|
|
250
|
+
return Math.round(Math.max(5, Math.min(14, fitted)) * 10) / 10;
|
|
251
|
+
}
|
|
252
|
+
function buildPrintDocumentCss(print) {
|
|
253
|
+
const width = resolvePrintContentWidthMm(print);
|
|
254
|
+
const watermark = print.watermark
|
|
255
|
+
? `.__print-watermark{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) rotate(-32deg);transform-origin:center center;pointer-events:none;z-index:0;color:rgba(15,23,42,.12);font-size:${resolveWatermarkFontMm(print.watermark, width)}mm;font-weight:700;letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;line-height:1;}`
|
|
256
|
+
: '';
|
|
257
|
+
return `
|
|
258
|
+
@page { size: ${print.paperSize} ${print.orientation}; }
|
|
259
|
+
html, body { width: ${width}mm; max-width: ${width}mm; margin: 0; }
|
|
260
|
+
body { background: #fff; color: #0f172a; font-family: Arial, Helvetica, sans-serif; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
261
|
+
${watermark}
|
|
262
|
+
.__print-letterhead { width: 100%; border-collapse: collapse; table-layout: fixed; border: 1.25pt solid #1e3a5f; }
|
|
263
|
+
.__print-letterhead__accent { height: 5px; background: #1e3a5f; font-size: 0; line-height: 0; }
|
|
264
|
+
.__print-letterhead__header { padding: 7mm 8mm 5mm; }
|
|
265
|
+
.__print-letterhead__brand { width: 100%; border-collapse: collapse; }
|
|
266
|
+
.__print-letterhead__logo { width: 42px; vertical-align: middle; }
|
|
267
|
+
.__print-letterhead__logo img, .__print-letterhead__logo svg { display: block; max-width: 36px; max-height: 36px; }
|
|
268
|
+
.__print-letterhead__name { font-size: 13.5pt; line-height: 1.2; font-weight: 700; color: #0f172a; letter-spacing: 0.01em; }
|
|
269
|
+
.__print-letterhead__email { font-size: 8.5pt; line-height: 1.4; color: #64748b; margin-top: 2px; }
|
|
270
|
+
.__print-letterhead__contact { text-align: right; vertical-align: middle; font-size: 8pt; line-height: 1.45; color: #64748b; }
|
|
271
|
+
.__print-letterhead__body { padding: 2mm 8mm 8mm; vertical-align: top; min-height: 165mm; }
|
|
272
|
+
.__print-letterhead__footer { padding: 4.5mm 8mm; background: #f1f5f9; border-top: 1px solid #cbd5e1; font-size: 8pt; line-height: 1.45; color: #475569; }
|
|
273
|
+
.__print-letterhead__footer-table { width: 100%; border-collapse: collapse; }
|
|
274
|
+
.__print-letterhead__copy { text-align: right; color: #64748b; }
|
|
275
|
+
.__print-doc-head { margin: 0 0 12px; padding: 0 0 10px; border-bottom: 1px solid #e2e8f0; }
|
|
276
|
+
.__print-doc-title { margin: 0 0 6px; font-size: 15pt; line-height: 1.25; font-weight: 700; color: #0f172a; }
|
|
277
|
+
.__print-doc-meta { display: flex; flex-wrap: wrap; gap: 6px 10px; font-size: 8.5pt; line-height: 1.4; color: #64748b; }
|
|
278
|
+
.__print-doc-meta > span:empty { display: none; }
|
|
279
|
+
.__print-doc-meta > span:not(:empty) { padding: 2px 8px; background: #f1f5f9; border-radius: 999px; color: #334155; }
|
|
280
|
+
.__print-document {
|
|
281
|
+
display: block !important; width: 100%; position: relative; z-index: 1;
|
|
282
|
+
break-inside: auto !important; page-break-inside: auto !important;
|
|
283
|
+
}
|
|
284
|
+
axm-questionnaire-print-host,
|
|
285
|
+
.axm-questionnaire-print-surface,
|
|
286
|
+
axm-questionnaire-viewer,
|
|
287
|
+
axm-questionnaire-viewer-print-view,
|
|
288
|
+
axp-widgets-container,
|
|
289
|
+
ax-form,
|
|
290
|
+
.__questionnaire-container {
|
|
291
|
+
display: block !important; break-inside: auto !important; page-break-inside: auto !important;
|
|
292
|
+
}
|
|
293
|
+
.__print-section {
|
|
294
|
+
display: block !important; break-inside: auto !important; page-break-inside: auto !important;
|
|
295
|
+
margin: 0 0 10px !important; padding: 0 !important; border: 1px solid #d0d9e6 !important; border-radius: 4px !important;
|
|
296
|
+
background: #fff !important; overflow: visible;
|
|
297
|
+
}
|
|
298
|
+
.__print-section:last-child { margin-bottom: 0 !important; }
|
|
299
|
+
axm-questionnaire-viewer-section-header {
|
|
300
|
+
display: block !important; width: 100% !important; margin: 0 !important; padding: 0 !important;
|
|
301
|
+
background: #eef3f8 !important; border-bottom: 1px solid #d0d9e6 !important;
|
|
302
|
+
}
|
|
303
|
+
axm-questionnaire-viewer-section-header .__mb-sm,
|
|
304
|
+
axm-questionnaire-viewer-section-header .__mb-md { margin-bottom: 0 !important; }
|
|
305
|
+
.__print-questions { display: block !important; padding: 2px 12px 8px !important; }
|
|
306
|
+
.__section-header { margin: 0 !important; padding: 8px 12px 7px !important; background: #eef3f8 !important; }
|
|
307
|
+
.__section-title-md, .__section-title-lg, .__print-section h2, .__print-section .__section-title-md, .__print-section .__section-title-lg {
|
|
308
|
+
margin: 0 !important; padding: 0 !important; padding-inline-start: 0 !important; border-inline-start: none !important;
|
|
309
|
+
font-size: 11pt !important; line-height: 1.25 !important; font-weight: 700 !important; color: #0f172a !important;
|
|
310
|
+
}
|
|
311
|
+
.__section-description, .__section-description--rich {
|
|
312
|
+
margin: 2px 0 0 !important; padding-inline-start: 0 !important; font-size: 8.5pt !important; line-height: 1.35 !important; color: #64748b !important;
|
|
313
|
+
}
|
|
314
|
+
.__question-item { break-inside: avoid; page-break-inside: avoid; }
|
|
315
|
+
.__question-item.__print-plain {
|
|
316
|
+
background: transparent !important; box-shadow: none !important; border: none !important; border-bottom: 1px solid #e8eef3 !important;
|
|
317
|
+
border-radius: 0 !important; padding: 8px 0 !important; margin: 0 !important;
|
|
318
|
+
}
|
|
319
|
+
.__print-questions .__question-item.__print-plain:last-child { border-bottom: none !important; }
|
|
320
|
+
.__question-header { display: flex !important; align-items: flex-start !important; gap: 8px !important; width: 100% !important; }
|
|
321
|
+
.__question-number {
|
|
322
|
+
display: inline-block !important; min-width: 0 !important; padding: 0 !important; border-radius: 0 !important;
|
|
323
|
+
background: transparent !important; color: #0f172a !important; font-size: 10pt !important; font-weight: 700 !important; text-align: start !important;
|
|
324
|
+
}
|
|
325
|
+
.__question-title, h3.__question-title, .__question-title--rich {
|
|
326
|
+
margin: 0 !important; font-size: 10pt !important; line-height: 1.4 !important; font-weight: 600 !important; color: #0f172a !important;
|
|
327
|
+
}
|
|
328
|
+
.__question-widget { margin-top: 4px !important; }
|
|
329
|
+
.__question-comment, .__question-comment--readonly {
|
|
330
|
+
margin-top: 4px !important; padding-inline-start: 2px !important;
|
|
331
|
+
}
|
|
332
|
+
.__question-comment-text {
|
|
333
|
+
margin: 0 !important; font-size: 9pt !important; line-height: 1.4 !important; font-weight: 400 !important;
|
|
334
|
+
font-style: italic !important; color: #64748b !important;
|
|
335
|
+
}
|
|
336
|
+
.axp-widget-print-field {
|
|
337
|
+
display: inline-block !important; width: auto !important; min-width: 22mm !important; max-width: 100% !important;
|
|
338
|
+
min-height: 0 !important; margin: 0 !important; padding: 3px 10px !important; border: none !important; border-bottom: none !important;
|
|
339
|
+
border-radius: 4px !important; background: #f1f5f9 !important; color: #0f172a !important; font-size: 11pt !important;
|
|
340
|
+
font-weight: 600 !important; line-height: 1.4 !important; word-break: break-word;
|
|
341
|
+
}
|
|
342
|
+
.axp-widget-print-field--empty {
|
|
343
|
+
background: transparent !important; color: #94a3b8 !important; font-weight: 400 !important; border: 1px dashed #cbd5e1 !important;
|
|
344
|
+
}
|
|
345
|
+
.axp-widget-print-field--multiline, .axp-widget-print-field--rich {
|
|
346
|
+
display: block !important; width: 100% !important; font-weight: 400 !important; background: #f8fafc !important;
|
|
347
|
+
border: 1px solid #e2e8f0 !important; min-height: 3.2em;
|
|
348
|
+
}
|
|
349
|
+
.axp-widget-print-choice { display: inline-flex; align-items: center; gap: 8px; font-size: 10.5pt; color: #0f172a; }
|
|
350
|
+
.axp-widget-print-mark { font-size: 13pt; line-height: 1; }
|
|
351
|
+
.__print-document[data-print-paging="page-per-group"] .__print-section + .__print-section,
|
|
352
|
+
.__print-document[data-print-paging="side-menu"] .__print-section + .__print-section { break-before: page; page-break-before: always; }
|
|
353
|
+
.__print-document[data-print-paging="page-per-question"] axm-questionnaire-viewer-question + axm-questionnaire-viewer-question { break-before: page; page-break-before: always; }
|
|
354
|
+
.__print-extra,
|
|
355
|
+
.__print-outcomes,
|
|
356
|
+
.__print-summary {
|
|
357
|
+
display: block !important;
|
|
358
|
+
break-inside: auto !important;
|
|
359
|
+
page-break-inside: auto !important;
|
|
360
|
+
}
|
|
361
|
+
.__print-outcomes,
|
|
362
|
+
.__print-summary {
|
|
363
|
+
break-before: page !important;
|
|
364
|
+
page-break-before: always !important;
|
|
365
|
+
}
|
|
366
|
+
.__print-outcomes .axp-outcome-results-viewer,
|
|
367
|
+
.__print-outcomes .__root,
|
|
368
|
+
.__print-summary .axm-post-questionnaire-content,
|
|
369
|
+
.__print-summary .__summary {
|
|
370
|
+
display: block !important;
|
|
371
|
+
min-height: 0 !important;
|
|
372
|
+
}
|
|
373
|
+
`;
|
|
374
|
+
}
|
|
375
|
+
function minifyPrintHtml(html) {
|
|
376
|
+
return html
|
|
377
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
378
|
+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
|
379
|
+
.replace(/\sng-reflect-[a-z0-9-]+="[^"]*"/gi, '')
|
|
380
|
+
.replace(/\s_ngcontent-[a-z0-9-]+="[^"]*"/gi, '')
|
|
381
|
+
.replace(/\s_nghost-[a-z0-9-]+="[^"]*"/gi, '')
|
|
382
|
+
.replace(/\sdata-testid="[^"]*"/gi, '')
|
|
383
|
+
.replace(/\sclass=""/g, '')
|
|
384
|
+
.replace(/\s{2,}/g, ' ')
|
|
385
|
+
.replace(/>\s+</g, '><')
|
|
386
|
+
.trim();
|
|
387
|
+
}
|
|
388
|
+
function resolvePrintPlainText(value) {
|
|
389
|
+
if (typeof value === 'string') {
|
|
390
|
+
return value.trim();
|
|
391
|
+
}
|
|
392
|
+
if (!value || typeof value !== 'object') {
|
|
393
|
+
return '';
|
|
394
|
+
}
|
|
395
|
+
const record = value;
|
|
396
|
+
for (const key of ['en-US', 'en', ...Object.keys(record)]) {
|
|
397
|
+
const text = record[key];
|
|
398
|
+
if (typeof text === 'string' && text.trim()) {
|
|
399
|
+
return text.trim();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return '';
|
|
403
|
+
}
|
|
404
|
+
function formatPrintAnswerText(value) {
|
|
405
|
+
if (value == null || value === '') {
|
|
406
|
+
return '—';
|
|
407
|
+
}
|
|
408
|
+
if (typeof value === 'string') {
|
|
409
|
+
const trimmed = value.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
410
|
+
return trimmed || '—';
|
|
411
|
+
}
|
|
412
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
413
|
+
return String(value);
|
|
414
|
+
}
|
|
415
|
+
if (value instanceof Date) {
|
|
416
|
+
return value.toISOString();
|
|
417
|
+
}
|
|
418
|
+
if (Array.isArray(value)) {
|
|
419
|
+
const parts = value.map((item) => formatPrintAnswerText(item)).filter((item) => item !== '—');
|
|
420
|
+
return parts.length ? parts.join(', ') : '—';
|
|
421
|
+
}
|
|
422
|
+
if (typeof value === 'object') {
|
|
423
|
+
const record = value;
|
|
424
|
+
const labeled = record['title'] ?? record['text'] ?? record['label'] ?? record['name'] ?? record['displayName'];
|
|
425
|
+
const resolved = resolvePrintPlainText(labeled);
|
|
426
|
+
if (resolved) {
|
|
427
|
+
return resolved.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
428
|
+
}
|
|
429
|
+
if (record['value'] != null) {
|
|
430
|
+
return formatPrintAnswerText(record['value']);
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
return JSON.stringify(value);
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
return '—';
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return String(value);
|
|
440
|
+
}
|
|
441
|
+
function buildQuestionnaireQuestionCardHtml(input) {
|
|
442
|
+
if (input.cardHtml?.trim()) {
|
|
443
|
+
return input.cardHtml.trim();
|
|
444
|
+
}
|
|
445
|
+
const titleHtml = input.titleHtml.includes('__question-title')
|
|
446
|
+
? input.titleHtml
|
|
447
|
+
: `<h3 class="__question-title">${input.titleHtml}</h3>`;
|
|
448
|
+
const number = input.number
|
|
449
|
+
? `<div class="__question-header-left"><span class="__question-number">${escapePrintDocumentText(input.number)}</span></div>`
|
|
450
|
+
: '';
|
|
451
|
+
const itemClass = '__question-item __print-plain';
|
|
452
|
+
return (`<div class="${itemClass}">` +
|
|
453
|
+
`<div class="__question-header">${number}` +
|
|
454
|
+
`<div class="__question-header-right"><div class="__question-title-block">${titleHtml}</div></div>` +
|
|
455
|
+
`</div>` +
|
|
456
|
+
`<div class="__question-widget">${input.answerHtml}</div>` +
|
|
457
|
+
`</div>`);
|
|
458
|
+
}
|
|
459
|
+
function buildQuestionnairePrintBodyHtml(input) {
|
|
460
|
+
const title = escapePrintDocumentText(input.title || 'Questionnaire');
|
|
461
|
+
const meta = [
|
|
462
|
+
input.caseTitle ? `<div><span>Case</span>${escapePrintDocumentText(input.caseTitle)}</div>` : '',
|
|
463
|
+
input.status ? `<div><span>Status</span>${escapePrintDocumentText(input.status)}</div>` : '',
|
|
464
|
+
]
|
|
465
|
+
.filter(Boolean)
|
|
466
|
+
.join('');
|
|
467
|
+
const sections = input.sections
|
|
468
|
+
.map((section) => {
|
|
469
|
+
const questions = section.questions.map((question) => buildQuestionnaireQuestionCardHtml(question)).join('');
|
|
470
|
+
return `<section class="section"><h2>${escapePrintDocumentText(section.title)}</h2>${questions}</section>`;
|
|
471
|
+
})
|
|
472
|
+
.join('');
|
|
473
|
+
return `<h1>${title}</h1>${meta ? `<div class="meta">${meta}</div>` : ''}${sections}`;
|
|
474
|
+
}
|
|
475
|
+
/** Q&A sections only — title/date live in the questionnaire print child template. */
|
|
476
|
+
function buildQuestionnaireSessionBodyHtml(input) {
|
|
477
|
+
return input.sections
|
|
478
|
+
.map((section) => {
|
|
479
|
+
const questions = section.questions.map((question) => buildQuestionnaireQuestionCardHtml(question)).join('');
|
|
480
|
+
return `<section class="section"><h2>${escapePrintDocumentText(section.title)}</h2>${questions}</section>`;
|
|
481
|
+
})
|
|
482
|
+
.join('');
|
|
483
|
+
}
|
|
484
|
+
/** Compact repeating questionnaire band: title left, date/status right. */
|
|
485
|
+
function buildQuestionnairePrintHeaderRegion(input) {
|
|
486
|
+
const title = escapePrintDocumentText(input.title.trim() || 'Questionnaire');
|
|
487
|
+
const caseTitle = escapePrintDocumentText((input.caseTitle ?? '').trim());
|
|
488
|
+
const sessionDate = escapePrintDocumentText((input.sessionDate ?? '').trim());
|
|
489
|
+
const statusLabel = escapePrintDocumentText((input.statusLabel ?? '').trim());
|
|
490
|
+
const sub = caseTitle
|
|
491
|
+
? `<div style="font-size:7.5pt;line-height:1.25;color:#64748b;margin-top:1px;">${caseTitle}</div>`
|
|
492
|
+
: '';
|
|
493
|
+
const right = [sessionDate, statusLabel].filter(Boolean).join(' · ');
|
|
494
|
+
const rightCell = right
|
|
495
|
+
? `<td style="vertical-align:middle;text-align:right;padding:1px 0 2px;white-space:nowrap;font-size:8pt;line-height:1.25;color:#64748b;width:36%;">${right}</td>`
|
|
496
|
+
: '';
|
|
497
|
+
return (`<header data-print-region="header" class="__print-page-header">` +
|
|
498
|
+
`<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" ` +
|
|
499
|
+
`style="width:100%;border-collapse:collapse;margin-top:2px;">` +
|
|
500
|
+
`<tr><td style="vertical-align:middle;padding:1px 0 2px;">` +
|
|
501
|
+
`<div style="font-size:10pt;line-height:1.2;font-weight:700;color:#0f172a;">${title}</div>${sub}` +
|
|
502
|
+
`</td>${rightCell}</tr></table>` +
|
|
503
|
+
`<div style="border-bottom:1px solid #cbd5e1;font-size:0;line-height:0;"> </div>` +
|
|
504
|
+
`</header>`);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Ensures the compact questionnaire header is the last `data-print-region="header"`
|
|
508
|
+
* (under the company letterhead) and removes the old first-page-only title block.
|
|
509
|
+
*/
|
|
510
|
+
function applyQuestionnairePrintHeader(html, input) {
|
|
511
|
+
const region = buildQuestionnairePrintHeaderRegion(input);
|
|
512
|
+
let next = html.replace(/<div class="__print-doc-head">\s*<h1\b[^>]*>[\s\S]*?<\/h1>\s*<div class="__print-doc-meta">[\s\S]*?<\/div>\s*<\/div>/i, '');
|
|
513
|
+
const headerRe = /<header\b[^>]*data-print-region=["']header["'][^>]*>[\s\S]*?<\/header>/gi;
|
|
514
|
+
const headers = next.match(headerRe) ?? [];
|
|
515
|
+
if (headers.length >= 2) {
|
|
516
|
+
let index = 0;
|
|
517
|
+
return next.replace(headerRe, (block) => {
|
|
518
|
+
index += 1;
|
|
519
|
+
return index === headers.length ? region : block;
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
if (headers.length === 1) {
|
|
523
|
+
return next.replace(headerRe, (block) => `${block}${region}`);
|
|
524
|
+
}
|
|
525
|
+
return `${region}${next}`;
|
|
526
|
+
}
|
|
527
|
+
/** Inner body of a wrapped print document, without watermark. */
|
|
528
|
+
function extractPrintDocumentBodyHtml(html) {
|
|
529
|
+
const trimmed = html.trim();
|
|
530
|
+
const bodyMatch = trimmed.match(/<body[^>]*>([\s\S]*)<\/body>/i);
|
|
531
|
+
const inner = (bodyMatch?.[1] ?? trimmed).trim();
|
|
532
|
+
return inner.replace(/<div class="__print-watermark"[^>]*>[\s\S]*?<\/div>/gi, '').trim();
|
|
533
|
+
}
|
|
534
|
+
function wrapPrintDocument(input) {
|
|
535
|
+
const title = escapePrintDocumentText(input.title || 'Questionnaire');
|
|
536
|
+
const print = resolvePrintSettings(input.print);
|
|
537
|
+
const watermark = print.watermark
|
|
538
|
+
? `<div class="__print-watermark" aria-hidden="true">${escapePrintDocumentText(print.watermark)}</div>`
|
|
539
|
+
: '';
|
|
540
|
+
const html = `<!doctype html><html><head><meta charset="utf-8"/>` +
|
|
541
|
+
`<title>${title}</title>` +
|
|
542
|
+
`<style>${buildPrintDocumentCss(print)}</style></head><body>` +
|
|
543
|
+
`${watermark}${input.bodyHtml}` +
|
|
544
|
+
`</body></html>`;
|
|
545
|
+
return {
|
|
546
|
+
html,
|
|
547
|
+
headerHtml: input.headerHtml !== undefined
|
|
548
|
+
? input.headerHtml
|
|
549
|
+
: `<span style="font-weight:700;">${title}</span>`,
|
|
550
|
+
footerHtml: input.footerHtml !== undefined
|
|
551
|
+
? input.footerHtml
|
|
552
|
+
: '<span style="font-size:8pt;color:#94a3b8;font-family:Arial,Helvetica,sans-serif;"><span class="pageNumber"></span> / <span class="totalPages"></span></span>',
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function escapePrintDocumentText(value) {
|
|
556
|
+
return value
|
|
557
|
+
.replace(/&/g, '&')
|
|
558
|
+
.replace(/</g, '<')
|
|
559
|
+
.replace(/>/g, '>')
|
|
560
|
+
.replace(/"/g, '"')
|
|
561
|
+
.replace(/'/g, ''');
|
|
562
|
+
}
|
|
563
|
+
//#endregion
|
|
564
|
+
|
|
565
|
+
//#endregion
|
|
566
|
+
|
|
567
|
+
//#endregion
|
|
568
|
+
|
|
569
|
+
//#endregion
|
|
570
|
+
|
|
571
|
+
//#region ---- Question comment value object ----
|
|
572
|
+
/**
|
|
573
|
+
* Default when no configuration is stored.
|
|
574
|
+
*/
|
|
575
|
+
const DEFAULT_QUESTION_COMMENT_CONFIG = {
|
|
576
|
+
enabled: false,
|
|
577
|
+
required: false,
|
|
578
|
+
};
|
|
579
|
+
/**
|
|
580
|
+
* Normalizes `enabled` / `isVisible`-style flags: booleans, legacy string booleans, or expression strings.
|
|
581
|
+
*/
|
|
582
|
+
function normalizeCommentFlag(value, emptyAs) {
|
|
583
|
+
if (value === undefined || value === null) {
|
|
584
|
+
return emptyAs;
|
|
585
|
+
}
|
|
586
|
+
if (value === true || value === false) {
|
|
587
|
+
return value;
|
|
588
|
+
}
|
|
589
|
+
if (typeof value === 'string') {
|
|
590
|
+
const trimmed = value.trim();
|
|
591
|
+
if (!trimmed) {
|
|
592
|
+
return emptyAs;
|
|
593
|
+
}
|
|
594
|
+
const lower = trimmed.toLowerCase();
|
|
595
|
+
if (lower === 'true' || lower === '1') {
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
if (lower === 'false' || lower === '0') {
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
return trimmed;
|
|
602
|
+
}
|
|
603
|
+
return value;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Normalizes API / partial values to a complete config.
|
|
607
|
+
* Preserves expression strings on `enabled` (Allow Comments toggle binding).
|
|
608
|
+
*/
|
|
609
|
+
function normalizeQuestionCommentConfig(value) {
|
|
610
|
+
const enabled = normalizeCommentFlag(value?.enabled, false);
|
|
611
|
+
const isVisible = normalizeCommentFlag(value?.isVisible, undefined);
|
|
612
|
+
return {
|
|
613
|
+
enabled: enabled === undefined ? false : enabled,
|
|
614
|
+
required: value?.required === true,
|
|
615
|
+
...(isVisible !== undefined ? { isVisible } : {}),
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Merges question bank defaults with optional questionnaire item overrides.
|
|
620
|
+
*/
|
|
621
|
+
function mergeQuestionCommentConfig(bank, override) {
|
|
622
|
+
const b = normalizeQuestionCommentConfig(bank);
|
|
623
|
+
if (!override) {
|
|
624
|
+
return b;
|
|
625
|
+
}
|
|
626
|
+
const overrideEnabled = override.enabled !== undefined ? normalizeCommentFlag(override.enabled, false) : undefined;
|
|
627
|
+
const overrideVis = normalizeCommentFlag(override.isVisible, undefined);
|
|
628
|
+
return {
|
|
629
|
+
enabled: overrideEnabled !== undefined ? overrideEnabled : b.enabled,
|
|
630
|
+
required: override.required !== undefined ? override.required === true : b.required,
|
|
631
|
+
...(overrideVis !== undefined
|
|
632
|
+
? { isVisible: overrideVis }
|
|
633
|
+
: b.isVisible !== undefined
|
|
634
|
+
? { isVisible: b.isVisible }
|
|
635
|
+
: {}),
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Returns only fields that differ from the bank default (for persisting questionnaire item overrides).
|
|
640
|
+
*/
|
|
641
|
+
function diffQuestionCommentOverride(bank, edited) {
|
|
642
|
+
const diff = {};
|
|
643
|
+
if (edited.enabled !== bank.enabled) {
|
|
644
|
+
diff.enabled = edited.enabled;
|
|
645
|
+
}
|
|
646
|
+
if (edited.required !== bank.required) {
|
|
647
|
+
diff.required = edited.required;
|
|
648
|
+
}
|
|
649
|
+
if (edited.isVisible !== bank.isVisible) {
|
|
650
|
+
diff.isVisible = edited.isVisible;
|
|
651
|
+
}
|
|
652
|
+
return Object.keys(diff).length > 0 ? diff : undefined;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Form context for the question edit dialog: surface legacy `isVisible` expressions on `enabled`
|
|
656
|
+
* (Allow Comments) so they display and save like question `isVisible`.
|
|
657
|
+
*/
|
|
658
|
+
function commentConfigForEditForm(merged) {
|
|
659
|
+
const legacyVis = merged.isVisible;
|
|
660
|
+
if (merged.enabled === true && typeof legacyVis === 'string' && legacyVis.trim()) {
|
|
661
|
+
return {
|
|
662
|
+
enabled: legacyVis.trim(),
|
|
663
|
+
required: merged.required,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
return {
|
|
667
|
+
enabled: merged.enabled,
|
|
668
|
+
required: merged.required,
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Effective visibility flag for the comment box (for async evaluation).
|
|
673
|
+
* Prefers expression/`false` on `enabled`; falls back to legacy `isVisible` when `enabled === true`.
|
|
674
|
+
*/
|
|
675
|
+
function getQuestionCommentVisibilityFlag(comment) {
|
|
676
|
+
if (!comment) {
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
const { enabled, isVisible } = comment;
|
|
680
|
+
if (enabled === false) {
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
if (typeof enabled === 'string') {
|
|
684
|
+
return enabled;
|
|
685
|
+
}
|
|
686
|
+
// enabled === true — optional legacy gate
|
|
687
|
+
return isVisible;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Context path for the respondent comment text for a questionnaire item (`answers.comments.<itemName>`).
|
|
691
|
+
*/
|
|
692
|
+
function getQuestionAnswerCommentStoragePath(questionItemName) {
|
|
693
|
+
return `answers.comments.${questionItemName}`;
|
|
694
|
+
}
|
|
695
|
+
//#endregion
|
|
696
|
+
|
|
697
|
+
//#region ---- Question hint value object ----
|
|
698
|
+
const DEFAULT_QUESTION_HINT_CONFIG = { mode: 'off' };
|
|
699
|
+
const VISUAL_MODES = [
|
|
700
|
+
'info',
|
|
701
|
+
'warning',
|
|
702
|
+
'danger',
|
|
703
|
+
'success',
|
|
704
|
+
'neutral',
|
|
705
|
+
];
|
|
706
|
+
function isEmptyHintContent(c) {
|
|
707
|
+
if (c == null) {
|
|
708
|
+
return true;
|
|
709
|
+
}
|
|
710
|
+
if (typeof c === 'string') {
|
|
711
|
+
return c.trim().length === 0;
|
|
712
|
+
}
|
|
713
|
+
if (typeof c === 'object') {
|
|
714
|
+
return Object.values(c).every((v) => typeof v !== 'string' || v.trim().length === 0);
|
|
715
|
+
}
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
/** Normalizes select / API values to a hint mode (exported for questionnaire builder forms). */
|
|
719
|
+
function normalizeQuestionHintMode(raw) {
|
|
720
|
+
if (raw == null) {
|
|
721
|
+
return undefined;
|
|
722
|
+
}
|
|
723
|
+
if (typeof raw === 'string') {
|
|
724
|
+
if (raw === 'off') {
|
|
725
|
+
return 'off';
|
|
726
|
+
}
|
|
727
|
+
if (VISUAL_MODES.includes(raw)) {
|
|
728
|
+
return raw;
|
|
729
|
+
}
|
|
730
|
+
return undefined;
|
|
731
|
+
}
|
|
732
|
+
if (typeof raw === 'object' && raw !== null && 'id' in raw) {
|
|
733
|
+
const id = raw.id;
|
|
734
|
+
return normalizeQuestionHintMode(id);
|
|
735
|
+
}
|
|
736
|
+
return undefined;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Reads optional `hint` or legacy flat `hintContent` / `hintMode` from a record (API / persisted rows).
|
|
740
|
+
*/
|
|
741
|
+
function readHintFieldsFromRecord(rec) {
|
|
742
|
+
if (!rec) {
|
|
743
|
+
return {};
|
|
744
|
+
}
|
|
745
|
+
const hint = rec['hint'] ?? rec['Hint'];
|
|
746
|
+
const legacyContent = rec['hintContent'] ?? rec['hint_content'];
|
|
747
|
+
const legacyMode = rec['hintMode'] ?? rec['hint_mode'];
|
|
748
|
+
return { hint, legacyContent, legacyMode };
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Normalizes API / partial values to a complete config. Coerces legacy flat fields when `hint` is absent.
|
|
752
|
+
*/
|
|
753
|
+
function normalizeQuestionHintConfig(value, legacy) {
|
|
754
|
+
let mode = normalizeQuestionHintMode(value && typeof value === 'object' && 'mode' in value ? value.mode : undefined);
|
|
755
|
+
let content = value && typeof value === 'object' && 'content' in value
|
|
756
|
+
? value.content
|
|
757
|
+
: undefined;
|
|
758
|
+
const hintObj = value && typeof value === 'object' && ('mode' in value || 'content' in value) ? value : null;
|
|
759
|
+
const noStructuredHint = !hintObj || (mode === undefined && content === undefined);
|
|
760
|
+
if (noStructuredHint && legacy) {
|
|
761
|
+
const lm = normalizeQuestionHintMode(legacy.hintMode);
|
|
762
|
+
const lc = legacy.hintContent;
|
|
763
|
+
if (lm !== undefined) {
|
|
764
|
+
mode = lm;
|
|
765
|
+
}
|
|
766
|
+
if (lc !== undefined) {
|
|
767
|
+
content = lc;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (mode === 'off' || mode === undefined) {
|
|
771
|
+
if (mode === undefined && content != null && !isEmptyHintContent(content)) {
|
|
772
|
+
const fallbackMode = 'info';
|
|
773
|
+
return { mode: fallbackMode, content: content };
|
|
774
|
+
}
|
|
775
|
+
return { mode: 'off' };
|
|
776
|
+
}
|
|
777
|
+
if (isEmptyHintContent(content)) {
|
|
778
|
+
return { mode: 'off' };
|
|
779
|
+
}
|
|
780
|
+
return { mode, content: content };
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Merges question bank defaults with optional questionnaire item overrides (per-field, like former hintContent/hintMode).
|
|
784
|
+
*/
|
|
785
|
+
function mergeQuestionHintForViewer(bank, item) {
|
|
786
|
+
const b = normalizeQuestionHintConfig(bank);
|
|
787
|
+
if (!item || (item.mode === undefined && item.content === undefined)) {
|
|
788
|
+
return b;
|
|
789
|
+
}
|
|
790
|
+
if (item.mode !== undefined) {
|
|
791
|
+
const mode = normalizeQuestionHintMode(item.mode) ?? 'off';
|
|
792
|
+
if (mode === 'off') {
|
|
793
|
+
return { mode: 'off' };
|
|
794
|
+
}
|
|
795
|
+
const content = item.content !== undefined
|
|
796
|
+
? item.content
|
|
797
|
+
: b.mode !== 'off'
|
|
798
|
+
? b.content
|
|
799
|
+
: undefined;
|
|
800
|
+
return normalizeQuestionHintConfig({ mode, content });
|
|
801
|
+
}
|
|
802
|
+
const mode = b.mode !== 'off' ? b.mode : 'info';
|
|
803
|
+
return normalizeQuestionHintConfig({ mode, content: item.content });
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Returns only fields that differ from the bank default (for persisting questionnaire item overrides).
|
|
807
|
+
*/
|
|
808
|
+
function diffQuestionHintOverride(bank, edited) {
|
|
809
|
+
if (edited.mode === 'off' && bank.mode === 'off') {
|
|
810
|
+
return undefined;
|
|
811
|
+
}
|
|
812
|
+
if (edited.mode === 'off' && bank.mode !== 'off') {
|
|
813
|
+
return { mode: 'off' };
|
|
814
|
+
}
|
|
815
|
+
if (bank.mode === 'off' && edited.mode !== 'off') {
|
|
816
|
+
return { mode: edited.mode, content: edited.content };
|
|
817
|
+
}
|
|
818
|
+
const diff = {};
|
|
819
|
+
if (edited.mode !== bank.mode) {
|
|
820
|
+
diff.mode = edited.mode;
|
|
821
|
+
}
|
|
822
|
+
if (edited.mode !== 'off') {
|
|
823
|
+
const bc = bank.mode !== 'off' ? bank.content : undefined;
|
|
824
|
+
const ec = edited.content;
|
|
825
|
+
if (JSON.stringify(ec ?? null) !== JSON.stringify(bc ?? null)) {
|
|
826
|
+
diff.content = ec;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return Object.keys(diff).length > 0 ? diff : undefined;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Normalizes a question bank row (or similar) to a full hint config, including legacy flat fields.
|
|
833
|
+
*/
|
|
834
|
+
function normalizeQuestionHintFromEntityRow(row) {
|
|
835
|
+
const fr = readHintFieldsFromRecord(row);
|
|
836
|
+
return normalizeQuestionHintConfig(fr.hint, {
|
|
837
|
+
hintContent: fr.legacyContent,
|
|
838
|
+
hintMode: fr.legacyMode,
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Reads optional questionnaire item hint override from a persisted item record (including legacy keys).
|
|
843
|
+
*/
|
|
844
|
+
function parseQuestionHintPartialFromRecord(row) {
|
|
845
|
+
if (!row) {
|
|
846
|
+
return undefined;
|
|
847
|
+
}
|
|
848
|
+
const fr = readHintFieldsFromRecord(row);
|
|
849
|
+
if (fr.hint != null && typeof fr.hint === 'object' && !Array.isArray(fr.hint)) {
|
|
850
|
+
const h = fr.hint;
|
|
851
|
+
if (h.mode !== undefined || h.content !== undefined) {
|
|
852
|
+
const out = {};
|
|
853
|
+
if (h.mode !== undefined) {
|
|
854
|
+
const m = normalizeQuestionHintMode(h.mode);
|
|
855
|
+
if (m !== undefined) {
|
|
856
|
+
out.mode = m;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (h.content !== undefined) {
|
|
860
|
+
out.content = h.content;
|
|
861
|
+
}
|
|
862
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
if (fr.legacyContent == null && fr.legacyMode == null) {
|
|
866
|
+
return undefined;
|
|
867
|
+
}
|
|
868
|
+
const out = {};
|
|
869
|
+
if (fr.legacyMode !== undefined) {
|
|
870
|
+
const m = normalizeQuestionHintMode(fr.legacyMode);
|
|
871
|
+
if (m !== undefined) {
|
|
872
|
+
out.mode = m;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
if (fr.legacyContent !== undefined) {
|
|
876
|
+
out.content = fr.legacyContent;
|
|
877
|
+
}
|
|
878
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
879
|
+
}
|
|
880
|
+
//#endregion
|
|
881
|
+
|
|
882
|
+
const DEFAULT_PRE_QUESTIONNAIRE_CONFIG = { enabled: false };
|
|
883
|
+
const DEFAULT_POST_QUESTIONNAIRE_CONFIG = {
|
|
884
|
+
reviewEnabled: false,
|
|
885
|
+
summaryEnabled: false,
|
|
886
|
+
showOutcomeResults: false,
|
|
887
|
+
};
|
|
888
|
+
const DEFAULT_QUESTIONNAIRE_ENTITY_DISPLAY = {
|
|
889
|
+
viewMode: 'single-page',
|
|
890
|
+
showProgressBar: true,
|
|
891
|
+
showTimer: false,
|
|
892
|
+
showQuestionNumbers: true,
|
|
893
|
+
validationStrategy: 'step',
|
|
894
|
+
completionMode: 'submit-only',
|
|
895
|
+
};
|
|
896
|
+
const DEFAULT_QUESTIONNAIRE_ENTITY_PRINT = DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS;
|
|
897
|
+
const OUTCOME_DISPLAY_OPERATORS = [
|
|
898
|
+
'eq',
|
|
899
|
+
'neq',
|
|
900
|
+
'gt',
|
|
901
|
+
'gte',
|
|
902
|
+
'lt',
|
|
903
|
+
'lte',
|
|
904
|
+
];
|
|
905
|
+
const OUTCOME_DISPLAY_EMPHASIS = ['normal', 'medium', 'bold'];
|
|
906
|
+
function normalizeOutcomeDisplayColor(value) {
|
|
907
|
+
if (typeof value !== 'string') {
|
|
908
|
+
return undefined;
|
|
909
|
+
}
|
|
910
|
+
const trimmed = value.trim();
|
|
911
|
+
const parts = trimmed.split(/\s+/);
|
|
912
|
+
if (parts.length !== 3) {
|
|
913
|
+
return undefined;
|
|
914
|
+
}
|
|
915
|
+
return trimmed;
|
|
916
|
+
}
|
|
917
|
+
function normalizeOutcomeDisplayOperator(value) {
|
|
918
|
+
const raw = typeof value === 'string'
|
|
919
|
+
? value
|
|
920
|
+
: typeof value === 'object' && value !== null && 'id' in value
|
|
921
|
+
? String(value.id ?? '')
|
|
922
|
+
: '';
|
|
923
|
+
const normalized = raw.trim().toLowerCase();
|
|
924
|
+
return OUTCOME_DISPLAY_OPERATORS.includes(normalized)
|
|
925
|
+
? normalized
|
|
926
|
+
: undefined;
|
|
927
|
+
}
|
|
928
|
+
function normalizeOutcomeDisplayCompareValue(value) {
|
|
929
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
930
|
+
return value;
|
|
931
|
+
}
|
|
932
|
+
if (typeof value === 'boolean') {
|
|
933
|
+
return value;
|
|
934
|
+
}
|
|
935
|
+
if (typeof value === 'string') {
|
|
936
|
+
const trimmed = value.trim();
|
|
937
|
+
if (!trimmed) {
|
|
938
|
+
return undefined;
|
|
939
|
+
}
|
|
940
|
+
if (trimmed === 'true')
|
|
941
|
+
return true;
|
|
942
|
+
if (trimmed === 'false')
|
|
943
|
+
return false;
|
|
944
|
+
const asNumber = Number(trimmed);
|
|
945
|
+
if (Number.isFinite(asNumber)) {
|
|
946
|
+
return asNumber;
|
|
947
|
+
}
|
|
948
|
+
return trimmed;
|
|
949
|
+
}
|
|
950
|
+
return undefined;
|
|
951
|
+
}
|
|
952
|
+
function normalizeOutcomeDisplayEmphasis(value) {
|
|
953
|
+
const raw = typeof value === 'string'
|
|
954
|
+
? value
|
|
955
|
+
: typeof value === 'object' && value !== null && 'id' in value
|
|
956
|
+
? String(value.id ?? '')
|
|
957
|
+
: '';
|
|
958
|
+
const normalized = raw.trim().toLowerCase();
|
|
959
|
+
return OUTCOME_DISPLAY_EMPHASIS.includes(normalized)
|
|
960
|
+
? normalized
|
|
961
|
+
: 'normal';
|
|
962
|
+
}
|
|
963
|
+
function normalizeOutcomeDisplayIcon(icon) {
|
|
964
|
+
if (icon == null || icon === '') {
|
|
965
|
+
return undefined;
|
|
966
|
+
}
|
|
967
|
+
if (typeof icon === 'string') {
|
|
968
|
+
const trimmed = icon.trim();
|
|
969
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
970
|
+
}
|
|
971
|
+
const styleClass = String(icon.styleClass ?? '').trim();
|
|
972
|
+
const iconClass = String(icon.iconClass ?? '').trim();
|
|
973
|
+
const combined = [styleClass, iconClass].filter(Boolean).join(' ');
|
|
974
|
+
return combined.length > 0 ? combined : undefined;
|
|
975
|
+
}
|
|
976
|
+
/** Parses a theme color chooser value into foreground, background, and border parts. */
|
|
977
|
+
function parseQuestionnaireOutcomeDisplayColor(value) {
|
|
978
|
+
if (!value?.trim()) {
|
|
979
|
+
return null;
|
|
980
|
+
}
|
|
981
|
+
const parts = value.trim().split(/\s+/);
|
|
982
|
+
if (parts.length !== 3) {
|
|
983
|
+
return null;
|
|
984
|
+
}
|
|
985
|
+
return {
|
|
986
|
+
foreground: parts[0],
|
|
987
|
+
background: parts[1],
|
|
988
|
+
border: parts[2],
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
function isQuestionnaireOutcomeDisplayColorHex(value) {
|
|
992
|
+
return value.trim().startsWith('#');
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Returns true when the evaluated outcome value matches the display rule condition.
|
|
996
|
+
*/
|
|
997
|
+
function matchesQuestionnaireOutcomeDisplayRule(value, rule) {
|
|
998
|
+
const right = rule.compareValue;
|
|
999
|
+
switch (rule.operator) {
|
|
1000
|
+
case 'eq':
|
|
1001
|
+
return value == right;
|
|
1002
|
+
case 'neq':
|
|
1003
|
+
return value != right;
|
|
1004
|
+
case 'gt':
|
|
1005
|
+
return Number(value) > Number(right);
|
|
1006
|
+
case 'gte':
|
|
1007
|
+
return Number(value) >= Number(right);
|
|
1008
|
+
case 'lt':
|
|
1009
|
+
return Number(value) < Number(right);
|
|
1010
|
+
case 'lte':
|
|
1011
|
+
return Number(value) <= Number(right);
|
|
1012
|
+
default:
|
|
1013
|
+
return false;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
function normalizeQuestionnaireOutcomeDisplayRules(rules) {
|
|
1017
|
+
if (!Array.isArray(rules)) {
|
|
1018
|
+
return [];
|
|
1019
|
+
}
|
|
1020
|
+
const normalized = [];
|
|
1021
|
+
for (const [index, rule] of rules.entries()) {
|
|
1022
|
+
const operator = normalizeOutcomeDisplayOperator(rule?.operator);
|
|
1023
|
+
const compareValue = normalizeOutcomeDisplayCompareValue(rule?.compareValue);
|
|
1024
|
+
const color = normalizeOutcomeDisplayColor(rule?.color);
|
|
1025
|
+
if (!operator || compareValue === undefined || !color) {
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
normalized.push({
|
|
1029
|
+
id: String(rule?.id ?? '').trim() || `rule-${index + 1}`,
|
|
1030
|
+
order: rule?.order ?? index,
|
|
1031
|
+
operator,
|
|
1032
|
+
compareValue,
|
|
1033
|
+
color,
|
|
1034
|
+
emphasis: normalizeOutcomeDisplayEmphasis(rule?.emphasis),
|
|
1035
|
+
icon: normalizeOutcomeDisplayIcon(rule?.icon),
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
return normalized.sort((a, b) => a.order - b.order);
|
|
1039
|
+
}
|
|
1040
|
+
const DEFAULT_QUESTIONNAIRE_OUTCOMES = { sections: [] };
|
|
1041
|
+
function normalizeQuestionnaireOutcomesValue(value) {
|
|
1042
|
+
const sections = value?.sections;
|
|
1043
|
+
if (!Array.isArray(sections)) {
|
|
1044
|
+
return { sections: [] };
|
|
1045
|
+
}
|
|
1046
|
+
return {
|
|
1047
|
+
sections: sections.map((section, index) => ({
|
|
1048
|
+
...section,
|
|
1049
|
+
name: (section.name ?? '').trim() || `section-${index + 1}`,
|
|
1050
|
+
order: section.order ?? index,
|
|
1051
|
+
items: Array.isArray(section.items)
|
|
1052
|
+
? section.items.map((item) => ({
|
|
1053
|
+
...item,
|
|
1054
|
+
displayRules: normalizeQuestionnaireOutcomeDisplayRules(item.displayRules),
|
|
1055
|
+
}))
|
|
1056
|
+
: [],
|
|
1057
|
+
})),
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
/** All outcome items across sections (evaluation, automations, duplicate checks). */
|
|
1061
|
+
function flattenQuestionnaireOutcomeItems(value) {
|
|
1062
|
+
return normalizeQuestionnaireOutcomesValue(value).sections.flatMap((section) => section.items);
|
|
1063
|
+
}
|
|
1064
|
+
function findDuplicateOutcomeNames(value) {
|
|
1065
|
+
const seen = new Map();
|
|
1066
|
+
for (const item of flattenQuestionnaireOutcomeItems(value)) {
|
|
1067
|
+
const key = (item.name ?? '').trim();
|
|
1068
|
+
if (!key)
|
|
1069
|
+
continue;
|
|
1070
|
+
seen.set(key, (seen.get(key) ?? 0) + 1);
|
|
1071
|
+
}
|
|
1072
|
+
return Array.from(seen.entries())
|
|
1073
|
+
.filter(([, count]) => count > 1)
|
|
1074
|
+
.map(([name]) => name);
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Maps entity pre/post to viewer config (defaults when omitted).
|
|
1078
|
+
*/
|
|
1079
|
+
function toPrePostConfig(q) {
|
|
1080
|
+
if (!q) {
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
const pre = {
|
|
1084
|
+
...DEFAULT_PRE_QUESTIONNAIRE_CONFIG,
|
|
1085
|
+
...q.pre,
|
|
1086
|
+
enabled: q.pre?.enabled === true,
|
|
1087
|
+
};
|
|
1088
|
+
const post = {
|
|
1089
|
+
...DEFAULT_POST_QUESTIONNAIRE_CONFIG,
|
|
1090
|
+
...q.post,
|
|
1091
|
+
reviewEnabled: q.post?.reviewEnabled === true,
|
|
1092
|
+
summaryEnabled: q.post?.summaryEnabled === true,
|
|
1093
|
+
showOutcomeResults: q.post?.showOutcomeResults === true,
|
|
1094
|
+
};
|
|
1095
|
+
return { pre, post };
|
|
1096
|
+
}
|
|
1097
|
+
const VIEW_MODE_VALUES = ['single-page', 'page-per-group', 'page-per-question', 'side-menu'];
|
|
1098
|
+
const VALIDATION_STRATEGY_VALUES = ['step', 'end'];
|
|
1099
|
+
const COMPLETION_MODE_VALUES = ['submit-only', 'save-and-continue'];
|
|
1100
|
+
/**
|
|
1101
|
+
* Coerces stored view mode (string or SelectBox `{ id }`) to a known value.
|
|
1102
|
+
*/
|
|
1103
|
+
function normalizeViewMode(value) {
|
|
1104
|
+
if (typeof value === 'string' && VIEW_MODE_VALUES.includes(value)) {
|
|
1105
|
+
return value;
|
|
1106
|
+
}
|
|
1107
|
+
if (value != null && typeof value === 'object' && 'id' in value && typeof value.id === 'string') {
|
|
1108
|
+
return normalizeViewMode(value.id);
|
|
1109
|
+
}
|
|
1110
|
+
return 'single-page';
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Coerces stored validation strategy (string or SelectBox `{ id }`) to a known value.
|
|
1114
|
+
*/
|
|
1115
|
+
function normalizeValidationStrategy(value) {
|
|
1116
|
+
if (typeof value === 'string' && VALIDATION_STRATEGY_VALUES.includes(value)) {
|
|
1117
|
+
return value;
|
|
1118
|
+
}
|
|
1119
|
+
if (value != null && typeof value === 'object' && 'id' in value && typeof value.id === 'string') {
|
|
1120
|
+
return normalizeValidationStrategy(value.id);
|
|
1121
|
+
}
|
|
1122
|
+
return 'step';
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Coerces stored completion mode (string or SelectBox `{ id }`) to a known value.
|
|
1126
|
+
*/
|
|
1127
|
+
function normalizeCompletionMode(value) {
|
|
1128
|
+
if (typeof value === 'string' && COMPLETION_MODE_VALUES.includes(value)) {
|
|
1129
|
+
return value;
|
|
1130
|
+
}
|
|
1131
|
+
if (value != null && typeof value === 'object' && 'id' in value && typeof value.id === 'string') {
|
|
1132
|
+
return normalizeCompletionMode(value.id);
|
|
1133
|
+
}
|
|
1134
|
+
return 'submit-only';
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Maps entity `display` to {@link QuestionnaireDisplaySettings} (defaults when omitted).
|
|
1138
|
+
*/
|
|
1139
|
+
function toDisplaySettings(q) {
|
|
1140
|
+
if (!q) {
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
1143
|
+
const d = { ...DEFAULT_QUESTIONNAIRE_ENTITY_DISPLAY, ...q.display };
|
|
1144
|
+
return {
|
|
1145
|
+
viewMode: normalizeViewMode(d.viewMode),
|
|
1146
|
+
showProgressBar: d.showProgressBar ?? true,
|
|
1147
|
+
showTimer: d.showTimer ?? false,
|
|
1148
|
+
showQuestionNumbers: d.showQuestionNumbers ?? true,
|
|
1149
|
+
validationStrategy: normalizeValidationStrategy(d.validationStrategy),
|
|
1150
|
+
completionMode: normalizeCompletionMode(d.completionMode),
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Maps entity `print` to {@link QuestionnairePrintSettings} (defaults when omitted).
|
|
1155
|
+
*/
|
|
1156
|
+
function toPrintSettings(q) {
|
|
1157
|
+
if (!q) {
|
|
1158
|
+
return null;
|
|
1159
|
+
}
|
|
1160
|
+
return resolvePrintSettings(q.print);
|
|
1161
|
+
}
|
|
1162
|
+
//#endregion
|
|
1163
|
+
|
|
1164
|
+
//#region ---- Contracts barrel ----
|
|
1165
|
+
|
|
1166
|
+
/**
|
|
1167
|
+
* Generated bundle index. Do not edit.
|
|
1168
|
+
*/
|
|
1169
|
+
|
|
1170
|
+
export { ASSESSMENT_PRINT_CONTENT_WIDTH_MM, ASSESSMENT_PRINT_HTML_GZIP_ENCODING, ASSESSMENT_PRINT_PAGE_FORMAT, AXMAssessmentManagementFeatureKeys, AXMAssessmentManagementPermissionKeys, AXM_ASSESSMENT_PRINT_MERGE_KEYS, AXM_ASSESSMENT_SESSION_PREVIEW_PDF_CLIENT_COMMAND_KEY, AXM_ASSESSMENT_SESSION_PREVIEW_PDF_COMMAND_KEY, AXPAssessmentManagementMenuKeys, AXPSafetyRiskPermissionKeys, DEFAULT_POST_QUESTIONNAIRE_CONFIG, DEFAULT_PRE_QUESTIONNAIRE_CONFIG, DEFAULT_QUESTIONNAIRE_ENTITY_DISPLAY, DEFAULT_QUESTIONNAIRE_ENTITY_PRINT, DEFAULT_QUESTIONNAIRE_OUTCOMES, DEFAULT_QUESTIONNAIRE_PRINT_SETTINGS, DEFAULT_QUESTION_COMMENT_CONFIG, DEFAULT_QUESTION_HINT_CONFIG, PRINT_PAGE_LETTERHEAD_BOTTOM_MARGIN_MM, PRINT_PAGE_LETTERHEAD_TOP_MARGIN_MM, PRINT_PAGE_SIDE_MARGIN_MM, QUESTIONNAIRE_OUTCOMES_PAGE_COMPONENT_KEY, QUESTIONNAIRE_QUESTIONS_PAGE_COMPONENT_KEY, RootConfig, applyQuestionnairePrintHeader, buildQuestionnairePrintBodyHtml, buildQuestionnairePrintHeaderRegion, buildQuestionnaireQuestionCardHtml, buildQuestionnaireSessionBodyHtml, commentConfigForEditForm, diffQuestionCommentOverride, diffQuestionHintOverride, escapePrintDocumentText, extractPrintDocumentBodyHtml, findDuplicateOutcomeNames, flattenQuestionnaireOutcomeItems, formatPrintAnswerText, getQuestionAnswerCommentStoragePath, getQuestionCommentVisibilityFlag, isQuestionnaireOutcomeDisplayColorHex, matchesQuestionnaireOutcomeDisplayRule, mergeQuestionCommentConfig, mergeQuestionHintForViewer, minifyPrintHtml, normalizeCompletionMode, normalizePrintOrientation, normalizePrintPaperSize, normalizePrintWatermark, normalizeQuestionCommentConfig, normalizeQuestionHintConfig, normalizeQuestionHintFromEntityRow, normalizeQuestionHintMode, normalizeQuestionnaireOutcomeDisplayRules, normalizeQuestionnaireOutcomesValue, normalizeValidationStrategy, normalizeViewMode, parseQuestionHintPartialFromRecord, parseQuestionnaireOutcomeDisplayColor, readHintFieldsFromRecord, resolvePrintContentWidthMm, resolvePrintLetterheadPdfMargin, resolvePrintPaging, resolvePrintPdfPageOptions, resolvePrintPlainText, resolvePrintSettings, toDisplaySettings, toPrePostConfig, toPrintSettings, wrapPrintDocument };
|
|
1171
|
+
//# sourceMappingURL=acorex-platform-module-assessment-management-client-contracts.mjs.map
|