@acorex-platform/module-content-management-client 0.0.38 → 0.0.48

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.
Files changed (22) hide show
  1. package/fesm2022/acorex-platform-module-content-management-client-contracts-entities-promotion.mjs +14 -0
  2. package/fesm2022/acorex-platform-module-content-management-client-contracts-entities-promotion.mjs.map +1 -1
  3. package/fesm2022/acorex-platform-module-content-management-client-contracts-entities-text-template.mjs +14 -0
  4. package/fesm2022/acorex-platform-module-content-management-client-contracts-entities-text-template.mjs.map +1 -1
  5. package/fesm2022/{acorex-platform-module-content-management-client-contracts-entity-catalog-acorex-platform-module-content-management-client-contracts-entity-catalog-CTui3PB-.mjs → acorex-platform-module-content-management-client-contracts-entity-catalog-acorex-platform-module-content-management-client-contracts-entity-catalog-B9_qUjL1.mjs} +3 -3
  6. package/fesm2022/{acorex-platform-module-content-management-client-contracts-entity-catalog-acorex-platform-module-content-management-client-contracts-entity-catalog-CTui3PB-.mjs.map → acorex-platform-module-content-management-client-contracts-entity-catalog-acorex-platform-module-content-management-client-contracts-entity-catalog-B9_qUjL1.mjs.map} +1 -1
  7. package/fesm2022/{acorex-platform-module-content-management-client-contracts-entity-catalog-promotion.entity-DXk_WIh3.mjs → acorex-platform-module-content-management-client-contracts-entity-catalog-promotion.entity--ZE6Bas7.mjs} +16 -2
  8. package/fesm2022/acorex-platform-module-content-management-client-contracts-entity-catalog-promotion.entity--ZE6Bas7.mjs.map +1 -0
  9. package/fesm2022/{acorex-platform-module-content-management-client-contracts-entity-catalog-text-template.entity-C8SFkg-E.mjs → acorex-platform-module-content-management-client-contracts-entity-catalog-text-template.entity-DnnRXOwT.mjs} +16 -2
  10. package/fesm2022/acorex-platform-module-content-management-client-contracts-entity-catalog-text-template.entity-DnnRXOwT.mjs.map +1 -0
  11. package/fesm2022/acorex-platform-module-content-management-client-contracts-entity-catalog.mjs +1 -1
  12. package/fesm2022/acorex-platform-module-content-management-client-contracts.mjs +28 -1
  13. package/fesm2022/acorex-platform-module-content-management-client-contracts.mjs.map +1 -1
  14. package/fesm2022/{acorex-platform-module-content-management-client-template-content-editor-widget-edit.component-BZUn1TiT.mjs → acorex-platform-module-content-management-client-template-content-editor-widget-edit.component-Cn-sIxBA.mjs} +141 -15
  15. package/fesm2022/acorex-platform-module-content-management-client-template-content-editor-widget-edit.component-Cn-sIxBA.mjs.map +1 -0
  16. package/fesm2022/acorex-platform-module-content-management-client.mjs +4 -33
  17. package/fesm2022/acorex-platform-module-content-management-client.mjs.map +1 -1
  18. package/package.json +1 -1
  19. package/types/acorex-platform-module-content-management-client-contracts.d.ts +16 -2
  20. package/fesm2022/acorex-platform-module-content-management-client-contracts-entity-catalog-promotion.entity-DXk_WIh3.mjs.map +0 -1
  21. package/fesm2022/acorex-platform-module-content-management-client-contracts-entity-catalog-text-template.entity-C8SFkg-E.mjs.map +0 -1
  22. package/fesm2022/acorex-platform-module-content-management-client-template-content-editor-widget-edit.component-BZUn1TiT.mjs.map +0 -1
@@ -24,11 +24,11 @@ import { AXPCommandExecutor } from '@acorex-platform/framework-client/runtime';
24
24
  import * as i1$1 from '@angular/common';
25
25
  import { CommonModule } from '@angular/common';
26
26
  import * as i0 from '@angular/core';
27
- import { inject, DestroyRef, ElementRef, viewChild, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
27
+ import { inject, DestroyRef, ElementRef, viewChild, signal, computed, effect, untracked, ChangeDetectionStrategy, Component } from '@angular/core';
28
28
  import { DomSanitizer } from '@angular/platform-browser';
29
29
  import * as i2 from '@angular/forms';
30
30
  import { FormsModule } from '@angular/forms';
31
- import { runtimeCommandPayloadData } from '@acorex-platform/framework-shared/core';
31
+ import { isFormValueEqual, runtimeCommandPayloadData } from '@acorex-platform/framework-shared/core';
32
32
  import { AXM_TEXT_TEMPLATE_KIND, AXM_TEXT_TEMPLATE_CONTENT_SLOT, resolveTextTemplateLocalizedString, AXM_TEXT_TEMPLATE_PREVIEW_COMMAND_KEY, collectTextTemplatePlaceholderNames, RootConfig, AXM_TEXT_TEMPLATE_MAX_PARENT_DEPTH, composeTextTemplateBodyChain, replaceTextTemplatePlaceholders, renderTextTemplateSource } from '@acorex-platform/module-content-management-client/contracts';
33
33
  import { AXP_TEXT_TEMPLATE_CHANNEL_DEFINITION_PROVIDER } from './acorex-platform-module-content-management-client.mjs';
34
34
 
@@ -107,6 +107,16 @@ class AXMTemplateContentEditorWidgetEditComponent extends AXPValueWidgetComponen
107
107
  this.hostRef = inject((ElementRef));
108
108
  /** Dedupes in-flight preview loads when effect re-runs. */
109
109
  this.previewRequestSeq = 0;
110
+ /**
111
+ * Quill `text-change` is debounced (~300ms) and `commitValue(html, true)` marks
112
+ * hydration as a user edit. Ignore writes until that timer elapses after a programmatic sync.
113
+ */
114
+ this.suppressWysiwygWrites = false;
115
+ this.suppressWysiwygWritesTimer = null;
116
+ this.lastSyncedChannel = null;
117
+ this.lastSyncedViewMode = null;
118
+ /** Drops the ax-tabs init event so it cannot overwrite the content-channel tab. */
119
+ this.ignoreNextChannelTabChange = false;
110
120
  this.wysiwygRef = viewChild('wysiwygRef', /* @ts-ignore */
111
121
  ...(ngDevMode ? [{ debugName: "wysiwygRef" }] : /* istanbul ignore next */ []));
112
122
  this.bodyTextareaRef = viewChild('bodyTextarea', { ...(ngDevMode ? { debugName: "bodyTextareaRef" } : /* istanbul ignore next */ {}), read: (ElementRef) });
@@ -158,9 +168,38 @@ class AXMTemplateContentEditorWidgetEditComponent extends AXPValueWidgetComponen
158
168
  this.serverPreviewByChannel.set({});
159
169
  }
160
170
  });
171
+ /**
172
+ * Quill keeps its own DOM; one-way ngModel does not refresh it when the entity
173
+ * loads, the user discards, or the active channel tab changes.
174
+ */
175
+ effect(() => {
176
+ const viewMode = this.viewMode();
177
+ const channel = this.activeChannel();
178
+ const changeState = this.contextService.changeEvent().state;
179
+ const body = channel ? this.getChannelBody(channel.name) : '';
180
+ const editor = this.wysiwygRef();
181
+ if (viewMode !== 'edit' || !channel || channel.type === 'plain' || !editor) {
182
+ this.lastSyncedViewMode = viewMode;
183
+ return;
184
+ }
185
+ const channelChanged = channel.name !== this.lastSyncedChannel;
186
+ const viewModeChanged = viewMode !== this.lastSyncedViewMode;
187
+ const editorChanged = editor !== this.lastSyncedWysiwyg;
188
+ const contextReload = this.shouldSyncWysiwygFromContext(changeState);
189
+ if (!channelChanged && !viewModeChanged && !editorChanged && !contextReload) {
190
+ return;
191
+ }
192
+ untracked(() => {
193
+ this.lastSyncedChannel = channel.name;
194
+ this.lastSyncedViewMode = viewMode;
195
+ this.lastSyncedWysiwyg = editor;
196
+ void this.applyWysiwygContentWhenReady(editor, body);
197
+ });
198
+ });
161
199
  this.settingsService.onChanged.subscribe(() => {
162
200
  void this.refreshChannelConfiguration();
163
201
  });
202
+ this.destroyRef.onDestroy(() => this.clearSuppressWysiwygWritesTimer());
164
203
  }
165
204
  isChannelConfigured(name) {
166
205
  return this.channelConfigured()[name] ?? true;
@@ -268,10 +307,23 @@ class AXMTemplateContentEditorWidgetEditComponent extends AXPValueWidgetComponen
268
307
  const names = Object.keys(value);
269
308
  const chs = this.availableChannels();
270
309
  const idx = chs.findIndex((c) => names.includes(c.name));
271
- if (idx >= 0)
310
+ if (idx >= 0) {
311
+ this.ignoreNextChannelTabChange = true;
312
+ this.beginSuppressWysiwygWrites();
272
313
  this.activeTabIndex.set(idx);
314
+ setTimeout(() => {
315
+ this.ignoreNextChannelTabChange = false;
316
+ });
317
+ }
273
318
  }
274
319
  }
320
+ onChannelTabChanged(index) {
321
+ if (this.ignoreNextChannelTabChange || index === this.activeTabIndex()) {
322
+ return;
323
+ }
324
+ this.beginSuppressWysiwygWrites();
325
+ this.activeTabIndex.set(index);
326
+ }
275
327
  /** Capture cursor/selection before dropdown opens (runs in mousedown capture phase) */
276
328
  captureCursorBeforeInsert() {
277
329
  const ch = this.activeChannel();
@@ -387,43 +439,117 @@ class AXMTemplateContentEditorWidgetEditComponent extends AXPValueWidgetComponen
387
439
  this.setChannelSubject(targetName, this.getChannelSubject(sourceName));
388
440
  }
389
441
  this.setChannelBody(targetName, this.getChannelBody(sourceName));
442
+ const active = this.activeChannel();
443
+ if (active?.name === targetName && active.type === 'rich') {
444
+ void this.applyWysiwygContentWhenReady(this.wysiwygRef(), this.getChannelBody(targetName));
445
+ }
390
446
  }
391
447
  getChannelSubject(name) {
392
448
  const v = this.getValue()?.[name];
393
449
  const raw = v && typeof v === 'object' && 'subject' in v ? v.subject : undefined;
394
450
  return resolveTextTemplateLocalizedString(raw, this.getTemplateLocale());
395
451
  }
452
+ handleSubjectChange(name, e) {
453
+ if (!e.isUserInteraction) {
454
+ return;
455
+ }
456
+ this.setChannelSubject(name, e.value ?? '');
457
+ }
396
458
  setChannelSubject(name, value) {
459
+ const nextText = value ?? '';
460
+ if (this.getChannelSubject(name) === nextText) {
461
+ return;
462
+ }
397
463
  const current = this.getValue() || {};
464
+ if (!current[name] && !nextText.trim()) {
465
+ return;
466
+ }
398
467
  const ch = current[name] || { body: '' };
399
468
  const locale = this.getTemplateLocale();
400
469
  const ml = this.normalizeChannelFieldToMl(ch.subject);
401
- ml[locale] = value ?? '';
402
- this.setValue({ ...current, [name]: { ...ch, subject: ml } });
470
+ ml[locale] = nextText;
471
+ this.commitChannelValue(current, name, { ...ch, subject: ml });
403
472
  }
404
473
  getChannelBody(name) {
405
474
  const v = this.getValue()?.[name];
406
475
  const raw = v && typeof v === 'object' && 'body' in v ? v.body : undefined;
407
476
  return resolveTextTemplateLocalizedString(raw, this.getTemplateLocale());
408
477
  }
478
+ handlePlainBodyChange(name, e) {
479
+ if (!e.isUserInteraction) {
480
+ return;
481
+ }
482
+ this.setChannelBody(name, e.value ?? '');
483
+ }
409
484
  handleWysiwygChange(name, e) {
485
+ if (this.suppressWysiwygWrites || !e.isUserInteraction) {
486
+ return;
487
+ }
410
488
  const val = typeof e === 'object' && e !== null && 'value' in e
411
- ? e.value
489
+ ? (e.value ?? '')
412
490
  : String(e ?? '');
413
491
  this.setChannelBody(name, val);
414
492
  }
415
493
  setChannelBody(name, value) {
494
+ const nextText = value ?? '';
495
+ if (this.getChannelBody(name) === nextText) {
496
+ return;
497
+ }
416
498
  const current = this.getValue() || {};
499
+ if (!current[name] && !nextText.trim()) {
500
+ return;
501
+ }
417
502
  const ch = current[name] || { body: '' };
418
- const hasSubject = this.availableChannels().find((c) => c.name === name)?.hasSubject ?? false;
419
503
  const locale = this.getTemplateLocale();
420
504
  const ml = this.normalizeChannelFieldToMl(ch.body);
421
- ml[locale] = value ?? '';
422
- if (hasSubject) {
423
- this.setValue({ ...current, [name]: { ...ch, body: ml } });
505
+ ml[locale] = nextText;
506
+ this.commitChannelValue(current, name, { ...ch, body: ml });
507
+ }
508
+ commitChannelValue(current, name, nextChannel) {
509
+ const nextValue = { ...current, [name]: nextChannel };
510
+ if (isFormValueEqual(nextValue, current)) {
511
+ return;
424
512
  }
425
- else {
426
- this.setValue({ ...current, [name]: { body: ml } });
513
+ const path = this.fullPath();
514
+ const saved = path ? this.contextService.getSavedValue(path) : undefined;
515
+ if (saved !== undefined && isFormValueEqual(nextValue, saved)) {
516
+ return;
517
+ }
518
+ this.setValue(nextValue);
519
+ }
520
+ shouldSyncWysiwygFromContext(state) {
521
+ return state === 'restored' || state === 'initiated';
522
+ }
523
+ beginSuppressWysiwygWrites() {
524
+ this.suppressWysiwygWrites = true;
525
+ this.clearSuppressWysiwygWritesTimer();
526
+ this.suppressWysiwygWritesTimer = setTimeout(() => {
527
+ this.suppressWysiwygWrites = false;
528
+ this.suppressWysiwygWritesTimer = null;
529
+ }, 500);
530
+ }
531
+ clearSuppressWysiwygWritesTimer() {
532
+ if (this.suppressWysiwygWritesTimer) {
533
+ clearTimeout(this.suppressWysiwygWritesTimer);
534
+ this.suppressWysiwygWritesTimer = null;
535
+ }
536
+ }
537
+ async applyWysiwygContentWhenReady(wysiwyg, text) {
538
+ const content = text ?? '';
539
+ for (let attempt = 0; attempt < 30; attempt++) {
540
+ const editor = this.wysiwygRef() ?? wysiwyg;
541
+ if (!editor) {
542
+ await new Promise((resolve) => setTimeout(resolve, 50));
543
+ continue;
544
+ }
545
+ try {
546
+ this.beginSuppressWysiwygWrites();
547
+ editor.setWysiwygContent(content);
548
+ return;
549
+ }
550
+ catch {
551
+ await new Promise((resolve) => setTimeout(resolve, 50));
552
+ }
427
553
  }
428
554
  }
429
555
  /**
@@ -670,7 +796,7 @@ class AXMTemplateContentEditorWidgetEditComponent extends AXPValueWidgetComponen
670
796
  .replace(/\n/g, '<br/>');
671
797
  }
672
798
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTemplateContentEditorWidgetEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
673
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMTemplateContentEditorWidgetEditComponent, isStandalone: true, selector: "axm-template-content-editor-widget-edit", viewQueries: [{ propertyName: "wysiwygRef", first: true, predicate: ["wysiwygRef"], descendants: true, isSignal: true }, { propertyName: "bodyTextareaRef", first: true, predicate: ["bodyTextarea"], descendants: true, read: ElementRef, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Template Content Editor: Channel tabs and content per channel -->\n<div class=\"flex flex-col gap-4 w-full\">\n <!-- Channel tabs navigation -->\n <div class=\"flex items-center gap-2 flex-wrap\">\n <ax-tabs\n [look]=\"'with-line'\"\n (onActiveTabChanged)=\"activeTabIndex.set($event.index)\"\n class=\"flex-1 min-w-0\"\n >\n @for (ch of availableChannels(); track ch.name; let i = $index) {\n <ax-tab-item\n [text]=\"(ch.title | translate | async) ?? ch.name\"\n [key]=\"i.toString()\"\n [active]=\"activeTabIndex() === i\"\n ></ax-tab-item>\n }\n </ax-tabs>\n </div>\n\n @if (activeChannel(); as ch) {\n <!-- Channel content area: Edit mode or Preview mode -->\n <div class=\"mb-4 p-4\">\n @if (!isChannelConfigured(ch.name) && ch.notConfiguredMessageKey) {\n <div\n class=\"mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-3 rounded border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/30\"\n >\n <p class=\"text-sm text-amber-900 dark:text-amber-100\">\n {{ ch.notConfiguredMessageKey | translate | async }}\n </p>\n @if (ch.configureSettings) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.configure-channel'\n | translate\n | async\n \"\n look=\"outline\"\n color=\"primary\"\n size=\"sm\"\n (onClick)=\"openChannelConfigure(ch)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-gear\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </div>\n }\n\n @if (viewMode() === 'edit') {\n <!-- Edit mode: Subject field (for channels that support it, e.g. Email) -->\n @if (ch.hasSubject) {\n <div class=\"mb-3\">\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}\n </label>\n <ax-text-box\n [ngModel]=\"getChannelSubject(ch.name)\"\n (ngModelChange)=\"setChannelSubject(ch.name, $event)\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.subject.placeholder'\n | translate\n | async)!\n \"\n ></ax-text-box>\n </div>\n }\n\n <!-- Edit mode: Body field (plain text or rich WYSIWYG) -->\n <div>\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.body.title'\n | translate\n | async\n }}\n </label>\n @if (ch.type === 'plain') {\n <ax-text-area\n #bodyTextarea\n [ngModel]=\"getChannelBody(ch.name)\"\n (ngModelChange)=\"setChannelBody(ch.name, $event)\"\n [rows]=\"8\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.plain'\n | translate\n | async)!\n \"\n ></ax-text-area>\n } @else {\n <ax-wysiwyg-container\n #wysiwygRef\n [placeHolder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.rich'\n | translate\n | async)!\n \"\n [ngModel]=\"getChannelBody(ch.name)\"\n (onValueChanged)=\"handleWysiwygChange(ch.name, $event)\"\n [look]=\"'solid'\"\n >\n <ax-wysiwyg-view [style.min-height.px]=\"200\"></ax-wysiwyg-view>\n <ax-wysiwyg-toolbar>\n <ax-prefix>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n </ax-prefix>\n </ax-wysiwyg-toolbar>\n </ax-wysiwyg-container>\n }\n </div>\n } @else {\n <!-- Preview mode: Rendered content with variable placeholders replaced by sample values -->\n <div class=\"space-y-2\">\n @if (ch.hasSubject && previewSubject(ch.name)) {\n <div>\n <span class=\"text-xs text-gray-500\"\n >{{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}:\n </span>\n <span class=\"text-sm\">{{ previewSubject(ch.name) }}</span>\n </div>\n }\n <!-- ----- Rich email keeps inline styles; plain channels use pre-wrap ----- -->\n <div\n class=\"text-sm p-3 bg-gray-100 dark:bg-gray-900 rounded border overflow-auto\"\n [class.whitespace-pre-wrap]=\"ch.type !== 'rich'\"\n [innerHTML]=\"previewBodyHtml(ch.name)\"\n ></div>\n </div>\n }\n </div>\n\n <!-- Footer: Action buttons (left) + Edit/Preview toggle (right) in single row -->\n <div\n class=\"flex flex-nowrap items-center justify-between gap-3 pt-3 mt-1 border-t border-gray-200 dark:border-gray-700\"\n >\n <div class=\"flex flex-nowrap items-center gap-2 min-w-0\">\n @if (viewMode() === 'edit') {\n <!-- ----- Insert variable dropdown from platform tokens ----- -->\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-variable'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (v of availableVariables(); track v.name) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(v.title || v.name) + ' ({{' + v.name + '}})'\"\n (onClick)=\"insertVariable(ch.name, v.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getVariableIcon(v)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n </ax-button>\n </div>\n <!--->\n <!-- ----- Insert reserved [content] slot for master templates ----- -->\n @if (isMasterKind()) {\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-content-slot'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n (onClick)=\"insertContentSlot(ch.name)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n }\n <!--->\n <!-- ----- Copy subject/body from another channel ----- -->\n @if (otherChannelsWithContent(ch.name).length > 0) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.copy-from'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-copy\"></ax-icon>\n </ax-prefix>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (\n src of otherChannelsWithContent(ch.name);\n track src.name\n ) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(src.title | translate | async) ?? src.name\"\n (onClick)=\"copyFromChannel(ch.name, src.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getChannelIcon(src)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n }\n </div>\n <div>\n <ax-tabs [look]=\"'default'\">\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.edit'\n | translate\n | async) ?? 'Edit'\n \"\n [active]=\"viewMode() === 'edit'\"\n (onClick)=\"viewMode.set('edit')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-pen\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.preview'\n | translate\n | async) ?? 'Preview'\n \"\n [active]=\"viewMode() === 'preview'\"\n (onClick)=\"viewMode.set('preview')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-eye\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n </ax-tabs>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i3.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "reorderable", "reorderDelay", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged", "onTabsReordered"] }, { kind: "component", type: i3.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXTextAreaModule }, { kind: "component", type: i4.AXTextAreaComponent, selector: "ax-text-area", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "placeholder", "maxLength", "look", "rows", "allowResize", "showCounter", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i5.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "maskPattern", "customTokens", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onMaskChanged"] }, { kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i6.AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "readonly", "disabled", "value", "placeHolder", "initialLine"], outputs: ["onValueChanged"] }, { kind: "component", type: i6.AXWysiwygViewComponent, selector: "ax-wysiwyg-view" }, { kind: "component", type: i6.AXWysiwygFontStyleComponent, selector: "ax-wysiwyg-font-style" }, { kind: "component", type: i6.AXWysiwygHistoryComponent, selector: "ax-wysiwyg-history" }, { kind: "component", type: i6.AXWysiwygListComponent, selector: "ax-wysiwyg-list" }, { kind: "component", type: i6.AXWysiwygToolbarComponent, selector: "ax-wysiwyg-toolbar" }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i7.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i7.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i7.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i8.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i2$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
799
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMTemplateContentEditorWidgetEditComponent, isStandalone: true, selector: "axm-template-content-editor-widget-edit", viewQueries: [{ propertyName: "wysiwygRef", first: true, predicate: ["wysiwygRef"], descendants: true, isSignal: true }, { propertyName: "bodyTextareaRef", first: true, predicate: ["bodyTextarea"], descendants: true, read: ElementRef, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Template Content Editor: Channel tabs and content per channel -->\n<div class=\"flex flex-col gap-4 w-full\">\n <!-- Channel tabs navigation -->\n <div class=\"flex items-center gap-2 flex-wrap\">\n <ax-tabs\n [look]=\"'with-line'\"\n (onActiveTabChanged)=\"onChannelTabChanged($event.index)\"\n class=\"flex-1 min-w-0\"\n >\n @for (ch of availableChannels(); track ch.name; let i = $index) {\n <ax-tab-item\n [text]=\"(ch.title | translate | async) ?? ch.name\"\n [key]=\"i.toString()\"\n [active]=\"activeTabIndex() === i\"\n ></ax-tab-item>\n }\n </ax-tabs>\n </div>\n\n @if (activeChannel(); as ch) {\n <!-- Channel content area: Edit mode or Preview mode -->\n <div class=\"mb-4 p-4\">\n @if (!isChannelConfigured(ch.name) && ch.notConfiguredMessageKey) {\n <div\n class=\"mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-3 rounded border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/30\"\n >\n <p class=\"text-sm text-amber-900 dark:text-amber-100\">\n {{ ch.notConfiguredMessageKey | translate | async }}\n </p>\n @if (ch.configureSettings) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.configure-channel'\n | translate\n | async\n \"\n look=\"outline\"\n color=\"primary\"\n size=\"sm\"\n (onClick)=\"openChannelConfigure(ch)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-gear\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </div>\n }\n\n @if (viewMode() === 'edit') {\n <!-- Edit mode: Subject field (for channels that support it, e.g. Email) -->\n @if (ch.hasSubject) {\n <div class=\"mb-3\">\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}\n </label>\n <ax-text-box\n [ngModel]=\"getChannelSubject(ch.name)\"\n (onValueChanged)=\"handleSubjectChange(ch.name, $event)\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.subject.placeholder'\n | translate\n | async)!\n \"\n ></ax-text-box>\n </div>\n }\n\n <!-- Edit mode: Body field (plain text or rich WYSIWYG) -->\n <div>\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.body.title'\n | translate\n | async\n }}\n </label>\n <!--->\n <!-- ----- Plain-text body for SMS-style channels ----- -->\n @if (ch.type === 'plain') {\n <ax-text-area\n #bodyTextarea\n [ngModel]=\"getChannelBody(ch.name)\"\n (onValueChanged)=\"handlePlainBodyChange(ch.name, $event)\"\n [rows]=\"8\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.plain'\n | translate\n | async)!\n \"\n ></ax-text-area>\n }\n <!-- ----- Recreate Quill per channel so tab switches do not keep the previous HTML ----- -->\n @else {\n @for (channelName of [ch.name]; track channelName) {\n <ax-wysiwyg-container\n #wysiwygRef\n [placeHolder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.rich'\n | translate\n | async)!\n \"\n [ngModel]=\"getChannelBody(channelName)\"\n (onValueChanged)=\"handleWysiwygChange(channelName, $event)\"\n [look]=\"'solid'\"\n >\n <ax-wysiwyg-view [style.min-height.px]=\"200\"></ax-wysiwyg-view>\n <ax-wysiwyg-toolbar>\n <ax-prefix>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n </ax-prefix>\n </ax-wysiwyg-toolbar>\n </ax-wysiwyg-container>\n }\n }\n </div>\n } @else {\n <!-- Preview mode: Rendered content with variable placeholders replaced by sample values -->\n <div class=\"space-y-2\">\n @if (ch.hasSubject && previewSubject(ch.name)) {\n <div>\n <span class=\"text-xs text-gray-500\"\n >{{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}:\n </span>\n <span class=\"text-sm\">{{ previewSubject(ch.name) }}</span>\n </div>\n }\n <!-- ----- Rich email keeps inline styles; plain channels use pre-wrap ----- -->\n <div\n class=\"text-sm p-3 bg-gray-100 dark:bg-gray-900 rounded border overflow-auto\"\n [class.whitespace-pre-wrap]=\"ch.type !== 'rich'\"\n [innerHTML]=\"previewBodyHtml(ch.name)\"\n ></div>\n </div>\n }\n </div>\n\n <!-- Footer: Action buttons (left) + Edit/Preview toggle (right) in single row -->\n <div\n class=\"flex flex-nowrap items-center justify-between gap-3 pt-3 mt-1 border-t border-gray-200 dark:border-gray-700\"\n >\n <div class=\"flex flex-nowrap items-center gap-2 min-w-0\">\n @if (viewMode() === 'edit') {\n <!-- ----- Insert variable dropdown from platform tokens ----- -->\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-variable'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (v of availableVariables(); track v.name) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(v.title || v.name) + ' ({{' + v.name + '}})'\"\n (onClick)=\"insertVariable(ch.name, v.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getVariableIcon(v)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n </ax-button>\n </div>\n <!--->\n <!-- ----- Insert reserved [content] slot for master templates ----- -->\n @if (isMasterKind()) {\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-content-slot'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n (onClick)=\"insertContentSlot(ch.name)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n }\n <!--->\n <!-- ----- Copy subject/body from another channel ----- -->\n @if (otherChannelsWithContent(ch.name).length > 0) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.copy-from'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-copy\"></ax-icon>\n </ax-prefix>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (\n src of otherChannelsWithContent(ch.name);\n track src.name\n ) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(src.title | translate | async) ?? src.name\"\n (onClick)=\"copyFromChannel(ch.name, src.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getChannelIcon(src)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n }\n </div>\n <div>\n <ax-tabs [look]=\"'default'\">\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.edit'\n | translate\n | async) ?? 'Edit'\n \"\n [active]=\"viewMode() === 'edit'\"\n (onClick)=\"viewMode.set('edit')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-pen\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.preview'\n | translate\n | async) ?? 'Preview'\n \"\n [active]=\"viewMode() === 'preview'\"\n (onClick)=\"viewMode.set('preview')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-eye\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n </ax-tabs>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i3.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "reorderable", "reorderDelay", "renderMode", "stacked", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged", "onTabsReordered"] }, { kind: "component", type: i3.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXTextAreaModule }, { kind: "component", type: i4.AXTextAreaComponent, selector: "ax-text-area", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "placeholder", "maxLength", "look", "rows", "allowResize", "showCounter", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i5.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "maskPattern", "customTokens", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onMaskChanged"] }, { kind: "ngmodule", type: AXWysiwygModule }, { kind: "component", type: i6.AXWysiwygContainerComponent, selector: "ax-wysiwyg-container", inputs: ["look", "readonly", "disabled", "value", "placeHolder", "initialLine"], outputs: ["onValueChanged"] }, { kind: "component", type: i6.AXWysiwygViewComponent, selector: "ax-wysiwyg-view" }, { kind: "component", type: i6.AXWysiwygFontStyleComponent, selector: "ax-wysiwyg-font-style" }, { kind: "component", type: i6.AXWysiwygHistoryComponent, selector: "ax-wysiwyg-history" }, { kind: "component", type: i6.AXWysiwygListComponent, selector: "ax-wysiwyg-list" }, { kind: "component", type: i6.AXWysiwygToolbarComponent, selector: "ax-wysiwyg-toolbar" }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i7.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i7.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i7.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i8.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i2$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
674
800
  }
675
801
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMTemplateContentEditorWidgetEditComponent, decorators: [{
676
802
  type: Component,
@@ -687,8 +813,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
687
813
  AXTranslationModule,
688
814
  AXButtonModule,
689
815
  AXDropdownModule,
690
- ], template: "<!-- Template Content Editor: Channel tabs and content per channel -->\n<div class=\"flex flex-col gap-4 w-full\">\n <!-- Channel tabs navigation -->\n <div class=\"flex items-center gap-2 flex-wrap\">\n <ax-tabs\n [look]=\"'with-line'\"\n (onActiveTabChanged)=\"activeTabIndex.set($event.index)\"\n class=\"flex-1 min-w-0\"\n >\n @for (ch of availableChannels(); track ch.name; let i = $index) {\n <ax-tab-item\n [text]=\"(ch.title | translate | async) ?? ch.name\"\n [key]=\"i.toString()\"\n [active]=\"activeTabIndex() === i\"\n ></ax-tab-item>\n }\n </ax-tabs>\n </div>\n\n @if (activeChannel(); as ch) {\n <!-- Channel content area: Edit mode or Preview mode -->\n <div class=\"mb-4 p-4\">\n @if (!isChannelConfigured(ch.name) && ch.notConfiguredMessageKey) {\n <div\n class=\"mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-3 rounded border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/30\"\n >\n <p class=\"text-sm text-amber-900 dark:text-amber-100\">\n {{ ch.notConfiguredMessageKey | translate | async }}\n </p>\n @if (ch.configureSettings) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.configure-channel'\n | translate\n | async\n \"\n look=\"outline\"\n color=\"primary\"\n size=\"sm\"\n (onClick)=\"openChannelConfigure(ch)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-gear\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </div>\n }\n\n @if (viewMode() === 'edit') {\n <!-- Edit mode: Subject field (for channels that support it, e.g. Email) -->\n @if (ch.hasSubject) {\n <div class=\"mb-3\">\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}\n </label>\n <ax-text-box\n [ngModel]=\"getChannelSubject(ch.name)\"\n (ngModelChange)=\"setChannelSubject(ch.name, $event)\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.subject.placeholder'\n | translate\n | async)!\n \"\n ></ax-text-box>\n </div>\n }\n\n <!-- Edit mode: Body field (plain text or rich WYSIWYG) -->\n <div>\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.body.title'\n | translate\n | async\n }}\n </label>\n @if (ch.type === 'plain') {\n <ax-text-area\n #bodyTextarea\n [ngModel]=\"getChannelBody(ch.name)\"\n (ngModelChange)=\"setChannelBody(ch.name, $event)\"\n [rows]=\"8\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.plain'\n | translate\n | async)!\n \"\n ></ax-text-area>\n } @else {\n <ax-wysiwyg-container\n #wysiwygRef\n [placeHolder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.rich'\n | translate\n | async)!\n \"\n [ngModel]=\"getChannelBody(ch.name)\"\n (onValueChanged)=\"handleWysiwygChange(ch.name, $event)\"\n [look]=\"'solid'\"\n >\n <ax-wysiwyg-view [style.min-height.px]=\"200\"></ax-wysiwyg-view>\n <ax-wysiwyg-toolbar>\n <ax-prefix>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n </ax-prefix>\n </ax-wysiwyg-toolbar>\n </ax-wysiwyg-container>\n }\n </div>\n } @else {\n <!-- Preview mode: Rendered content with variable placeholders replaced by sample values -->\n <div class=\"space-y-2\">\n @if (ch.hasSubject && previewSubject(ch.name)) {\n <div>\n <span class=\"text-xs text-gray-500\"\n >{{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}:\n </span>\n <span class=\"text-sm\">{{ previewSubject(ch.name) }}</span>\n </div>\n }\n <!-- ----- Rich email keeps inline styles; plain channels use pre-wrap ----- -->\n <div\n class=\"text-sm p-3 bg-gray-100 dark:bg-gray-900 rounded border overflow-auto\"\n [class.whitespace-pre-wrap]=\"ch.type !== 'rich'\"\n [innerHTML]=\"previewBodyHtml(ch.name)\"\n ></div>\n </div>\n }\n </div>\n\n <!-- Footer: Action buttons (left) + Edit/Preview toggle (right) in single row -->\n <div\n class=\"flex flex-nowrap items-center justify-between gap-3 pt-3 mt-1 border-t border-gray-200 dark:border-gray-700\"\n >\n <div class=\"flex flex-nowrap items-center gap-2 min-w-0\">\n @if (viewMode() === 'edit') {\n <!-- ----- Insert variable dropdown from platform tokens ----- -->\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-variable'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (v of availableVariables(); track v.name) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(v.title || v.name) + ' ({{' + v.name + '}})'\"\n (onClick)=\"insertVariable(ch.name, v.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getVariableIcon(v)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n </ax-button>\n </div>\n <!--->\n <!-- ----- Insert reserved [content] slot for master templates ----- -->\n @if (isMasterKind()) {\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-content-slot'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n (onClick)=\"insertContentSlot(ch.name)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n }\n <!--->\n <!-- ----- Copy subject/body from another channel ----- -->\n @if (otherChannelsWithContent(ch.name).length > 0) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.copy-from'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-copy\"></ax-icon>\n </ax-prefix>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (\n src of otherChannelsWithContent(ch.name);\n track src.name\n ) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(src.title | translate | async) ?? src.name\"\n (onClick)=\"copyFromChannel(ch.name, src.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getChannelIcon(src)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n }\n </div>\n <div>\n <ax-tabs [look]=\"'default'\">\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.edit'\n | translate\n | async) ?? 'Edit'\n \"\n [active]=\"viewMode() === 'edit'\"\n (onClick)=\"viewMode.set('edit')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-pen\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.preview'\n | translate\n | async) ?? 'Preview'\n \"\n [active]=\"viewMode() === 'preview'\"\n (onClick)=\"viewMode.set('preview')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-eye\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n </ax-tabs>\n </div>\n </div>\n }\n</div>\n" }]
816
+ ], template: "<!-- Template Content Editor: Channel tabs and content per channel -->\n<div class=\"flex flex-col gap-4 w-full\">\n <!-- Channel tabs navigation -->\n <div class=\"flex items-center gap-2 flex-wrap\">\n <ax-tabs\n [look]=\"'with-line'\"\n (onActiveTabChanged)=\"onChannelTabChanged($event.index)\"\n class=\"flex-1 min-w-0\"\n >\n @for (ch of availableChannels(); track ch.name; let i = $index) {\n <ax-tab-item\n [text]=\"(ch.title | translate | async) ?? ch.name\"\n [key]=\"i.toString()\"\n [active]=\"activeTabIndex() === i\"\n ></ax-tab-item>\n }\n </ax-tabs>\n </div>\n\n @if (activeChannel(); as ch) {\n <!-- Channel content area: Edit mode or Preview mode -->\n <div class=\"mb-4 p-4\">\n @if (!isChannelConfigured(ch.name) && ch.notConfiguredMessageKey) {\n <div\n class=\"mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-3 rounded border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/30\"\n >\n <p class=\"text-sm text-amber-900 dark:text-amber-100\">\n {{ ch.notConfiguredMessageKey | translate | async }}\n </p>\n @if (ch.configureSettings) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.configure-channel'\n | translate\n | async\n \"\n look=\"outline\"\n color=\"primary\"\n size=\"sm\"\n (onClick)=\"openChannelConfigure(ch)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-gear\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </div>\n }\n\n @if (viewMode() === 'edit') {\n <!-- Edit mode: Subject field (for channels that support it, e.g. Email) -->\n @if (ch.hasSubject) {\n <div class=\"mb-3\">\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}\n </label>\n <ax-text-box\n [ngModel]=\"getChannelSubject(ch.name)\"\n (onValueChanged)=\"handleSubjectChange(ch.name, $event)\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.subject.placeholder'\n | translate\n | async)!\n \"\n ></ax-text-box>\n </div>\n }\n\n <!-- Edit mode: Body field (plain text or rich WYSIWYG) -->\n <div>\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.body.title'\n | translate\n | async\n }}\n </label>\n <!--->\n <!-- ----- Plain-text body for SMS-style channels ----- -->\n @if (ch.type === 'plain') {\n <ax-text-area\n #bodyTextarea\n [ngModel]=\"getChannelBody(ch.name)\"\n (onValueChanged)=\"handlePlainBodyChange(ch.name, $event)\"\n [rows]=\"8\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.plain'\n | translate\n | async)!\n \"\n ></ax-text-area>\n }\n <!-- ----- Recreate Quill per channel so tab switches do not keep the previous HTML ----- -->\n @else {\n @for (channelName of [ch.name]; track channelName) {\n <ax-wysiwyg-container\n #wysiwygRef\n [placeHolder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.rich'\n | translate\n | async)!\n \"\n [ngModel]=\"getChannelBody(channelName)\"\n (onValueChanged)=\"handleWysiwygChange(channelName, $event)\"\n [look]=\"'solid'\"\n >\n <ax-wysiwyg-view [style.min-height.px]=\"200\"></ax-wysiwyg-view>\n <ax-wysiwyg-toolbar>\n <ax-prefix>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n </ax-prefix>\n </ax-wysiwyg-toolbar>\n </ax-wysiwyg-container>\n }\n }\n </div>\n } @else {\n <!-- Preview mode: Rendered content with variable placeholders replaced by sample values -->\n <div class=\"space-y-2\">\n @if (ch.hasSubject && previewSubject(ch.name)) {\n <div>\n <span class=\"text-xs text-gray-500\"\n >{{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}:\n </span>\n <span class=\"text-sm\">{{ previewSubject(ch.name) }}</span>\n </div>\n }\n <!-- ----- Rich email keeps inline styles; plain channels use pre-wrap ----- -->\n <div\n class=\"text-sm p-3 bg-gray-100 dark:bg-gray-900 rounded border overflow-auto\"\n [class.whitespace-pre-wrap]=\"ch.type !== 'rich'\"\n [innerHTML]=\"previewBodyHtml(ch.name)\"\n ></div>\n </div>\n }\n </div>\n\n <!-- Footer: Action buttons (left) + Edit/Preview toggle (right) in single row -->\n <div\n class=\"flex flex-nowrap items-center justify-between gap-3 pt-3 mt-1 border-t border-gray-200 dark:border-gray-700\"\n >\n <div class=\"flex flex-nowrap items-center gap-2 min-w-0\">\n @if (viewMode() === 'edit') {\n <!-- ----- Insert variable dropdown from platform tokens ----- -->\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-variable'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (v of availableVariables(); track v.name) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(v.title || v.name) + ' ({{' + v.name + '}})'\"\n (onClick)=\"insertVariable(ch.name, v.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getVariableIcon(v)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n </ax-button>\n </div>\n <!--->\n <!-- ----- Insert reserved [content] slot for master templates ----- -->\n @if (isMasterKind()) {\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-content-slot'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n (onClick)=\"insertContentSlot(ch.name)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n }\n <!--->\n <!-- ----- Copy subject/body from another channel ----- -->\n @if (otherChannelsWithContent(ch.name).length > 0) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.copy-from'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-copy\"></ax-icon>\n </ax-prefix>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (\n src of otherChannelsWithContent(ch.name);\n track src.name\n ) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(src.title | translate | async) ?? src.name\"\n (onClick)=\"copyFromChannel(ch.name, src.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getChannelIcon(src)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n }\n </div>\n <div>\n <ax-tabs [look]=\"'default'\">\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.edit'\n | translate\n | async) ?? 'Edit'\n \"\n [active]=\"viewMode() === 'edit'\"\n (onClick)=\"viewMode.set('edit')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-pen\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.preview'\n | translate\n | async) ?? 'Preview'\n \"\n [active]=\"viewMode() === 'preview'\"\n (onClick)=\"viewMode.set('preview')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-eye\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n </ax-tabs>\n </div>\n </div>\n }\n</div>\n" }]
691
817
  }], ctorParameters: () => [], propDecorators: { wysiwygRef: [{ type: i0.ViewChild, args: ['wysiwygRef', { isSignal: true }] }], bodyTextareaRef: [{ type: i0.ViewChild, args: ['bodyTextarea', { ...{ read: (ElementRef) }, isSignal: true }] }] } });
692
818
 
693
819
  export { AXMTemplateContentEditorWidgetEditComponent };
694
- //# sourceMappingURL=acorex-platform-module-content-management-client-template-content-editor-widget-edit.component-BZUn1TiT.mjs.map
820
+ //# sourceMappingURL=acorex-platform-module-content-management-client-template-content-editor-widget-edit.component-Cn-sIxBA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acorex-platform-module-content-management-client-template-content-editor-widget-edit.component-Cn-sIxBA.mjs","sources":["../../../../libs/modules/content-management/client/src/lib/features/template-content-editor/template-content-editor-widget-edit.component.ts","../../../../libs/modules/content-management/client/src/lib/features/template-content-editor/template-content-editor-widget-edit.component.html"],"sourcesContent":["import { AXButtonModule } from '@acorex/components/button';\nimport { AXDecoratorModule } from '@acorex/components/decorators';\nimport { AXDropdownModule } from '@acorex/components/dropdown';\nimport { AXFormModule } from '@acorex/components/form';\nimport { AXTabsModule } from '@acorex/components/tabs';\nimport { AXTextAreaModule } from '@acorex/components/text-area';\nimport { AXTextBoxModule } from '@acorex/components/text-box';\nimport { AXToastService } from '@acorex/components/toast';\nimport {\n AXWysiwygContainerComponent,\n AXWysiwygModule,\n} from '@acorex/components/wysiwyg';\nimport { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';\nimport { AXValidationModule } from '@acorex/core/validation';\nimport { AXPSettingsService, AXPTokenDefinitionService } from '@acorex-platform/framework-client/common';\nimport { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';\nimport { AXPValueWidgetComponent } from '@acorex-platform/framework-client/layout/widget-core';\nimport { AXPCommandExecutor } from '@acorex-platform/framework-client/runtime';\nimport { CommonModule } from '@angular/common';\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n effect,\n inject,\n OnInit,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { DomSanitizer, type SafeHtml } from '@angular/platform-browser';\nimport { FormsModule } from '@angular/forms';\nimport { AXValueChangedEvent } from '@acorex/cdk/common';\nimport {\n AXPContextState,\n AXPPlatformScope,\n isFormValueEqual,\n runtimeCommandPayloadData,\n type AXPMultiLanguageString,\n} from '@acorex-platform/framework-shared/core';\nimport {\n AXM_TEXT_TEMPLATE_PREVIEW_COMMAND_KEY,\n RootConfig,\n type AXMTextTemplatePreviewRequest,\n type AXMTextTemplatePreviewResult,\n} from '@acorex-platform/module-content-management-client/contracts';\nimport { AXP_TEXT_TEMPLATE_CHANNEL_DEFINITION_PROVIDER } from './channel-definition.provider';\nimport {\n AXMTextTemplateChannelDefinition,\n AXMTextTemplateChannelsValue,\n} from './channel-definition.types';\nimport {\n AXM_TEXT_TEMPLATE_CONTENT_SLOT,\n AXM_TEXT_TEMPLATE_KIND,\n AXM_TEXT_TEMPLATE_MAX_PARENT_DEPTH,\n collectTextTemplatePlaceholderNames,\n composeTextTemplateBodyChain,\n renderTextTemplateSource,\n replaceTextTemplatePlaceholders,\n resolveTextTemplateLocalizedString,\n type AXMTextTemplateEntityModel,\n} from './text-template-placeholder.util';\n\n/** Variable definition from PlatformManagement.Tokens for template preview and Insert variable */\ninterface TemplateVariable {\n name: string;\n title: string;\n sampleValue?: string;\n kind?: string;\n dataType?: string;\n}\n\n@Component({\n selector: 'axm-template-content-editor-widget-edit',\n templateUrl: './template-content-editor-widget-edit.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n CommonModule,\n AXDecoratorModule,\n FormsModule,\n AXFormModule,\n AXTabsModule,\n AXTextAreaModule,\n AXTextBoxModule,\n AXWysiwygModule,\n AXValidationModule,\n AXTranslationModule,\n AXButtonModule,\n AXDropdownModule,\n ],\n})\nexport class AXMTemplateContentEditorWidgetEditComponent\n extends AXPValueWidgetComponent<AXMTextTemplateChannelsValue | null>\n implements OnInit, AfterViewInit\n{\n /** Stored cursor/selection state before Insert Variable dropdown opens */\n private storedCursor: {\n channelName: string;\n isPlain: boolean;\n selectionStart?: number;\n selectionEnd?: number;\n range?: Range;\n } | null = null;\n private readonly channelProviders = inject(AXP_TEXT_TEMPLATE_CHANNEL_DEFINITION_PROVIDER, {\n optional: true,\n });\n private readonly settingsService = inject(AXPSettingsService);\n private readonly translationService = inject(AXTranslationService);\n private readonly entityService = inject(AXPEntityService);\n private readonly tokenDefinitionService = inject(AXPTokenDefinitionService, { optional: true });\n private readonly commandExecutor = inject(AXPCommandExecutor);\n private readonly toastService = inject(AXToastService);\n private readonly sanitizer = inject(DomSanitizer);\n private readonly destroyRef = inject(DestroyRef);\n private readonly hostRef = inject(ElementRef<HTMLElement>);\n\n /** Dedupes in-flight preview loads when effect re-runs. */\n private previewRequestSeq = 0;\n\n /**\n * Quill `text-change` is debounced (~300ms) and `commitValue(html, true)` marks\n * hydration as a user edit. Ignore writes until that timer elapses after a programmatic sync.\n */\n private suppressWysiwygWrites = false;\n private suppressWysiwygWritesTimer: ReturnType<typeof setTimeout> | null = null;\n\n private lastSyncedChannel: string | null = null;\n private lastSyncedViewMode: 'edit' | 'preview' | null = null;\n private lastSyncedWysiwyg: AXWysiwygContainerComponent | undefined;\n /** Drops the ax-tabs init event so it cannot overwrite the content-channel tab. */\n private ignoreNextChannelTabChange = false;\n\n protected wysiwygRef = viewChild<AXWysiwygContainerComponent>('wysiwygRef');\n protected bodyTextareaRef = viewChild('bodyTextarea', { read: ElementRef<HTMLElement> });\n\n protected availableChannels = signal<AXMTextTemplateChannelDefinition[]>([]);\n protected channelConfigured = signal<Record<string, boolean>>({});\n protected availableVariables = signal<TemplateVariable[]>([]);\n protected activeTabIndex = signal<number>(0);\n protected viewMode = signal<'edit' | 'preview'>('edit');\n\n /** Resolved values for local preview fallback: expression/token evaluation, then sampleValue */\n protected resolvedPreviewValues = signal<Record<string, string>>({});\n\n /** Parent-chain bodies (leaf → root) for the active locale, keyed by channel (local fallback). */\n protected composedPreviewBodies = signal<Record<string, string>>({});\n\n /** Server Preview results keyed by channel (preferred over local compose). */\n protected serverPreviewByChannel = signal<\n Record<string, { subject?: string; body: string }>\n >({});\n\n protected activeChannel = computed(() => {\n const idx = this.activeTabIndex();\n const chs = this.availableChannels();\n return chs[idx] ?? null;\n });\n\n /** True when the host entity form has Kind = Master. */\n protected isMasterKind = computed(() => {\n this.contextService.changeEvent();\n const kind = this.contextService.getValue('kind');\n return kind === AXM_TEXT_TEMPLATE_KIND.Master;\n });\n\n protected otherChannelsWithContent = (currentName: string) =>\n this.availableChannels().filter(\n (c) => c.name !== currentName && (this.getChannelBody(c.name) || (c.hasSubject && this.getChannelSubject(c.name)))\n );\n\n /** Returns icon class for a variable/token based on kind and dataType */\n protected getVariableIcon(v: TemplateVariable): string {\n const kindMap: Record<string, string> = {\n Static: 'fa-light fa-database',\n Context: 'fa-light fa-layer-group',\n Event: 'fa-light fa-bolt',\n Computed: 'fa-light fa-calculator',\n Secret: 'fa-light fa-key',\n };\n const dataTypeMap: Record<string, string> = {\n String: 'fa-light fa-font',\n Integer: 'fa-light fa-hashtag',\n Boolean: 'fa-light fa-toggle-on',\n Decimal: 'fa-light fa-calculator',\n DateTime: 'fa-light fa-clock',\n Json: 'fa-light fa-braces',\n };\n const byKind = v.kind && kindMap[v.kind];\n if (byKind) return byKind;\n const byDataType = v.dataType && dataTypeMap[v.dataType];\n if (byDataType) return byDataType;\n return 'fa-light fa-code';\n }\n\n /** Returns icon class for a channel based on name and type */\n protected getChannelIcon(ch: AXMTextTemplateChannelDefinition): string {\n const nameMap: Record<string, string> = {\n email: 'fa-light fa-envelope',\n sms: 'fa-light fa-comment-sms',\n whatsapp: 'fa-brands fa-whatsapp',\n push: 'fa-light fa-bell',\n telegram: 'fa-brands fa-telegram',\n 'in-app': 'fa-light fa-inbox',\n };\n const byName = nameMap[ch.name?.toLowerCase() ?? ''];\n if (byName) return byName;\n return ch.type === 'rich' ? 'fa-light fa-file-lines' : 'fa-light fa-align-left';\n }\n\n private getTemplateLocale(): string {\n return this.translationService.getActiveLang() ?? 'en-US';\n }\n\n /**\n * Builds a mutable locale map from a stored channel field (string legacy or ML object).\n */\n private normalizeChannelFieldToMl(\n existing: AXPMultiLanguageString | string | undefined,\n ): Record<string, string> {\n if (existing == null || existing === '') {\n return {};\n }\n if (typeof existing === 'string') {\n const s = existing;\n return { 'en-US': s, 'fa-IR': s };\n }\n return { ...(existing as Record<string, string>) };\n }\n\n constructor() {\n super();\n effect(() => {\n this.viewMode();\n this.activeTabIndex();\n this.getValue();\n this.contextService.changeEvent();\n if (this.viewMode() === 'preview') {\n void this.loadServerPreview();\n } else {\n this.previewRequestSeq += 1;\n this.resolvedPreviewValues.set({});\n this.composedPreviewBodies.set({});\n this.serverPreviewByChannel.set({});\n }\n });\n\n /**\n * Quill keeps its own DOM; one-way ngModel does not refresh it when the entity\n * loads, the user discards, or the active channel tab changes.\n */\n effect(() => {\n const viewMode = this.viewMode();\n const channel = this.activeChannel();\n const changeState = this.contextService.changeEvent().state;\n const body = channel ? this.getChannelBody(channel.name) : '';\n const editor = this.wysiwygRef();\n\n if (viewMode !== 'edit' || !channel || channel.type === 'plain' || !editor) {\n this.lastSyncedViewMode = viewMode;\n return;\n }\n\n const channelChanged = channel.name !== this.lastSyncedChannel;\n const viewModeChanged = viewMode !== this.lastSyncedViewMode;\n const editorChanged = editor !== this.lastSyncedWysiwyg;\n const contextReload = this.shouldSyncWysiwygFromContext(changeState);\n\n if (!channelChanged && !viewModeChanged && !editorChanged && !contextReload) {\n return;\n }\n\n untracked(() => {\n this.lastSyncedChannel = channel.name;\n this.lastSyncedViewMode = viewMode;\n this.lastSyncedWysiwyg = editor;\n void this.applyWysiwygContentWhenReady(editor, body);\n });\n });\n\n this.settingsService.onChanged.subscribe(() => {\n void this.refreshChannelConfiguration();\n });\n\n this.destroyRef.onDestroy(() => this.clearSuppressWysiwygWritesTimer());\n }\n\n protected isChannelConfigured(name: string): boolean {\n return this.channelConfigured()[name] ?? true;\n }\n\n protected async openChannelConfigure(channel: AXMTextTemplateChannelDefinition): Promise<void> {\n const configure = channel.configureSettings;\n if (!configure) {\n return;\n }\n\n const saved = await this.settingsService.showSectionPopup({\n scope: configure.scope,\n section: configure.section,\n group: configure.group,\n });\n if (saved) {\n await this.refreshChannelConfiguration();\n }\n }\n\n private async refreshChannelConfiguration(): Promise<void> {\n const channels = this.availableChannels();\n const next: Record<string, boolean> = {};\n for (const channel of channels) {\n next[channel.name] = await this.isChannelConfiguredInternal(channel);\n }\n this.channelConfigured.set(next);\n }\n\n private async isChannelConfiguredInternal(channel: AXMTextTemplateChannelDefinition): Promise<boolean> {\n const requiredKeys = channel.requiredSettingKeys ?? [];\n if (!requiredKeys.length) {\n return true;\n }\n const scopeKey = channel.configureSettings?.scope ?? 'T';\n const scoped = this.settingsService.scope(scopeKey as AXPPlatformScope);\n for (const key of requiredKeys) {\n const value = await scoped.get(key);\n if (!this.hasNonEmptySettingValue(value)) {\n return false;\n }\n }\n return true;\n }\n\n private hasNonEmptySettingValue(value: unknown): boolean {\n if (value == null) {\n return false;\n }\n if (typeof value === 'string') {\n return value.trim().length > 0;\n }\n if (typeof value === 'number') {\n return Number.isFinite(value);\n }\n if (typeof value === 'boolean') {\n return true;\n }\n if (typeof value === 'object' && 'value' in value) {\n return this.hasNonEmptySettingValue((value as { value?: unknown }).value);\n }\n return String(value).trim().length > 0;\n }\n\n ngAfterViewInit(): void {\n const el = this.hostRef.nativeElement;\n const handleMousedown = (e: MouseEvent) => {\n const target = e.target as Node;\n if (!target || !el.contains(target)) return;\n const trigger = (target as Element).closest?.('[data-insert-var-trigger]');\n if (!trigger) return;\n this.captureCursorBeforeInsert();\n };\n el.addEventListener('mousedown', handleMousedown, { capture: true });\n this.destroyRef.onDestroy(() =>\n el.removeEventListener('mousedown', handleMousedown, { capture: true })\n );\n }\n\n override async ngOnInit(): Promise<void> {\n super.ngOnInit();\n const rawCh = this.channelProviders;\n const chProviders = rawCh == null ? [] : Array.isArray(rawCh) ? rawCh : [rawCh];\n const allChannels: AXMTextTemplateChannelDefinition[] = [];\n for (const p of chProviders) {\n if (p?.getChannels) allChannels.push(...p.getChannels());\n }\n this.availableChannels.set(\n Array.from(new Map(allChannels.map((c) => [c.name, c])).values())\n );\n await this.refreshChannelConfiguration();\n\n try {\n const tokensAccessor = this.entityService.withEntity('PlatformManagement', 'Tokens').data();\n const result = await tokensAccessor.query({ skip: 0, take: 500 });\n const items = (result.items ?? []) as Array<{\n name?: string;\n title?: string;\n sampleValue?: string;\n kind?: string;\n dataType?: string;\n }>;\n const vars: TemplateVariable[] = items\n .map((t) => ({\n name: String(t.name ?? ''),\n title: String(t.title ?? t.name ?? ''),\n sampleValue: t.sampleValue != null ? String(t.sampleValue) : undefined,\n kind: t.kind,\n dataType: t.dataType,\n }))\n .filter((v) => v.name);\n this.availableVariables.set(Array.from(new Map(vars.map((v) => [v.name, v])).values()));\n } catch {\n this.availableVariables.set([]);\n }\n\n const value = this.getValue();\n if (value && typeof value === 'object' && Object.keys(value).length > 0) {\n const names = Object.keys(value);\n const chs = this.availableChannels();\n const idx = chs.findIndex((c) => names.includes(c.name));\n if (idx >= 0) {\n this.ignoreNextChannelTabChange = true;\n this.beginSuppressWysiwygWrites();\n this.activeTabIndex.set(idx);\n setTimeout(() => {\n this.ignoreNextChannelTabChange = false;\n });\n }\n }\n }\n\n protected onChannelTabChanged(index: number): void {\n if (this.ignoreNextChannelTabChange || index === this.activeTabIndex()) {\n return;\n }\n this.beginSuppressWysiwygWrites();\n this.activeTabIndex.set(index);\n }\n\n /** Capture cursor/selection before dropdown opens (runs in mousedown capture phase) */\n private captureCursorBeforeInsert(): void {\n const ch = this.activeChannel();\n if (!ch) return;\n this.storedCursor = null;\n const active = document.activeElement as HTMLElement | null;\n if (!active) return;\n if (ch.type === 'plain') {\n const textarea = this.getTextareaElement(active);\n if (textarea) {\n this.storedCursor = {\n channelName: ch.name,\n isPlain: true,\n selectionStart: textarea.selectionStart,\n selectionEnd: textarea.selectionEnd,\n };\n }\n } else {\n const editable = this.getContentEditableElement(active);\n if (editable) {\n const sel = document.getSelection();\n if (sel && sel.rangeCount > 0) {\n const range = sel.getRangeAt(0).cloneRange();\n this.storedCursor = {\n channelName: ch.name,\n isPlain: false,\n range,\n };\n }\n }\n }\n }\n\n private getTextareaElement(el: HTMLElement): HTMLTextAreaElement | null {\n if (el instanceof HTMLTextAreaElement) return el;\n return el.querySelector?.('textarea') ?? null;\n }\n\n private getContentEditableElement(el: HTMLElement): HTMLElement | null {\n if (el.isContentEditable) return el;\n return el.closest?.('[contenteditable=\"true\"]') ?? null;\n }\n\n protected insertVariable(channelName: string, varName: string): void {\n this.insertToken(channelName, `{{${varName}}}`);\n }\n\n protected insertContentSlot(channelName: string): void {\n this.insertToken(channelName, AXM_TEXT_TEMPLATE_CONTENT_SLOT);\n }\n\n private insertToken(channelName: string, token: string): void {\n const current = this.getChannelBody(channelName);\n const stored = this.storedCursor;\n this.storedCursor = null;\n\n if (stored && stored.channelName === channelName) {\n if (stored.isPlain) {\n const start = stored.selectionStart ?? current.length;\n const end = stored.selectionEnd ?? start;\n const before = current.slice(0, start);\n const after = current.slice(end);\n const newBody = before + token + after;\n this.setChannelBody(channelName, newBody);\n const newCursor = start + token.length;\n queueMicrotask(() => this.restoreTextareaCursor(newCursor));\n } else if (stored.range) {\n try {\n const startNode = stored.range.startContainer;\n const elem = startNode.nodeType === Node.TEXT_NODE\n ? (startNode as Text).parentElement\n : (startNode as Element);\n const editable = elem?.closest?.('[contenteditable=\"true\"]') as HTMLElement | null;\n const wysiwyg = this.wysiwygRef();\n const target = editable ?? wysiwyg?.getHostElement()?.querySelector?.('[contenteditable=\"true\"]');\n if (target) {\n (target as HTMLElement).focus();\n const sel = document.getSelection();\n if (sel) {\n sel.removeAllRanges();\n sel.addRange(stored.range);\n document.execCommand('insertText', false, token);\n }\n } else {\n this.setChannelBody(channelName, current + token);\n }\n } catch {\n this.setChannelBody(channelName, current + token);\n }\n }\n } else {\n this.setChannelBody(channelName, current + token);\n }\n }\n\n private restoreTextareaCursor(position: number): void {\n const ref = this.bodyTextareaRef();\n const el = ref?.nativeElement;\n const textarea = el?.querySelector?.('textarea') ?? (el instanceof HTMLTextAreaElement ? el : null);\n if (textarea) {\n textarea.focus();\n textarea.setSelectionRange(position, position);\n }\n }\n\n protected copyFromChannel(targetName: string, sourceName: string): void {\n const ch = this.availableChannels().find((c) => c.name === sourceName);\n if (!ch) return;\n const hasSubject = ch.hasSubject;\n if (hasSubject) {\n this.setChannelSubject(targetName, this.getChannelSubject(sourceName));\n }\n this.setChannelBody(targetName, this.getChannelBody(sourceName));\n const active = this.activeChannel();\n if (active?.name === targetName && active.type === 'rich') {\n void this.applyWysiwygContentWhenReady(this.wysiwygRef(), this.getChannelBody(targetName));\n }\n }\n\n protected getChannelSubject(name: string): string {\n const v = this.getValue()?.[name];\n const raw =\n v && typeof v === 'object' && 'subject' in v ? (v as { subject?: AXPMultiLanguageString }).subject : undefined;\n return resolveTextTemplateLocalizedString(raw, this.getTemplateLocale());\n }\n\n protected handleSubjectChange(name: string, e: AXValueChangedEvent<string>): void {\n if (!e.isUserInteraction) {\n return;\n }\n this.setChannelSubject(name, e.value ?? '');\n }\n\n protected setChannelSubject(name: string, value: string): void {\n const nextText = value ?? '';\n if (this.getChannelSubject(name) === nextText) {\n return;\n }\n const current = this.getValue() || {};\n if (!current[name] && !nextText.trim()) {\n return;\n }\n const ch = current[name] || { body: '' };\n const locale = this.getTemplateLocale();\n const ml = this.normalizeChannelFieldToMl(ch.subject);\n ml[locale] = nextText;\n this.commitChannelValue(current, name, { ...ch, subject: ml });\n }\n\n protected getChannelBody(name: string): string {\n const v = this.getValue()?.[name];\n const raw =\n v && typeof v === 'object' && 'body' in v ? (v as { body?: AXPMultiLanguageString }).body : undefined;\n return resolveTextTemplateLocalizedString(raw, this.getTemplateLocale());\n }\n\n protected handlePlainBodyChange(name: string, e: AXValueChangedEvent<string>): void {\n if (!e.isUserInteraction) {\n return;\n }\n this.setChannelBody(name, e.value ?? '');\n }\n\n protected handleWysiwygChange(name: string, e: AXValueChangedEvent<string>): void {\n if (this.suppressWysiwygWrites || !e.isUserInteraction) {\n return;\n }\n const val =\n typeof e === 'object' && e !== null && 'value' in e\n ? ((e as { value: string | null }).value ?? '')\n : String(e ?? '');\n this.setChannelBody(name, val);\n }\n\n protected setChannelBody(name: string, value: string): void {\n const nextText = value ?? '';\n if (this.getChannelBody(name) === nextText) {\n return;\n }\n const current = this.getValue() || {};\n if (!current[name] && !nextText.trim()) {\n return;\n }\n const ch = current[name] || { body: '' };\n const locale = this.getTemplateLocale();\n const ml = this.normalizeChannelFieldToMl(ch.body);\n ml[locale] = nextText;\n this.commitChannelValue(current, name, { ...ch, body: ml });\n }\n\n private commitChannelValue(\n current: AXMTextTemplateChannelsValue,\n name: string,\n nextChannel: AXMTextTemplateChannelsValue[string],\n ): void {\n const nextValue = { ...current, [name]: nextChannel };\n if (isFormValueEqual(nextValue, current)) {\n return;\n }\n const path = this.fullPath();\n const saved = path ? this.contextService.getSavedValue(path) : undefined;\n if (saved !== undefined && isFormValueEqual(nextValue, saved)) {\n return;\n }\n this.setValue(nextValue);\n }\n\n private shouldSyncWysiwygFromContext(state: AXPContextState): boolean {\n return state === 'restored' || state === 'initiated';\n }\n\n private beginSuppressWysiwygWrites(): void {\n this.suppressWysiwygWrites = true;\n this.clearSuppressWysiwygWritesTimer();\n this.suppressWysiwygWritesTimer = setTimeout(() => {\n this.suppressWysiwygWrites = false;\n this.suppressWysiwygWritesTimer = null;\n }, 500);\n }\n\n private clearSuppressWysiwygWritesTimer(): void {\n if (this.suppressWysiwygWritesTimer) {\n clearTimeout(this.suppressWysiwygWritesTimer);\n this.suppressWysiwygWritesTimer = null;\n }\n }\n\n private async applyWysiwygContentWhenReady(\n wysiwyg: AXWysiwygContainerComponent | undefined,\n text: string,\n ): Promise<void> {\n const content = text ?? '';\n\n for (let attempt = 0; attempt < 30; attempt++) {\n const editor = this.wysiwygRef() ?? wysiwyg;\n if (!editor) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n continue;\n }\n\n try {\n this.beginSuppressWysiwygWrites();\n editor.setWysiwygContent(content);\n return;\n } catch {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n }\n }\n\n /**\n * Prefer server draft Preview (Context tokens + Event samples + parent composition).\n * Falls back to local compose when the command fails.\n */\n private async loadServerPreview(): Promise<void> {\n const requestSeq = ++this.previewRequestSeq;\n const value = this.getValue();\n const channel = this.activeChannel()?.name?.trim() || '';\n if (!value || typeof value !== 'object' || !channel) {\n this.serverPreviewByChannel.set({});\n this.composedPreviewBodies.set({});\n return;\n }\n\n const locale = this.getTemplateLocale();\n const parentIdRaw = this.contextService.getValue('parentId');\n const parentId = typeof parentIdRaw === 'string' ? parentIdRaw.trim() : '';\n const kindRaw = this.contextService.getValue('kind');\n const kind = typeof kindRaw === 'string' ? kindRaw.trim() : undefined;\n\n const request: AXMTextTemplatePreviewRequest = {\n channels: value,\n channel,\n locale,\n ...(parentId ? { parentId } : {}),\n ...(kind ? { kind } : {}),\n };\n\n try {\n const result = await this.commandExecutor.execute<\n AXMTextTemplatePreviewRequest,\n AXMTextTemplatePreviewResult\n >(AXM_TEXT_TEMPLATE_PREVIEW_COMMAND_KEY, request);\n\n if (requestSeq !== this.previewRequestSeq) {\n return;\n }\n\n const preview = runtimeCommandPayloadData(result);\n if (preview?.body != null) {\n this.serverPreviewByChannel.update((prev) => ({\n ...prev,\n [channel]: {\n ...(preview.subject != null ? { subject: preview.subject } : {}),\n body: preview.body,\n },\n }));\n return;\n }\n\n const message =\n typeof result?.message?.text === 'string' && result.message.text.trim()\n ? result.message.text.trim()\n : undefined;\n await this.fallbackToLocalPreview(channel, message);\n } catch (error) {\n if (requestSeq !== this.previewRequestSeq) {\n return;\n }\n const message = error instanceof Error ? error.message : undefined;\n await this.fallbackToLocalPreview(channel, message);\n }\n }\n\n private async fallbackToLocalPreview(channel: string, errorMessage?: string): Promise<void> {\n const title = await this.translationService.translateAsync(\n '@content-management:templates.messages.preview-failed.title',\n );\n const content = await this.translationService.translateAsync(\n '@content-management:templates.messages.preview-failed.content',\n );\n this.toastService.show({\n color: 'warning',\n title,\n content: errorMessage ? `${content} ${errorMessage}` : content,\n closeButton: true,\n timeOut: 5000,\n });\n\n this.serverPreviewByChannel.update((prev) => {\n const next = { ...prev };\n delete next[channel];\n return next;\n });\n await this.resolveComposedPreviewBodies();\n }\n\n /** Resolve variable values for local preview fallback */\n private async resolvePreviewVariables(): Promise<void> {\n const value = this.getValue();\n if (!value || typeof value !== 'object') return;\n const locale = this.getTemplateLocale();\n const parts: string[] = [];\n for (const v of Object.values(value)) {\n if (v != null && typeof v === 'object' && 'body' in v) {\n const o = v as { subject?: AXPMultiLanguageString; body?: AXPMultiLanguageString };\n parts.push(resolveTextTemplateLocalizedString(o.subject, locale));\n parts.push(resolveTextTemplateLocalizedString(o.body, locale));\n }\n }\n for (const body of Object.values(this.composedPreviewBodies())) {\n parts.push(body);\n }\n const allText = parts.join('');\n const varNames = collectTextTemplatePlaceholderNames(allText);\n if (varNames.length === 0) return;\n const vars = this.availableVariables();\n const resolved: Record<string, string> = {};\n const svc = this.tokenDefinitionService;\n for (const name of varNames) {\n try {\n if (svc) {\n const val = await svc.getValue(name);\n resolved[name] = val != null ? String(val) : '';\n }\n } catch {\n /* use fallback */\n }\n if (!(name in resolved) || !resolved[name]) {\n const v = vars.find((x) => x.name === name);\n if (v?.sampleValue != null) {\n resolved[name] = v.sampleValue;\n } else if (!(name in resolved)) {\n resolved[name] = '';\n }\n }\n }\n this.resolvedPreviewValues.update((prev) => ({ ...prev, ...resolved }));\n }\n\n /**\n * Local fallback: loads optional parent masters and stores leaf→root body chains per channel.\n */\n private async resolveComposedPreviewBodies(): Promise<void> {\n const value = this.getValue();\n if (!value || typeof value !== 'object') {\n this.composedPreviewBodies.set({});\n return;\n }\n\n const parentIdRaw = this.contextService.getValue('parentId');\n const parentId = typeof parentIdRaw === 'string' ? parentIdRaw.trim() : '';\n const locale = this.getTemplateLocale();\n const next: Record<string, string> = {};\n\n if (!parentId) {\n for (const channelName of Object.keys(value)) {\n next[channelName] = this.getChannelBody(channelName);\n }\n this.composedPreviewBodies.set(next);\n await this.resolvePreviewVariables();\n return;\n }\n\n const parentBodiesByChannel: Record<string, string[]> = {};\n try {\n const accessor = this.entityService\n .withEntity(RootConfig.module.name, RootConfig.entities.textTemplate.name)\n .data<\n string,\n AXMTextTemplateEntityModel,\n AXMTextTemplateEntityModel,\n AXMTextTemplateEntityModel,\n AXMTextTemplateEntityModel\n >();\n\n const visited = new Set<string>();\n const selfIdRaw = this.contextService.getValue('id');\n const selfId = typeof selfIdRaw === 'string' ? selfIdRaw.trim() : '';\n if (selfId) {\n visited.add(selfId);\n }\n\n let currentId: string | null = parentId;\n let depth = 1;\n while (currentId && depth <= AXM_TEXT_TEMPLATE_MAX_PARENT_DEPTH) {\n if (visited.has(currentId)) {\n break;\n }\n visited.add(currentId);\n const parent = await accessor.byKey(currentId);\n if (!parent?.channels) {\n break;\n }\n for (const [channelName, channelDef] of Object.entries(parent.channels)) {\n const body = resolveTextTemplateLocalizedString(channelDef?.body, locale);\n if (!body) continue;\n (parentBodiesByChannel[channelName] ??= []).push(body);\n }\n currentId = parent.parentId?.trim() || null;\n depth += 1;\n }\n } catch {\n /* keep leaf-only preview */\n }\n\n for (const channelName of Object.keys(value)) {\n const leafBody = this.getChannelBody(channelName);\n const parents = parentBodiesByChannel[channelName] ?? [];\n next[channelName] = composeTextTemplateBodyChain([leafBody, ...parents]);\n }\n this.composedPreviewBodies.set(next);\n await this.resolvePreviewVariables();\n }\n\n /** Get preview value for variable: expression/token first, then sampleValue */\n private getPreviewValue(varName: string): string {\n const resolved = this.resolvedPreviewValues()[varName];\n if (resolved !== undefined && resolved !== '') return resolved;\n const v = this.availableVariables().find((x) => x.name === varName);\n return v?.sampleValue ?? `{{${varName}}}`;\n }\n\n /**\n * Merge map for interpolating `{{ path }}` in `text`.\n * When `escapeMergeValuesForHtml` is true, substitution values are escaped for safe `innerHTML` fragments.\n */\n private previewMergeFor(text: string, escapeMergeValuesForHtml: boolean): Record<string, string> {\n const out: Record<string, string> = {};\n for (const name of collectTextTemplatePlaceholderNames(text)) {\n let v = this.getPreviewValue(name);\n if (escapeMergeValuesForHtml) {\n v = v.replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n out[name] = v;\n }\n return out;\n }\n\n protected previewSubject(channelName: string): string {\n const server = this.serverPreviewByChannel()[channelName];\n if (server?.subject != null) {\n return server.subject;\n }\n return this.previewText(this.getChannelSubject(channelName));\n }\n\n protected previewText(text: string): string {\n return replaceTextTemplatePlaceholders(text, this.previewMergeFor(text, false));\n }\n\n /**\n * Email/rich preview must bypass Angular's default innerHTML sanitizer;\n * otherwise inline `style` (colors, gradients, header bar) is stripped and\n * the preview diverges from the real sent email.\n */\n protected previewBodyHtml(channelName: string): SafeHtml | string {\n const ch = this.availableChannels().find((c) => c.name === channelName);\n const server = this.serverPreviewByChannel()[channelName];\n if (server?.body != null) {\n if (ch?.type === 'rich') {\n return this.sanitizer.bypassSecurityTrustHtml(server.body);\n }\n return server.body\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\\n/g, '<br/>');\n }\n\n const composed = this.composedPreviewBodies()[channelName];\n const body = composed ?? this.getChannelBody(channelName);\n // Local fallback: do not escape data for rich HTML (logo mark / styled shells).\n const merged = renderTextTemplateSource(\n body,\n this.previewMergeFor(body, ch?.type !== 'rich'),\n );\n if (ch?.type === 'rich') {\n return this.sanitizer.bypassSecurityTrustHtml(merged);\n }\n return merged\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\\n/g, '<br/>');\n }\n}\n","<!-- Template Content Editor: Channel tabs and content per channel -->\n<div class=\"flex flex-col gap-4 w-full\">\n <!-- Channel tabs navigation -->\n <div class=\"flex items-center gap-2 flex-wrap\">\n <ax-tabs\n [look]=\"'with-line'\"\n (onActiveTabChanged)=\"onChannelTabChanged($event.index)\"\n class=\"flex-1 min-w-0\"\n >\n @for (ch of availableChannels(); track ch.name; let i = $index) {\n <ax-tab-item\n [text]=\"(ch.title | translate | async) ?? ch.name\"\n [key]=\"i.toString()\"\n [active]=\"activeTabIndex() === i\"\n ></ax-tab-item>\n }\n </ax-tabs>\n </div>\n\n @if (activeChannel(); as ch) {\n <!-- Channel content area: Edit mode or Preview mode -->\n <div class=\"mb-4 p-4\">\n @if (!isChannelConfigured(ch.name) && ch.notConfiguredMessageKey) {\n <div\n class=\"mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-3 rounded border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/30\"\n >\n <p class=\"text-sm text-amber-900 dark:text-amber-100\">\n {{ ch.notConfiguredMessageKey | translate | async }}\n </p>\n @if (ch.configureSettings) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.configure-channel'\n | translate\n | async\n \"\n look=\"outline\"\n color=\"primary\"\n size=\"sm\"\n (onClick)=\"openChannelConfigure(ch)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-gear\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </div>\n }\n\n @if (viewMode() === 'edit') {\n <!-- Edit mode: Subject field (for channels that support it, e.g. Email) -->\n @if (ch.hasSubject) {\n <div class=\"mb-3\">\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}\n </label>\n <ax-text-box\n [ngModel]=\"getChannelSubject(ch.name)\"\n (onValueChanged)=\"handleSubjectChange(ch.name, $event)\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.subject.placeholder'\n | translate\n | async)!\n \"\n ></ax-text-box>\n </div>\n }\n\n <!-- Edit mode: Body field (plain text or rich WYSIWYG) -->\n <div>\n <label class=\"block text-sm mb-1\">\n {{\n '@content-management:templates.entities.text-template.fields.body.title'\n | translate\n | async\n }}\n </label>\n <!--->\n <!-- ----- Plain-text body for SMS-style channels ----- -->\n @if (ch.type === 'plain') {\n <ax-text-area\n #bodyTextarea\n [ngModel]=\"getChannelBody(ch.name)\"\n (onValueChanged)=\"handlePlainBodyChange(ch.name, $event)\"\n [rows]=\"8\"\n [placeholder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.plain'\n | translate\n | async)!\n \"\n ></ax-text-area>\n }\n <!-- ----- Recreate Quill per channel so tab switches do not keep the previous HTML ----- -->\n @else {\n @for (channelName of [ch.name]; track channelName) {\n <ax-wysiwyg-container\n #wysiwygRef\n [placeHolder]=\"\n ('@content-management:templates.entities.text-template.fields.body-placeholder.rich'\n | translate\n | async)!\n \"\n [ngModel]=\"getChannelBody(channelName)\"\n (onValueChanged)=\"handleWysiwygChange(channelName, $event)\"\n [look]=\"'solid'\"\n >\n <ax-wysiwyg-view [style.min-height.px]=\"200\"></ax-wysiwyg-view>\n <ax-wysiwyg-toolbar>\n <ax-prefix>\n <ax-wysiwyg-history></ax-wysiwyg-history>\n <ax-wysiwyg-font-style></ax-wysiwyg-font-style>\n <ax-wysiwyg-list></ax-wysiwyg-list>\n </ax-prefix>\n </ax-wysiwyg-toolbar>\n </ax-wysiwyg-container>\n }\n }\n </div>\n } @else {\n <!-- Preview mode: Rendered content with variable placeholders replaced by sample values -->\n <div class=\"space-y-2\">\n @if (ch.hasSubject && previewSubject(ch.name)) {\n <div>\n <span class=\"text-xs text-gray-500\"\n >{{\n '@content-management:templates.entities.text-template.fields.subject.title'\n | translate\n | async\n }}:\n </span>\n <span class=\"text-sm\">{{ previewSubject(ch.name) }}</span>\n </div>\n }\n <!-- ----- Rich email keeps inline styles; plain channels use pre-wrap ----- -->\n <div\n class=\"text-sm p-3 bg-gray-100 dark:bg-gray-900 rounded border overflow-auto\"\n [class.whitespace-pre-wrap]=\"ch.type !== 'rich'\"\n [innerHTML]=\"previewBodyHtml(ch.name)\"\n ></div>\n </div>\n }\n </div>\n\n <!-- Footer: Action buttons (left) + Edit/Preview toggle (right) in single row -->\n <div\n class=\"flex flex-nowrap items-center justify-between gap-3 pt-3 mt-1 border-t border-gray-200 dark:border-gray-700\"\n >\n <div class=\"flex flex-nowrap items-center gap-2 min-w-0\">\n @if (viewMode() === 'edit') {\n <!-- ----- Insert variable dropdown from platform tokens ----- -->\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-variable'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n </ax-prefix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (v of availableVariables(); track v.name) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(v.title || v.name) + ' ({{' + v.name + '}})'\"\n (onClick)=\"insertVariable(ch.name, v.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getVariableIcon(v)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n </ax-button>\n </div>\n <!--->\n <!-- ----- Insert reserved [content] slot for master templates ----- -->\n @if (isMasterKind()) {\n <div data-insert-var-trigger>\n <ax-button\n [text]=\"\n '@content-management:templates.actions.insert-content-slot'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n (onClick)=\"insertContentSlot(ch.name)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n }\n <!--->\n <!-- ----- Copy subject/body from another channel ----- -->\n @if (otherChannelsWithContent(ch.name).length > 0) {\n <ax-button\n [text]=\"\n '@content-management:templates.actions.copy-from'\n | translate\n | async\n \"\n look=\"twotone\"\n color=\"default\"\n size=\"sm\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-copy\"></ax-icon>\n </ax-prefix>\n <ax-suffix>\n <ax-icon icon=\"fa-light fa-chevron-down\"></ax-icon>\n </ax-suffix>\n <ax-dropdown-panel>\n <ax-button-item-list>\n @for (\n src of otherChannelsWithContent(ch.name);\n track src.name\n ) {\n <ax-button-item\n look=\"blank\"\n color=\"default\"\n [text]=\"(src.title | translate | async) ?? src.name\"\n (onClick)=\"copyFromChannel(ch.name, src.name)\"\n >\n <ax-prefix>\n <ax-icon [icon]=\"getChannelIcon(src)\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n }\n </div>\n <div>\n <ax-tabs [look]=\"'default'\">\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.edit'\n | translate\n | async) ?? 'Edit'\n \"\n [active]=\"viewMode() === 'edit'\"\n (onClick)=\"viewMode.set('edit')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-pen\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n <ax-tab-item\n [text]=\"\n ('@content-management:templates.actions.preview'\n | translate\n | async) ?? 'Preview'\n \"\n [active]=\"viewMode() === 'preview'\"\n (onClick)=\"viewMode.set('preview')\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-eye\" class=\"text-current\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n </ax-tabs>\n </div>\n </div>\n }\n</div>\n"],"names":["i9","i10"],"mappings":"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"}