@smartbit4all/ng-client 7.3.13 → 7.3.15
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.
|
@@ -7290,46 +7290,32 @@ class SmartFormService {
|
|
|
7290
7290
|
}
|
|
7291
7291
|
getValueDeeply(model, key) {
|
|
7292
7292
|
let splittedKey = key.split('.');
|
|
7293
|
-
let value;
|
|
7294
|
-
splittedKey.
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
else {
|
|
7299
|
-
if (value[k] === undefined ||
|
|
7300
|
-
value[k] === null ||
|
|
7301
|
-
(!value && typeof value[k] !== 'boolean')) {
|
|
7302
|
-
value = '';
|
|
7303
|
-
return value;
|
|
7304
|
-
}
|
|
7305
|
-
else {
|
|
7306
|
-
value = value[k];
|
|
7307
|
-
}
|
|
7293
|
+
let value = model[splittedKey[0]];
|
|
7294
|
+
for (const k of splittedKey.slice(1)) {
|
|
7295
|
+
// A null or non-object parent has no field: the key binds nothing.
|
|
7296
|
+
if (value === null || typeof value !== 'object') {
|
|
7297
|
+
return undefined;
|
|
7308
7298
|
}
|
|
7309
|
-
|
|
7299
|
+
value = value[k] ?? '';
|
|
7300
|
+
}
|
|
7310
7301
|
return value;
|
|
7311
7302
|
}
|
|
7312
7303
|
setValueDeeply(model, key, value) {
|
|
7313
7304
|
let splittedKeys = key.split('.');
|
|
7314
|
-
|
|
7315
|
-
let tempModel;
|
|
7316
|
-
for (
|
|
7317
|
-
tempModel =
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
tempModel[splittedKeys[index]] !== undefined) {
|
|
7322
|
-
deepModel.push(tempModel[splittedKeys[index]]);
|
|
7323
|
-
}
|
|
7324
|
-
if (index === splittedKeys.length - 1) {
|
|
7325
|
-
let oldValue = tempModel[splittedKeys[index]];
|
|
7326
|
-
// if (value === '' && (oldValue === null || oldValue === undefined) then don't change value.
|
|
7327
|
-
if (value !== '' || (oldValue !== null && oldValue !== undefined)) {
|
|
7328
|
-
tempModel[splittedKeys[index]] = value;
|
|
7329
|
-
}
|
|
7330
|
-
break;
|
|
7305
|
+
const leafKey = splittedKeys.pop();
|
|
7306
|
+
let tempModel = model;
|
|
7307
|
+
for (const k of splittedKeys) {
|
|
7308
|
+
tempModel = tempModel[k];
|
|
7309
|
+
// A null or non-object parent has no field to write: the write is dropped.
|
|
7310
|
+
if (tempModel === null || typeof tempModel !== 'object') {
|
|
7311
|
+
return;
|
|
7331
7312
|
}
|
|
7332
7313
|
}
|
|
7314
|
+
let oldValue = tempModel[leafKey];
|
|
7315
|
+
// if (value === '' && (oldValue === null || oldValue === undefined) then don't change value.
|
|
7316
|
+
if (value !== '' || (oldValue !== null && oldValue !== undefined)) {
|
|
7317
|
+
tempModel[leafKey] = value;
|
|
7318
|
+
}
|
|
7333
7319
|
}
|
|
7334
7320
|
getPropertyNamesDeeply(element) {
|
|
7335
7321
|
let properties = Object.keys(element);
|
|
@@ -11487,36 +11473,316 @@ function resolveViewHandler(viewHandlers, defaultComponents, view) {
|
|
|
11487
11473
|
* Public API Surface of smart-view-context
|
|
11488
11474
|
*/
|
|
11489
11475
|
|
|
11476
|
+
/** Input types that take no text, so a key pressed on them is free for a keybinding. */
|
|
11477
|
+
const NON_TEXT_INPUT_TYPES = new Set([
|
|
11478
|
+
'button',
|
|
11479
|
+
'checkbox',
|
|
11480
|
+
'radio',
|
|
11481
|
+
'submit',
|
|
11482
|
+
'reset',
|
|
11483
|
+
'file',
|
|
11484
|
+
'range',
|
|
11485
|
+
'color',
|
|
11486
|
+
]);
|
|
11487
|
+
/**
|
|
11488
|
+
* Whether the element takes typed text: a text-like input, a textarea, a select or anything
|
|
11489
|
+
* contenteditable. Keys pressed there belong to the element first (ADR-0012).
|
|
11490
|
+
*/
|
|
11491
|
+
function isEditableTarget(element) {
|
|
11492
|
+
if (element instanceof HTMLInputElement) {
|
|
11493
|
+
return !NON_TEXT_INPUT_TYPES.has(element.type);
|
|
11494
|
+
}
|
|
11495
|
+
return (element instanceof HTMLTextAreaElement ||
|
|
11496
|
+
element instanceof HTMLSelectElement ||
|
|
11497
|
+
(element instanceof HTMLElement && element.isContentEditable));
|
|
11498
|
+
}
|
|
11499
|
+
/** The controls the browser activates on `Enter` or `Space`, natively or by their ARIA role. */
|
|
11500
|
+
const ACTIVATABLE_SELECTOR = [
|
|
11501
|
+
'button',
|
|
11502
|
+
'a[href]',
|
|
11503
|
+
'summary',
|
|
11504
|
+
...[
|
|
11505
|
+
'button',
|
|
11506
|
+
'link',
|
|
11507
|
+
'menuitem',
|
|
11508
|
+
'menuitemcheckbox',
|
|
11509
|
+
'menuitemradio',
|
|
11510
|
+
'option',
|
|
11511
|
+
'switch',
|
|
11512
|
+
'tab',
|
|
11513
|
+
'checkbox',
|
|
11514
|
+
'radio',
|
|
11515
|
+
'treeitem',
|
|
11516
|
+
].map((role) => `[role="${role}"]`),
|
|
11517
|
+
].join(', ');
|
|
11518
|
+
/**
|
|
11519
|
+
* Whether the element is, or sits in, a control that `Enter` or `Space` activates: a button, a
|
|
11520
|
+
* link, a summary, a clickable input or an ARIA-interactive role. The browser activates it after
|
|
11521
|
+
* the keydown, so a binding firing on that key would steal the click (ADR-0012).
|
|
11522
|
+
*/
|
|
11523
|
+
function isActivatableTarget(element) {
|
|
11524
|
+
if (element instanceof HTMLInputElement) {
|
|
11525
|
+
return NON_TEXT_INPUT_TYPES.has(element.type);
|
|
11526
|
+
}
|
|
11527
|
+
return element?.closest(ACTIVATABLE_SELECTOR) != null;
|
|
11528
|
+
}
|
|
11529
|
+
|
|
11530
|
+
/** The keys that edit the text of an editable element or move in it, unmodified. */
|
|
11531
|
+
const TEXT_KEYS = new Set([
|
|
11532
|
+
'Backspace',
|
|
11533
|
+
'Delete',
|
|
11534
|
+
'ArrowUp',
|
|
11535
|
+
'ArrowDown',
|
|
11536
|
+
'ArrowLeft',
|
|
11537
|
+
'ArrowRight',
|
|
11538
|
+
'Home',
|
|
11539
|
+
'End',
|
|
11540
|
+
'PageUp',
|
|
11541
|
+
'PageDown',
|
|
11542
|
+
'Tab',
|
|
11543
|
+
]);
|
|
11544
|
+
/**
|
|
11545
|
+
* Turns key presses into the actions the views bind them to (ADR-0012). One document listener
|
|
11546
|
+
* serves every view: the key goes to the innermost view holding the focus and bubbles to the
|
|
11547
|
+
* enclosing views until a binding fires. When nothing has the focus, it goes to the view that had
|
|
11548
|
+
* it last (a pushed layout re-renders the focused field, and the focus falls to the body), else
|
|
11549
|
+
* the top-most dialog, else the current page; while a dialog is open, the view that had the focus
|
|
11550
|
+
* last counts only if it is in the dialog. A dialog sits in the overlay container, outside the DOM
|
|
11551
|
+
* of the views below it, so the key never leaves a dialog.
|
|
11552
|
+
*/
|
|
11553
|
+
class SmartKeybindingService {
|
|
11554
|
+
constructor() {
|
|
11555
|
+
this.document = inject(DOCUMENT);
|
|
11556
|
+
this.injector = inject(Injector);
|
|
11557
|
+
this.isMac = isMacPlatform();
|
|
11558
|
+
this.hosts = new Map();
|
|
11559
|
+
/** The elements of no view whose keys go to a view: a dialog's header to the page it shows. */
|
|
11560
|
+
this.forwards = new Map();
|
|
11561
|
+
const listener = (event) => this.onKeydown(event);
|
|
11562
|
+
const focusListener = (event) => this.onFocusin(event);
|
|
11563
|
+
this.document.addEventListener('keydown', listener);
|
|
11564
|
+
this.document.addEventListener('focusin', focusListener);
|
|
11565
|
+
inject(DestroyRef).onDestroy(() => {
|
|
11566
|
+
this.document.removeEventListener('keydown', listener);
|
|
11567
|
+
this.document.removeEventListener('focusin', focusListener);
|
|
11568
|
+
});
|
|
11569
|
+
}
|
|
11570
|
+
/** Lets the view take keys; returns the function that stops it. */
|
|
11571
|
+
register(entry) {
|
|
11572
|
+
this.hosts.set(entry.host, entry);
|
|
11573
|
+
return () => {
|
|
11574
|
+
if (this.hosts.get(entry.host) === entry) {
|
|
11575
|
+
this.hosts.delete(entry.host);
|
|
11576
|
+
}
|
|
11577
|
+
if (this.lastActive === entry) {
|
|
11578
|
+
this.lastActive = undefined;
|
|
11579
|
+
}
|
|
11580
|
+
};
|
|
11581
|
+
}
|
|
11582
|
+
/**
|
|
11583
|
+
* Sends the keys pressed with the focus in `from`, an element outside every view (the header
|
|
11584
|
+
* of a dialog), to the view whose host is `to`; returns the function that stops it.
|
|
11585
|
+
*/
|
|
11586
|
+
forwardKeys(from, to) {
|
|
11587
|
+
this.forwards.set(from, to);
|
|
11588
|
+
return () => {
|
|
11589
|
+
if (this.forwards.get(from) === to) {
|
|
11590
|
+
this.forwards.delete(from);
|
|
11591
|
+
}
|
|
11592
|
+
};
|
|
11593
|
+
}
|
|
11594
|
+
onFocusin(event) {
|
|
11595
|
+
// The focus in an overlay of no view (a select or menu panel) keeps the view it came from.
|
|
11596
|
+
const view = this.closestView(event.target instanceof Element ? event.target : null);
|
|
11597
|
+
if (view) {
|
|
11598
|
+
this.lastActive = view;
|
|
11599
|
+
}
|
|
11600
|
+
}
|
|
11601
|
+
onKeydown(event) {
|
|
11602
|
+
// The Enter of an IME composition confirms the composed text; it is no command. A keydown
|
|
11603
|
+
// without a key (the browser's autofill fires one) is no key press either.
|
|
11604
|
+
if (event.repeat || event.defaultPrevented || event.isComposing || !event.key) {
|
|
11605
|
+
return;
|
|
11606
|
+
}
|
|
11607
|
+
const target = event.target instanceof Element ? event.target : null;
|
|
11608
|
+
if (isEditableTarget(target) && editsText(event, target)) {
|
|
11609
|
+
return;
|
|
11610
|
+
}
|
|
11611
|
+
if (isActivatableTarget(target) && activates(event)) {
|
|
11612
|
+
return;
|
|
11613
|
+
}
|
|
11614
|
+
for (let view = this.startView(); view; view = this.closestView(view.host.parentElement)) {
|
|
11615
|
+
const binding = view.bindings().find((b) => matches(b.chord, event, this.isMac));
|
|
11616
|
+
if (binding && view.fire(binding.uiActionCode, binding.uiActionIdentifier)) {
|
|
11617
|
+
event.preventDefault();
|
|
11618
|
+
event.stopPropagation();
|
|
11619
|
+
return;
|
|
11620
|
+
}
|
|
11621
|
+
}
|
|
11622
|
+
}
|
|
11623
|
+
startView() {
|
|
11624
|
+
const active = this.document.activeElement;
|
|
11625
|
+
if (active &&
|
|
11626
|
+
active !== this.document.body &&
|
|
11627
|
+
active !== this.document.documentElement &&
|
|
11628
|
+
this.document.contains(active)) {
|
|
11629
|
+
// An element in an overlay of no view (an open select or menu panel) finds none.
|
|
11630
|
+
const view = this.closestView(active) ?? this.forwardedView(active);
|
|
11631
|
+
if (view) {
|
|
11632
|
+
this.lastActive = view;
|
|
11633
|
+
}
|
|
11634
|
+
return view;
|
|
11635
|
+
}
|
|
11636
|
+
// Injected late: the view context is not needed before the first key, and resolving it at
|
|
11637
|
+
// startup would construct it ahead of the bootstrap.
|
|
11638
|
+
const viewContext = this.injector.get(SmartViewContextService);
|
|
11639
|
+
const last = this.lastActive && this.isOnScreen(this.lastActive) ? this.lastActive : undefined;
|
|
11640
|
+
const dialogUuid = viewContext.topDialogUuid();
|
|
11641
|
+
if (dialogUuid !== undefined) {
|
|
11642
|
+
// A view nested in the dialog keeps the key; the page behind the dialog does not get it.
|
|
11643
|
+
const dialog = this.viewOf(dialogUuid);
|
|
11644
|
+
return last && dialog?.host.contains(last.host) ? last : dialog;
|
|
11645
|
+
}
|
|
11646
|
+
return last ?? this.viewOf(viewContext.activePageUuid());
|
|
11647
|
+
}
|
|
11648
|
+
isOnScreen(view) {
|
|
11649
|
+
return this.hosts.get(view.host) === view && this.document.contains(view.host);
|
|
11650
|
+
}
|
|
11651
|
+
viewOf(uuid) {
|
|
11652
|
+
return [...this.hosts.values()].find((view) => view.uuid === uuid);
|
|
11653
|
+
}
|
|
11654
|
+
forwardedView(element) {
|
|
11655
|
+
for (const [from, to] of this.forwards) {
|
|
11656
|
+
if (from.contains(element)) {
|
|
11657
|
+
return this.hosts.get(to);
|
|
11658
|
+
}
|
|
11659
|
+
}
|
|
11660
|
+
return undefined;
|
|
11661
|
+
}
|
|
11662
|
+
closestView(element) {
|
|
11663
|
+
for (let node = element; node; node = node.parentElement) {
|
|
11664
|
+
const view = this.hosts.get(node);
|
|
11665
|
+
if (view) {
|
|
11666
|
+
return view;
|
|
11667
|
+
}
|
|
11668
|
+
}
|
|
11669
|
+
return undefined;
|
|
11670
|
+
}
|
|
11671
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartKeybindingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
11672
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartKeybindingService, providedIn: 'root' }); }
|
|
11673
|
+
}
|
|
11674
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartKeybindingService, decorators: [{
|
|
11675
|
+
type: Injectable,
|
|
11676
|
+
args: [{ providedIn: 'root' }]
|
|
11677
|
+
}], ctorParameters: () => [] });
|
|
11678
|
+
/**
|
|
11679
|
+
* Whether the key, pressed in an editable element, edits or moves in its text. `Escape`, the
|
|
11680
|
+
* function keys and `Enter` in a single-line input do not, so they reach the bindings.
|
|
11681
|
+
*/
|
|
11682
|
+
function editsText(event, target) {
|
|
11683
|
+
if (event.ctrlKey || event.altKey || event.metaKey) {
|
|
11684
|
+
return false;
|
|
11685
|
+
}
|
|
11686
|
+
if (event.key.length === 1 || TEXT_KEYS.has(event.key)) {
|
|
11687
|
+
return true;
|
|
11688
|
+
}
|
|
11689
|
+
return (event.key === 'Enter' &&
|
|
11690
|
+
(target instanceof HTMLTextAreaElement ||
|
|
11691
|
+
(target instanceof HTMLElement && target.isContentEditable)));
|
|
11692
|
+
}
|
|
11693
|
+
/**
|
|
11694
|
+
* Whether the key activates a focused button, link or ARIA control: an unmodified `Enter` or
|
|
11695
|
+
* `Space` (Shift alone counts as unmodified). The browser clicks the control after the keydown,
|
|
11696
|
+
* so the key stays with it.
|
|
11697
|
+
*/
|
|
11698
|
+
function activates(event) {
|
|
11699
|
+
const modified = event.ctrlKey || event.altKey || event.metaKey;
|
|
11700
|
+
return !modified && (event.key === 'Enter' || event.key === ' ');
|
|
11701
|
+
}
|
|
11702
|
+
|
|
11703
|
+
/** The hardcoded toolbar ids (UiAction.toolbar) a child's action can target. */
|
|
11704
|
+
const TOOLBAR_DIALOG_HEADER = "toolbarDialogHeader";
|
|
11705
|
+
const TOOLBAR_DIALOG_FOOTER = "toolbarDialogFooter";
|
|
11706
|
+
/** The one place that knows where the client keeps its current window descriptor. Adjust to your model. */
|
|
11707
|
+
function windowDescriptorOf(client) {
|
|
11708
|
+
return client?.modelState?.()?.windowDescriptor;
|
|
11709
|
+
}
|
|
11710
|
+
/** The shape the toolbar was always given: { descriptor, uiAction }. */
|
|
11711
|
+
function toModel(action) {
|
|
11712
|
+
return { descriptor: action.descriptor, uiAction: action };
|
|
11713
|
+
}
|
|
11490
11714
|
class SmartContainerDialog {
|
|
11491
11715
|
constructor() {
|
|
11716
|
+
this.TOOLBAR_DIALOG_HEADER = TOOLBAR_DIALOG_HEADER;
|
|
11717
|
+
this.TOOLBAR_DIALOG_FOOTER = TOOLBAR_DIALOG_FOOTER;
|
|
11492
11718
|
this.data = inject(MAT_DIALOG_DATA);
|
|
11493
|
-
|
|
11719
|
+
this.keybindings = inject(SmartKeybindingService);
|
|
11720
|
+
this.destroyRef = inject(DestroyRef);
|
|
11721
|
+
/** The client of the rendered page: the executor of the toolbar actions. */
|
|
11494
11722
|
this.executor = signal(undefined, /* @ts-ignore */
|
|
11495
11723
|
...(ngDevMode ? [{ debugName: "executor" }] : /* istanbul ignore next */ []));
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11724
|
+
/** The current window descriptor: starts from the dialog data, then follows the client. */
|
|
11725
|
+
this.descriptor = signal(this.data.descriptor, /* @ts-ignore */
|
|
11726
|
+
...(ngDevMode ? [{ debugName: "descriptor" }] : /* istanbul ignore next */ []));
|
|
11727
|
+
this.title = computed(() => this.descriptor()?.title ?? "", /* @ts-ignore */
|
|
11728
|
+
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
11729
|
+
this.childActions = computed(() => {
|
|
11730
|
+
const models = this.executor()?.actionModels?.() ?? [];
|
|
11731
|
+
const actions = models.map((m) => m.uiAction).filter((a) => !!a);
|
|
11732
|
+
return actions;
|
|
11733
|
+
}, /* @ts-ignore */
|
|
11734
|
+
...(ngDevMode ? [{ debugName: "childActions" }] : /* istanbul ignore next */ []));
|
|
11735
|
+
this.headerModels = computed(() => {
|
|
11736
|
+
const result = this.childActions()
|
|
11737
|
+
.filter((a) => a.toolbar === TOOLBAR_DIALOG_HEADER)
|
|
11738
|
+
.map(toModel);
|
|
11739
|
+
return result;
|
|
11740
|
+
}, /* @ts-ignore */
|
|
11741
|
+
...(ngDevMode ? [{ debugName: "headerModels" }] : /* istanbul ignore next */ []));
|
|
11742
|
+
this.footerModels = computed(() => {
|
|
11743
|
+
const result = this.childActions()
|
|
11744
|
+
.filter((a) => a.toolbar === TOOLBAR_DIALOG_FOOTER)
|
|
11745
|
+
.map(toModel);
|
|
11746
|
+
return result;
|
|
11747
|
+
}, /* @ts-ignore */
|
|
11748
|
+
...(ngDevMode ? [{ debugName: "footerModels" }] : /* istanbul ignore next */ []));
|
|
11505
11749
|
}
|
|
11506
11750
|
ngAfterViewInit() {
|
|
11507
11751
|
const ref = this.vcRef.createComponent(this.data.component);
|
|
11508
|
-
|
|
11752
|
+
const client = ref.injector.get(SmartComponentHost, null)?.client;
|
|
11753
|
+
if (client) {
|
|
11754
|
+
// The header is outside the page's element, so its keys would reach no view.
|
|
11755
|
+
this.destroyRef.onDestroy(this.keybindings.forwardKeys(this.header.nativeElement, ref.location.nativeElement));
|
|
11756
|
+
// The window descriptor (title) can change with the page's data.
|
|
11757
|
+
client.dataChanged
|
|
11758
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
11759
|
+
.subscribe(() => this.refreshDescriptor(client));
|
|
11760
|
+
}
|
|
11761
|
+
this.executor.set(client);
|
|
11509
11762
|
ref.changeDetectorRef.detectChanges();
|
|
11763
|
+
if (client) {
|
|
11764
|
+
this.refreshDescriptor(client);
|
|
11765
|
+
}
|
|
11766
|
+
}
|
|
11767
|
+
refreshDescriptor(client) {
|
|
11768
|
+
const next = windowDescriptorOf(client);
|
|
11769
|
+
// Keep the descriptor from the dialog data until the client has one of its own.
|
|
11770
|
+
if (next && next !== this.descriptor()) {
|
|
11771
|
+
this.descriptor.set(next);
|
|
11772
|
+
}
|
|
11510
11773
|
}
|
|
11511
11774
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartContainerDialog, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11512
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartContainerDialog, isStandalone: true, selector: "smart-container-dialog", viewQueries: [{ propertyName: "vcRef", first: true, predicate: ["renderComponentHere"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div class=\"dialog-container\">\r\n <div class=\"dialog-header\">\r\n <h1 class=\"dialog-title\">{{ title }}</h1>\r\n\r\n @if (
|
|
11775
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartContainerDialog, isStandalone: true, selector: "smart-container-dialog", viewQueries: [{ propertyName: "vcRef", first: true, predicate: ["renderComponentHere"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "header", first: true, predicate: ["header"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"dialog-container\">\r\n <div class=\"dialog-header\" #header>\r\n <h1 class=\"dialog-title\">{{ title() }}</h1>\r\n\r\n @if (headerModels().length && executor()) {\r\n <smart-ui-action-toolbar\r\n class=\"dialog-header-toolbar\"\r\n [id]=\"TOOLBAR_DIALOG_HEADER\"\r\n [uiActionModels]=\"headerModels()\"\r\n [executor]=\"executor()\"\r\n ></smart-ui-action-toolbar>\r\n }\r\n </div>\r\n\r\n <mat-dialog-content class=\"dialog-content\">\r\n <ng-template #renderComponentHere></ng-template>\r\n </mat-dialog-content>\r\n\r\n @if (footerModels().length && executor()) {\r\n <div class=\"dialog-footer\">\r\n <smart-ui-action-toolbar\r\n class=\"dialog-footer-toolbar\"\r\n [id]=\"TOOLBAR_DIALOG_FOOTER\"\r\n [uiActionModels]=\"footerModels()\"\r\n [executor]=\"executor()\"\r\n ></smart-ui-action-toolbar>\r\n </div>\r\n }\r\n</div>", styles: [".dialog-container{display:flex;flex-direction:column;--sb4-dialog-default-padding: .5rem;--sb4-dialog-default-max-height: 80vh;--mat-dialog-content-padding: var(--sb4-dialog-default-padding)}.dialog-header{display:flex;align-items:center;gap:var(--sb4-dialog-default-padding);padding:var(--sb4-dialog-default-padding)}.mat-mdc-dialog-content{max-height:var(--sb4-dialog-default-max-height)}.dialog-title{flex:1;margin:0}.dialog-header-toolbar ::ng-deep button{min-width:unset}.dialog-footer{padding:var(--sb4-dialog-default-padding)}\n"], dependencies: [{ kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }] }); }
|
|
11513
11776
|
}
|
|
11514
11777
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartContainerDialog, decorators: [{
|
|
11515
11778
|
type: Component,
|
|
11516
|
-
args: [{ selector: "smart-container-dialog", imports: [MatDialogContent, UiActionToolbarComponent], template: "<div class=\"dialog-container\">\r\n <div class=\"dialog-header\">\r\n <h1 class=\"dialog-title\">{{ title }}</h1>\r\n\r\n @if (
|
|
11779
|
+
args: [{ selector: "smart-container-dialog", imports: [MatDialogContent, UiActionToolbarComponent], template: "<div class=\"dialog-container\">\r\n <div class=\"dialog-header\" #header>\r\n <h1 class=\"dialog-title\">{{ title() }}</h1>\r\n\r\n @if (headerModels().length && executor()) {\r\n <smart-ui-action-toolbar\r\n class=\"dialog-header-toolbar\"\r\n [id]=\"TOOLBAR_DIALOG_HEADER\"\r\n [uiActionModels]=\"headerModels()\"\r\n [executor]=\"executor()\"\r\n ></smart-ui-action-toolbar>\r\n }\r\n </div>\r\n\r\n <mat-dialog-content class=\"dialog-content\">\r\n <ng-template #renderComponentHere></ng-template>\r\n </mat-dialog-content>\r\n\r\n @if (footerModels().length && executor()) {\r\n <div class=\"dialog-footer\">\r\n <smart-ui-action-toolbar\r\n class=\"dialog-footer-toolbar\"\r\n [id]=\"TOOLBAR_DIALOG_FOOTER\"\r\n [uiActionModels]=\"footerModels()\"\r\n [executor]=\"executor()\"\r\n ></smart-ui-action-toolbar>\r\n </div>\r\n }\r\n</div>", styles: [".dialog-container{display:flex;flex-direction:column;--sb4-dialog-default-padding: .5rem;--sb4-dialog-default-max-height: 80vh;--mat-dialog-content-padding: var(--sb4-dialog-default-padding)}.dialog-header{display:flex;align-items:center;gap:var(--sb4-dialog-default-padding);padding:var(--sb4-dialog-default-padding)}.mat-mdc-dialog-content{max-height:var(--sb4-dialog-default-max-height)}.dialog-title{flex:1;margin:0}.dialog-header-toolbar ::ng-deep button{min-width:unset}.dialog-footer{padding:var(--sb4-dialog-default-padding)}\n"] }]
|
|
11517
11780
|
}], propDecorators: { vcRef: [{
|
|
11518
11781
|
type: ViewChild,
|
|
11519
11782
|
args: ["renderComponentHere", { read: ViewContainerRef, static: true }]
|
|
11783
|
+
}], header: [{
|
|
11784
|
+
type: ViewChild,
|
|
11785
|
+
args: ["header", { static: true }]
|
|
11520
11786
|
}] } });
|
|
11521
11787
|
|
|
11522
11788
|
class SmartViewContextDialogService {
|
|
@@ -11543,12 +11809,12 @@ class SmartViewContextDialogService {
|
|
|
11543
11809
|
return dialogRef;
|
|
11544
11810
|
}
|
|
11545
11811
|
openComponentAsDialog(component, viewName, uuid, dialogDescriptor) {
|
|
11546
|
-
return this.openContainerDialog(component, viewName, dialogDescriptor);
|
|
11812
|
+
return this.openContainerDialog(component, viewName, dialogDescriptor, undefined, uuid);
|
|
11547
11813
|
}
|
|
11548
|
-
openContainerDialog(component, viewName, dialogDescriptor, config) {
|
|
11814
|
+
openContainerDialog(component, viewName, dialogDescriptor, config, uuid) {
|
|
11549
11815
|
return this.dialog.open(SmartContainerDialog, {
|
|
11550
11816
|
...config,
|
|
11551
|
-
data: { component, descriptor: dialogDescriptor, viewName },
|
|
11817
|
+
data: { component, descriptor: dialogDescriptor, viewName, uuid },
|
|
11552
11818
|
closeOnNavigation: false,
|
|
11553
11819
|
});
|
|
11554
11820
|
}
|
|
@@ -11622,60 +11888,6 @@ function findExchangeSlots(ops) {
|
|
|
11622
11888
|
return new Set([...opening].filter((key) => closing.has(key)));
|
|
11623
11889
|
}
|
|
11624
11890
|
|
|
11625
|
-
/** Input types that take no text, so a key pressed on them is free for a keybinding. */
|
|
11626
|
-
const NON_TEXT_INPUT_TYPES = new Set([
|
|
11627
|
-
'button',
|
|
11628
|
-
'checkbox',
|
|
11629
|
-
'radio',
|
|
11630
|
-
'submit',
|
|
11631
|
-
'reset',
|
|
11632
|
-
'file',
|
|
11633
|
-
'range',
|
|
11634
|
-
'color',
|
|
11635
|
-
]);
|
|
11636
|
-
/**
|
|
11637
|
-
* Whether the element takes typed text: a text-like input, a textarea, a select or anything
|
|
11638
|
-
* contenteditable. Keys pressed there belong to the element first (ADR-0012).
|
|
11639
|
-
*/
|
|
11640
|
-
function isEditableTarget(element) {
|
|
11641
|
-
if (element instanceof HTMLInputElement) {
|
|
11642
|
-
return !NON_TEXT_INPUT_TYPES.has(element.type);
|
|
11643
|
-
}
|
|
11644
|
-
return (element instanceof HTMLTextAreaElement ||
|
|
11645
|
-
element instanceof HTMLSelectElement ||
|
|
11646
|
-
(element instanceof HTMLElement && element.isContentEditable));
|
|
11647
|
-
}
|
|
11648
|
-
/** The controls the browser activates on `Enter` or `Space`, natively or by their ARIA role. */
|
|
11649
|
-
const ACTIVATABLE_SELECTOR = [
|
|
11650
|
-
'button',
|
|
11651
|
-
'a[href]',
|
|
11652
|
-
'summary',
|
|
11653
|
-
...[
|
|
11654
|
-
'button',
|
|
11655
|
-
'link',
|
|
11656
|
-
'menuitem',
|
|
11657
|
-
'menuitemcheckbox',
|
|
11658
|
-
'menuitemradio',
|
|
11659
|
-
'option',
|
|
11660
|
-
'switch',
|
|
11661
|
-
'tab',
|
|
11662
|
-
'checkbox',
|
|
11663
|
-
'radio',
|
|
11664
|
-
'treeitem',
|
|
11665
|
-
].map((role) => `[role="${role}"]`),
|
|
11666
|
-
].join(', ');
|
|
11667
|
-
/**
|
|
11668
|
-
* Whether the element is, or sits in, a control that `Enter` or `Space` activates: a button, a
|
|
11669
|
-
* link, a summary, a clickable input or an ARIA-interactive role. The browser activates it after
|
|
11670
|
-
* the keydown, so a binding firing on that key would steal the click (ADR-0012).
|
|
11671
|
-
*/
|
|
11672
|
-
function isActivatableTarget(element) {
|
|
11673
|
-
if (element instanceof HTMLInputElement) {
|
|
11674
|
-
return NON_TEXT_INPUT_TYPES.has(element.type);
|
|
11675
|
-
}
|
|
11676
|
-
return element?.closest(ACTIVATABLE_SELECTOR) != null;
|
|
11677
|
-
}
|
|
11678
|
-
|
|
11679
11891
|
const DefaultUiActionCode_CLOSE = "DEFAULT_CLOSE";
|
|
11680
11892
|
const DIALOG_DISABLE_CLOSE = new InjectionToken("dialogDisableClose");
|
|
11681
11893
|
/** How long the old component of an exchanged slot waits for the model of the new view. */
|
|
@@ -15568,156 +15780,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
15568
15780
|
type: Injectable
|
|
15569
15781
|
}] });
|
|
15570
15782
|
|
|
15571
|
-
/** The keys that edit the text of an editable element or move in it, unmodified. */
|
|
15572
|
-
const TEXT_KEYS = new Set([
|
|
15573
|
-
'Backspace',
|
|
15574
|
-
'Delete',
|
|
15575
|
-
'ArrowUp',
|
|
15576
|
-
'ArrowDown',
|
|
15577
|
-
'ArrowLeft',
|
|
15578
|
-
'ArrowRight',
|
|
15579
|
-
'Home',
|
|
15580
|
-
'End',
|
|
15581
|
-
'PageUp',
|
|
15582
|
-
'PageDown',
|
|
15583
|
-
'Tab',
|
|
15584
|
-
]);
|
|
15585
|
-
/**
|
|
15586
|
-
* Turns key presses into the actions the views bind them to (ADR-0012). One document listener
|
|
15587
|
-
* serves every view: the key goes to the innermost view holding the focus and bubbles to the
|
|
15588
|
-
* enclosing views until a binding fires. When nothing has the focus, it goes to the view that had
|
|
15589
|
-
* it last (a pushed layout re-renders the focused field, and the focus falls to the body), else
|
|
15590
|
-
* the top-most dialog, else the current page; while a dialog is open, the view that had the focus
|
|
15591
|
-
* last counts only if it is in the dialog. A dialog sits in the overlay container, outside the DOM
|
|
15592
|
-
* of the views below it, so the key never leaves a dialog.
|
|
15593
|
-
*/
|
|
15594
|
-
class SmartKeybindingService {
|
|
15595
|
-
constructor() {
|
|
15596
|
-
this.document = inject(DOCUMENT);
|
|
15597
|
-
this.injector = inject(Injector);
|
|
15598
|
-
this.isMac = isMacPlatform();
|
|
15599
|
-
this.hosts = new Map();
|
|
15600
|
-
const listener = (event) => this.onKeydown(event);
|
|
15601
|
-
const focusListener = (event) => this.onFocusin(event);
|
|
15602
|
-
this.document.addEventListener('keydown', listener);
|
|
15603
|
-
this.document.addEventListener('focusin', focusListener);
|
|
15604
|
-
inject(DestroyRef).onDestroy(() => {
|
|
15605
|
-
this.document.removeEventListener('keydown', listener);
|
|
15606
|
-
this.document.removeEventListener('focusin', focusListener);
|
|
15607
|
-
});
|
|
15608
|
-
}
|
|
15609
|
-
/** Lets the view take keys; returns the function that stops it. */
|
|
15610
|
-
register(entry) {
|
|
15611
|
-
this.hosts.set(entry.host, entry);
|
|
15612
|
-
return () => {
|
|
15613
|
-
if (this.hosts.get(entry.host) === entry) {
|
|
15614
|
-
this.hosts.delete(entry.host);
|
|
15615
|
-
}
|
|
15616
|
-
if (this.lastActive === entry) {
|
|
15617
|
-
this.lastActive = undefined;
|
|
15618
|
-
}
|
|
15619
|
-
};
|
|
15620
|
-
}
|
|
15621
|
-
onFocusin(event) {
|
|
15622
|
-
// The focus in an overlay of no view (a select or menu panel) keeps the view it came from.
|
|
15623
|
-
const view = this.closestView(event.target instanceof Element ? event.target : null);
|
|
15624
|
-
if (view) {
|
|
15625
|
-
this.lastActive = view;
|
|
15626
|
-
}
|
|
15627
|
-
}
|
|
15628
|
-
onKeydown(event) {
|
|
15629
|
-
// The Enter of an IME composition confirms the composed text; it is no command.
|
|
15630
|
-
if (event.repeat || event.defaultPrevented || event.isComposing) {
|
|
15631
|
-
return;
|
|
15632
|
-
}
|
|
15633
|
-
const target = event.target instanceof Element ? event.target : null;
|
|
15634
|
-
if (isEditableTarget(target) && editsText(event, target)) {
|
|
15635
|
-
return;
|
|
15636
|
-
}
|
|
15637
|
-
if (isActivatableTarget(target) && activates(event)) {
|
|
15638
|
-
return;
|
|
15639
|
-
}
|
|
15640
|
-
for (let view = this.startView(); view; view = this.closestView(view.host.parentElement)) {
|
|
15641
|
-
const binding = view.bindings().find((b) => matches(b.chord, event, this.isMac));
|
|
15642
|
-
if (binding && view.fire(binding.uiActionCode, binding.uiActionIdentifier)) {
|
|
15643
|
-
event.preventDefault();
|
|
15644
|
-
event.stopPropagation();
|
|
15645
|
-
return;
|
|
15646
|
-
}
|
|
15647
|
-
}
|
|
15648
|
-
}
|
|
15649
|
-
startView() {
|
|
15650
|
-
const active = this.document.activeElement;
|
|
15651
|
-
if (active &&
|
|
15652
|
-
active !== this.document.body &&
|
|
15653
|
-
active !== this.document.documentElement &&
|
|
15654
|
-
this.document.contains(active)) {
|
|
15655
|
-
// An element in an overlay of no view (an open select or menu panel) finds none.
|
|
15656
|
-
const view = this.closestView(active);
|
|
15657
|
-
if (view) {
|
|
15658
|
-
this.lastActive = view;
|
|
15659
|
-
}
|
|
15660
|
-
return view;
|
|
15661
|
-
}
|
|
15662
|
-
// Injected late: the view context is not needed before the first key, and resolving it at
|
|
15663
|
-
// startup would construct it ahead of the bootstrap.
|
|
15664
|
-
const viewContext = this.injector.get(SmartViewContextService);
|
|
15665
|
-
const last = this.lastActive && this.isOnScreen(this.lastActive) ? this.lastActive : undefined;
|
|
15666
|
-
const dialogUuid = viewContext.topDialogUuid();
|
|
15667
|
-
if (dialogUuid !== undefined) {
|
|
15668
|
-
// A view nested in the dialog keeps the key; the page behind the dialog does not get it.
|
|
15669
|
-
const dialog = this.viewOf(dialogUuid);
|
|
15670
|
-
return last && dialog?.host.contains(last.host) ? last : dialog;
|
|
15671
|
-
}
|
|
15672
|
-
return last ?? this.viewOf(viewContext.activePageUuid());
|
|
15673
|
-
}
|
|
15674
|
-
isOnScreen(view) {
|
|
15675
|
-
return this.hosts.get(view.host) === view && this.document.contains(view.host);
|
|
15676
|
-
}
|
|
15677
|
-
viewOf(uuid) {
|
|
15678
|
-
return [...this.hosts.values()].find((view) => view.uuid === uuid);
|
|
15679
|
-
}
|
|
15680
|
-
closestView(element) {
|
|
15681
|
-
for (let node = element; node; node = node.parentElement) {
|
|
15682
|
-
const view = this.hosts.get(node);
|
|
15683
|
-
if (view) {
|
|
15684
|
-
return view;
|
|
15685
|
-
}
|
|
15686
|
-
}
|
|
15687
|
-
return undefined;
|
|
15688
|
-
}
|
|
15689
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartKeybindingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
15690
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartKeybindingService, providedIn: 'root' }); }
|
|
15691
|
-
}
|
|
15692
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartKeybindingService, decorators: [{
|
|
15693
|
-
type: Injectable,
|
|
15694
|
-
args: [{ providedIn: 'root' }]
|
|
15695
|
-
}], ctorParameters: () => [] });
|
|
15696
|
-
/**
|
|
15697
|
-
* Whether the key, pressed in an editable element, edits or moves in its text. `Escape`, the
|
|
15698
|
-
* function keys and `Enter` in a single-line input do not, so they reach the bindings.
|
|
15699
|
-
*/
|
|
15700
|
-
function editsText(event, target) {
|
|
15701
|
-
if (event.ctrlKey || event.altKey || event.metaKey) {
|
|
15702
|
-
return false;
|
|
15703
|
-
}
|
|
15704
|
-
if (event.key.length === 1 || TEXT_KEYS.has(event.key)) {
|
|
15705
|
-
return true;
|
|
15706
|
-
}
|
|
15707
|
-
return (event.key === 'Enter' &&
|
|
15708
|
-
(target instanceof HTMLTextAreaElement ||
|
|
15709
|
-
(target instanceof HTMLElement && target.isContentEditable)));
|
|
15710
|
-
}
|
|
15711
|
-
/**
|
|
15712
|
-
* Whether the key activates a focused button, link or ARIA control: an unmodified `Enter` or
|
|
15713
|
-
* `Space` (Shift alone counts as unmodified). The browser clicks the control after the keydown,
|
|
15714
|
-
* so the key stays with it.
|
|
15715
|
-
*/
|
|
15716
|
-
function activates(event) {
|
|
15717
|
-
const modified = event.ctrlKey || event.altKey || event.metaKey;
|
|
15718
|
-
return !modified && (event.key === 'Enter' || event.key === ' ');
|
|
15719
|
-
}
|
|
15720
|
-
|
|
15721
15783
|
class SmartformLayoutDefinitionService {
|
|
15722
15784
|
static { this.DEFAULT_QUILL_MODULES = {
|
|
15723
15785
|
toolbar: {
|
|
@@ -16748,11 +16810,11 @@ class SmartTreeComponent {
|
|
|
16748
16810
|
return `${cssClass}-${plusProperty}`;
|
|
16749
16811
|
}
|
|
16750
16812
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
16751
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartTreeComponent, isStandalone: true, selector: "smart-tree", inputs: { treeStyle: { classPropertyName: "treeStyle", publicName: "treeStyle", isSignal: true, isRequired: false, transformFunction: null }, treeService: { classPropertyName: "treeService", publicName: "treeService", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-testid": "this.testId" } }, viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true }, { propertyName: "trigger", predicate: MatMenuTrigger, descendants: true }], ngImport: i0, template: "<div class=\"smartTreeContainer\">\r\n @if (uiActionModels.length) {\r\n <smart-ui-action-toolbar\r\n [uiActionModels]=\"uiActionModels\"\r\n [executor]=\"executor\"\r\n ></smart-ui-action-toolbar>\r\n }\r\n @if (treeData) {\r\n <mat-tree\r\n #tree\r\n [dataSource]=\"dataSource\"\r\n [treeControl]=\"treeControl\"\r\n [trackBy]=\"trackByIdentifier\"\r\n class=\"sm-tree\"\r\n >\r\n <mat-nested-tree-node\r\n *matTreeNodeDef=\"let node; when: hasChild\"\r\n matTreeNodeToggle\r\n [ngClass]=\"getClassesForTreeNode(node)\"\r\n [ngStyle]=\"getNodeStyle(node)\"\r\n >\r\n <div\r\n [ngStyle]=\"getNodePadding(node)\"\r\n [ngClass]=\"getInnerClassesForTreeNode(node)\"\r\n class=\"mat-tree-node sm-tree-node\"\r\n (click)=\"onNodeClick($event, node)\"\r\n >\r\n <button mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.name\">\r\n <mat-icon class=\"mat-icon-rtl-mirror\" (click)=\"onOpenNode($event, node)\">\r\n @if (hasChild(node.level, node)) {\r\n <div>\r\n {{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\r\n </div>\r\n }\r\n </mat-icon>\r\n </button>\r\n <smart-icon [icon]=\"node.icon\"> </smart-icon>\r\n <div class=\"sm-tree-row\" [ngClass]=\"node.classes\">\r\n <div class=\"sm-tree-row-caption\" [attr.title]=\"node.shortDescription || null\">\r\n {{ node.caption }}\r\n </div>\r\n <div class=\"sm-shortDescription-spacer\"></div>\r\n <div class=\"sm-tree-row-shortDescription\">\r\n {{ node.shortDescription }}\r\n </div>\r\n <div class=\"sm-shortDescription-button-spacer\"></div>\r\n @if (node.button) {\r\n <div class=\"sm-tree-node-button\">\r\n @switch (node.button.type) {\r\n @case (smartTreeNodeButtonType.ICON) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-icon-button\r\n >\r\n <smart-icon title=\"{{ node.button.icon }}\" [icon]=\"node.button.icon\"></smart-icon>\r\n </button>\r\n }\r\n @case (smartTreeNodeButtonType.MENU) {\r\n <div>\r\n <button\r\n mat-button\r\n [matMenuTriggerFor]=\"menu\"\r\n (click)=\"customButtonClicked($event, node.button, true)\"\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon\r\n >\r\n }{{ node.button.label }}\r\n </button>\r\n <mat-menu #menu=\"matMenu\">\r\n @for (\r\n button of node.button.menuItemButtons;\r\n track button.code ?? $index\r\n ) {\r\n <button\r\n (click)=\"customButtonClicked($event, button, true)\"\r\n mat-menu-item\r\n [attr.data-testid]=\"button.code ?? null\"\r\n >\r\n @if (button.icon) {\r\n <smart-icon [icon]=\"button.icon\"></smart-icon\r\n >\r\n }{{ button.label }}\r\n </button>\r\n }\r\n </mat-menu>\r\n </div>\r\n }\r\n @case (smartTreeNodeButtonType.NORMAL) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-raised-button\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon>\r\n }\r\n {{ node.button.icon }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div\r\n [class.sm-tree-invisible]=\"!treeControl.isExpanded(node)\"\r\n [ngClass]=\"getClassesForTreeNodeChildren(node)\"\r\n role=\"group\"\r\n >\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n </mat-nested-tree-node>\r\n </mat-tree>\r\n }\r\n @if (!treeData) {\r\n <div class=\"tree-loading\">\r\n <mat-spinner diameter=\"24\" color=\"primary\"></mat-spinner>\r\n </div>\r\n }\r\n </div>\r\n", styles: [".smartTreeContainer{display:flex;flex-direction:column;gap:.5rem}.sm-tree-invisible{display:none}.sm-tree ul,.sm-tree li{margin-top:0;margin-bottom:0;list-style-type:none}.sm-tree div[role=group]>.mat-tree-node{padding-left:40px}.sm-tee-node{padding-left:40px}.sm-tree-node-name{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tree-node-name-row{padding-left:15px;padding-top:15px;display:flex;flex-direction:row;justify-content:space-between}.sm-tree-node-name-col{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tee-node-id{font-weight:lighter}.mat-tree-node:hover{cursor:pointer}.sm-tree-node-selected{background-color:var(--tree-active-background, var(--accent-color, #20b6a8));color:var(--tree-active-color, #ffffff)}::ng-deep .mat-icon-rtl-mirror{display:flex;flex-direction:row}.sm-tree-row{display:flex;flex-direction:row;flex:1;align-items:center}.sm-shortDescription-spacer{flex:1}.sm-tree-row.sm-tree-branch-new{color:var(--success-color, #16a34a)}.sm-tree-row.sm-tree-branch-new .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-modified{color:var(--accent-color, #20b6a8)}.sm-tree-row.sm-tree-branch-modified .sm-tree-row-caption{font-weight:600}.sm-tree-row.sm-tree-branch-deleted{color:var(--color-text-muted, #68778e)}.sm-tree-row.sm-tree-branch-deleted .sm-tree-row-caption{text-decoration:line-through}.sm-tree-row.sm-tree-branch-foreign,.sm-tree-row.sm-tree-branch-own-other-view-context{border-left:3px solid;padding-left:6px}.sm-tree-row.sm-tree-branch-foreign{border-left-color:var(--warning-color, #d97706)}.sm-tree-row.sm-tree-branch-own-other-view-context{border-left-color:var(--info-color, #64748b)}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-caption,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-shortDescription,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-shortDescription{display:none}.sm-tree-node-selected .sm-tree-row,.sm-tree-node-selected .sm-tree-row-caption,.sm-tree-node-selected .sm-tree-row-shortDescription{color:inherit}.tree-loading{display:flex;justify-content:center;align-items:center;min-height:200px;width:100%}\n"], dependencies: [{ kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }, { kind: "component", type: MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
|
|
16813
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartTreeComponent, isStandalone: true, selector: "smart-tree", inputs: { treeStyle: { classPropertyName: "treeStyle", publicName: "treeStyle", isSignal: true, isRequired: false, transformFunction: null }, treeService: { classPropertyName: "treeService", publicName: "treeService", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-testid": "this.testId" } }, viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true }, { propertyName: "trigger", predicate: MatMenuTrigger, descendants: true }], ngImport: i0, template: "<div class=\"smartTreeContainer\">\r\n @if (uiActionModels.length) {\r\n <smart-ui-action-toolbar\r\n [uiActionModels]=\"uiActionModels\"\r\n [executor]=\"executor\"\r\n ></smart-ui-action-toolbar>\r\n }\r\n @if (treeData) {\r\n <mat-tree\r\n #tree\r\n [dataSource]=\"dataSource\"\r\n [treeControl]=\"treeControl\"\r\n [trackBy]=\"trackByIdentifier\"\r\n class=\"sm-tree\"\r\n >\r\n <mat-nested-tree-node\r\n *matTreeNodeDef=\"let node; when: hasChild\"\r\n matTreeNodeToggle\r\n [ngClass]=\"getClassesForTreeNode(node)\"\r\n [ngStyle]=\"getNodeStyle(node)\"\r\n >\r\n <div\r\n [ngStyle]=\"getNodePadding(node)\"\r\n [ngClass]=\"getInnerClassesForTreeNode(node)\"\r\n class=\"mat-tree-node sm-tree-node\"\r\n (click)=\"onNodeClick($event, node)\"\r\n >\r\n <button mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.name\">\r\n <mat-icon class=\"mat-icon-rtl-mirror\" (click)=\"onOpenNode($event, node)\">\r\n @if (hasChild(node.level, node)) {\r\n <div>\r\n {{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\r\n </div>\r\n }\r\n </mat-icon>\r\n </button>\r\n <smart-icon [icon]=\"node.icon\"> </smart-icon>\r\n <div class=\"sm-tree-row\" [ngClass]=\"node.classes\">\r\n <div class=\"sm-tree-row-caption\" [attr.title]=\"node.shortDescription || null\">\r\n {{ node.caption }}\r\n </div>\r\n <div class=\"sm-shortDescription-spacer\"></div>\r\n <div class=\"sm-tree-row-shortDescription\">\r\n {{ node.shortDescription }}\r\n </div>\r\n <div class=\"sm-shortDescription-button-spacer\"></div>\r\n @if (node.button) {\r\n <div class=\"sm-tree-node-button\">\r\n @switch (node.button.type) {\r\n @case (smartTreeNodeButtonType.ICON) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-icon-button\r\n >\r\n <smart-icon title=\"{{ node.button.icon }}\" [icon]=\"node.button.icon\"></smart-icon>\r\n </button>\r\n }\r\n @case (smartTreeNodeButtonType.MENU) {\r\n <div>\r\n <button\r\n mat-button\r\n [matMenuTriggerFor]=\"menu\"\r\n (click)=\"customButtonClicked($event, node.button, true)\"\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon\r\n >\r\n }{{ node.button.label }}\r\n </button>\r\n <mat-menu #menu=\"matMenu\">\r\n @for (\r\n button of node.button.menuItemButtons;\r\n track button.code ?? $index\r\n ) {\r\n <button\r\n (click)=\"customButtonClicked($event, button, true)\"\r\n mat-menu-item\r\n [attr.data-testid]=\"button.code ?? null\"\r\n >\r\n @if (button.icon) {\r\n <smart-icon [icon]=\"button.icon\"></smart-icon\r\n >\r\n }{{ button.label }}\r\n </button>\r\n }\r\n </mat-menu>\r\n </div>\r\n }\r\n @case (smartTreeNodeButtonType.NORMAL) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-raised-button\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon>\r\n }\r\n {{ node.button.icon }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div\r\n [class.sm-tree-invisible]=\"!treeControl.isExpanded(node)\"\r\n [ngClass]=\"getClassesForTreeNodeChildren(node)\"\r\n role=\"group\"\r\n >\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n </mat-nested-tree-node>\r\n </mat-tree>\r\n }\r\n @if (!treeData) {\r\n <div class=\"tree-loading\">\r\n <mat-spinner diameter=\"24\" color=\"primary\"></mat-spinner>\r\n </div>\r\n }\r\n </div>\r\n", styles: [".smartTreeContainer{display:flex;flex-direction:column;gap:.5rem}.sm-tree-invisible{display:none}.sm-tree ul,.sm-tree li{margin-top:0;margin-bottom:0;list-style-type:none}.sm-tree div[role=group]>.mat-tree-node{padding-left:40px}.sm-tee-node{padding-left:40px}.sm-tree-node-name{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tree-node-name-row{padding-left:15px;padding-top:15px;display:flex;flex-direction:row;justify-content:space-between}.sm-tree-node-name-col{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tee-node-id{font-weight:lighter}.mat-tree-node:hover{cursor:pointer}.sm-tree-node-selected{background-color:var(--tree-active-background, var(--accent-color, #20b6a8));color:var(--tree-active-color, #ffffff)}::ng-deep .mat-icon-rtl-mirror{display:flex;flex-direction:row}.sm-tree-row{display:flex;flex-direction:row;flex:1;align-items:center}.sm-shortDescription-spacer{flex:1}.sm-tree-row.sm-tree-branch-new,.sm-tree-row.sm-tree-branch-new *{color:var(--success-color, #16a34a)}.sm-tree-row.sm-tree-branch-new .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-modified,.sm-tree-row.sm-tree-branch-modified *{color:var(--accent-color, #20b6a8)}.sm-tree-row.sm-tree-branch-modified .sm-tree-row-caption{font-weight:600}.sm-tree-row.sm-tree-branch-deleted,.sm-tree-row.sm-tree-branch-deleted *{color:var(--color-text-muted, #68778e)}.sm-tree-row.sm-tree-branch-deleted .sm-tree-row-caption{text-decoration:line-through}.sm-tree-row.sm-tree-branch-contains-change,.sm-tree-row.sm-tree-branch-contains-change *{color:var(--accent-color, #20b6a8)}.sm-tree-row.sm-tree-branch-foreign,.sm-tree-row.sm-tree-branch-own-other-view-context{border-left:3px solid;padding-left:6px}.sm-tree-row.sm-tree-branch-foreign{border-left-color:var(--warning-color, #d97706)}.sm-tree-row.sm-tree-branch-own-other-view-context{border-left-color:var(--info-color, #64748b)}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-caption,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-shortDescription,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-shortDescription{display:none}.sm-tree-node-selected .sm-tree-row,.sm-tree-node-selected .sm-tree-row-caption,.sm-tree-node-selected .sm-tree-row-shortDescription{color:inherit}.tree-loading{display:flex;justify-content:center;align-items:center;min-height:200px;width:100%}\n"], dependencies: [{ kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }, { kind: "component", type: MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
|
|
16752
16814
|
}
|
|
16753
16815
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartTreeComponent, decorators: [{
|
|
16754
16816
|
type: Component,
|
|
16755
|
-
args: [{ selector: 'smart-tree', imports: [UiActionToolbarComponent, MatTree, MatTreeNodeDef, MatNestedTreeNode, MatTreeNodeToggle, NgClass, NgStyle, MatIconButton, MatIcon, SmartIconComponent, MatButton, MatMenuTrigger, MatMenu, MatMenuItem, MatTreeNodeOutlet, MatProgressSpinner], template: "<div class=\"smartTreeContainer\">\r\n @if (uiActionModels.length) {\r\n <smart-ui-action-toolbar\r\n [uiActionModels]=\"uiActionModels\"\r\n [executor]=\"executor\"\r\n ></smart-ui-action-toolbar>\r\n }\r\n @if (treeData) {\r\n <mat-tree\r\n #tree\r\n [dataSource]=\"dataSource\"\r\n [treeControl]=\"treeControl\"\r\n [trackBy]=\"trackByIdentifier\"\r\n class=\"sm-tree\"\r\n >\r\n <mat-nested-tree-node\r\n *matTreeNodeDef=\"let node; when: hasChild\"\r\n matTreeNodeToggle\r\n [ngClass]=\"getClassesForTreeNode(node)\"\r\n [ngStyle]=\"getNodeStyle(node)\"\r\n >\r\n <div\r\n [ngStyle]=\"getNodePadding(node)\"\r\n [ngClass]=\"getInnerClassesForTreeNode(node)\"\r\n class=\"mat-tree-node sm-tree-node\"\r\n (click)=\"onNodeClick($event, node)\"\r\n >\r\n <button mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.name\">\r\n <mat-icon class=\"mat-icon-rtl-mirror\" (click)=\"onOpenNode($event, node)\">\r\n @if (hasChild(node.level, node)) {\r\n <div>\r\n {{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\r\n </div>\r\n }\r\n </mat-icon>\r\n </button>\r\n <smart-icon [icon]=\"node.icon\"> </smart-icon>\r\n <div class=\"sm-tree-row\" [ngClass]=\"node.classes\">\r\n <div class=\"sm-tree-row-caption\" [attr.title]=\"node.shortDescription || null\">\r\n {{ node.caption }}\r\n </div>\r\n <div class=\"sm-shortDescription-spacer\"></div>\r\n <div class=\"sm-tree-row-shortDescription\">\r\n {{ node.shortDescription }}\r\n </div>\r\n <div class=\"sm-shortDescription-button-spacer\"></div>\r\n @if (node.button) {\r\n <div class=\"sm-tree-node-button\">\r\n @switch (node.button.type) {\r\n @case (smartTreeNodeButtonType.ICON) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-icon-button\r\n >\r\n <smart-icon title=\"{{ node.button.icon }}\" [icon]=\"node.button.icon\"></smart-icon>\r\n </button>\r\n }\r\n @case (smartTreeNodeButtonType.MENU) {\r\n <div>\r\n <button\r\n mat-button\r\n [matMenuTriggerFor]=\"menu\"\r\n (click)=\"customButtonClicked($event, node.button, true)\"\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon\r\n >\r\n }{{ node.button.label }}\r\n </button>\r\n <mat-menu #menu=\"matMenu\">\r\n @for (\r\n button of node.button.menuItemButtons;\r\n track button.code ?? $index\r\n ) {\r\n <button\r\n (click)=\"customButtonClicked($event, button, true)\"\r\n mat-menu-item\r\n [attr.data-testid]=\"button.code ?? null\"\r\n >\r\n @if (button.icon) {\r\n <smart-icon [icon]=\"button.icon\"></smart-icon\r\n >\r\n }{{ button.label }}\r\n </button>\r\n }\r\n </mat-menu>\r\n </div>\r\n }\r\n @case (smartTreeNodeButtonType.NORMAL) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-raised-button\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon>\r\n }\r\n {{ node.button.icon }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div\r\n [class.sm-tree-invisible]=\"!treeControl.isExpanded(node)\"\r\n [ngClass]=\"getClassesForTreeNodeChildren(node)\"\r\n role=\"group\"\r\n >\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n </mat-nested-tree-node>\r\n </mat-tree>\r\n }\r\n @if (!treeData) {\r\n <div class=\"tree-loading\">\r\n <mat-spinner diameter=\"24\" color=\"primary\"></mat-spinner>\r\n </div>\r\n }\r\n </div>\r\n", styles: [".smartTreeContainer{display:flex;flex-direction:column;gap:.5rem}.sm-tree-invisible{display:none}.sm-tree ul,.sm-tree li{margin-top:0;margin-bottom:0;list-style-type:none}.sm-tree div[role=group]>.mat-tree-node{padding-left:40px}.sm-tee-node{padding-left:40px}.sm-tree-node-name{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tree-node-name-row{padding-left:15px;padding-top:15px;display:flex;flex-direction:row;justify-content:space-between}.sm-tree-node-name-col{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tee-node-id{font-weight:lighter}.mat-tree-node:hover{cursor:pointer}.sm-tree-node-selected{background-color:var(--tree-active-background, var(--accent-color, #20b6a8));color:var(--tree-active-color, #ffffff)}::ng-deep .mat-icon-rtl-mirror{display:flex;flex-direction:row}.sm-tree-row{display:flex;flex-direction:row;flex:1;align-items:center}.sm-shortDescription-spacer{flex:1}.sm-tree-row.sm-tree-branch-new{color:var(--success-color, #16a34a)}.sm-tree-row.sm-tree-branch-new .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-modified{color:var(--accent-color, #20b6a8)}.sm-tree-row.sm-tree-branch-modified .sm-tree-row-caption{font-weight:600}.sm-tree-row.sm-tree-branch-deleted{color:var(--color-text-muted, #68778e)}.sm-tree-row.sm-tree-branch-deleted .sm-tree-row-caption{text-decoration:line-through}.sm-tree-row.sm-tree-branch-foreign,.sm-tree-row.sm-tree-branch-own-other-view-context{border-left:3px solid;padding-left:6px}.sm-tree-row.sm-tree-branch-foreign{border-left-color:var(--warning-color, #d97706)}.sm-tree-row.sm-tree-branch-own-other-view-context{border-left-color:var(--info-color, #64748b)}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-caption,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-shortDescription,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-shortDescription{display:none}.sm-tree-node-selected .sm-tree-row,.sm-tree-node-selected .sm-tree-row-caption,.sm-tree-node-selected .sm-tree-row-shortDescription{color:inherit}.tree-loading{display:flex;justify-content:center;align-items:center;min-height:200px;width:100%}\n"] }]
|
|
16817
|
+
args: [{ selector: 'smart-tree', imports: [UiActionToolbarComponent, MatTree, MatTreeNodeDef, MatNestedTreeNode, MatTreeNodeToggle, NgClass, NgStyle, MatIconButton, MatIcon, SmartIconComponent, MatButton, MatMenuTrigger, MatMenu, MatMenuItem, MatTreeNodeOutlet, MatProgressSpinner], template: "<div class=\"smartTreeContainer\">\r\n @if (uiActionModels.length) {\r\n <smart-ui-action-toolbar\r\n [uiActionModels]=\"uiActionModels\"\r\n [executor]=\"executor\"\r\n ></smart-ui-action-toolbar>\r\n }\r\n @if (treeData) {\r\n <mat-tree\r\n #tree\r\n [dataSource]=\"dataSource\"\r\n [treeControl]=\"treeControl\"\r\n [trackBy]=\"trackByIdentifier\"\r\n class=\"sm-tree\"\r\n >\r\n <mat-nested-tree-node\r\n *matTreeNodeDef=\"let node; when: hasChild\"\r\n matTreeNodeToggle\r\n [ngClass]=\"getClassesForTreeNode(node)\"\r\n [ngStyle]=\"getNodeStyle(node)\"\r\n >\r\n <div\r\n [ngStyle]=\"getNodePadding(node)\"\r\n [ngClass]=\"getInnerClassesForTreeNode(node)\"\r\n class=\"mat-tree-node sm-tree-node\"\r\n (click)=\"onNodeClick($event, node)\"\r\n >\r\n <button mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.name\">\r\n <mat-icon class=\"mat-icon-rtl-mirror\" (click)=\"onOpenNode($event, node)\">\r\n @if (hasChild(node.level, node)) {\r\n <div>\r\n {{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\r\n </div>\r\n }\r\n </mat-icon>\r\n </button>\r\n <smart-icon [icon]=\"node.icon\"> </smart-icon>\r\n <div class=\"sm-tree-row\" [ngClass]=\"node.classes\">\r\n <div class=\"sm-tree-row-caption\" [attr.title]=\"node.shortDescription || null\">\r\n {{ node.caption }}\r\n </div>\r\n <div class=\"sm-shortDescription-spacer\"></div>\r\n <div class=\"sm-tree-row-shortDescription\">\r\n {{ node.shortDescription }}\r\n </div>\r\n <div class=\"sm-shortDescription-button-spacer\"></div>\r\n @if (node.button) {\r\n <div class=\"sm-tree-node-button\">\r\n @switch (node.button.type) {\r\n @case (smartTreeNodeButtonType.ICON) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-icon-button\r\n >\r\n <smart-icon title=\"{{ node.button.icon }}\" [icon]=\"node.button.icon\"></smart-icon>\r\n </button>\r\n }\r\n @case (smartTreeNodeButtonType.MENU) {\r\n <div>\r\n <button\r\n mat-button\r\n [matMenuTriggerFor]=\"menu\"\r\n (click)=\"customButtonClicked($event, node.button, true)\"\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon\r\n >\r\n }{{ node.button.label }}\r\n </button>\r\n <mat-menu #menu=\"matMenu\">\r\n @for (\r\n button of node.button.menuItemButtons;\r\n track button.code ?? $index\r\n ) {\r\n <button\r\n (click)=\"customButtonClicked($event, button, true)\"\r\n mat-menu-item\r\n [attr.data-testid]=\"button.code ?? null\"\r\n >\r\n @if (button.icon) {\r\n <smart-icon [icon]=\"button.icon\"></smart-icon\r\n >\r\n }{{ button.label }}\r\n </button>\r\n }\r\n </mat-menu>\r\n </div>\r\n }\r\n @case (smartTreeNodeButtonType.NORMAL) {\r\n <button\r\n (click)=\"customButtonClicked($event, node.button)\"\r\n mat-raised-button\r\n >\r\n @if (node.button.icon) {\r\n <smart-icon [icon]=\"node.button.icon\"></smart-icon>\r\n }\r\n {{ node.button.icon }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div\r\n [class.sm-tree-invisible]=\"!treeControl.isExpanded(node)\"\r\n [ngClass]=\"getClassesForTreeNodeChildren(node)\"\r\n role=\"group\"\r\n >\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </div>\r\n </mat-nested-tree-node>\r\n </mat-tree>\r\n }\r\n @if (!treeData) {\r\n <div class=\"tree-loading\">\r\n <mat-spinner diameter=\"24\" color=\"primary\"></mat-spinner>\r\n </div>\r\n }\r\n </div>\r\n", styles: [".smartTreeContainer{display:flex;flex-direction:column;gap:.5rem}.sm-tree-invisible{display:none}.sm-tree ul,.sm-tree li{margin-top:0;margin-bottom:0;list-style-type:none}.sm-tree div[role=group]>.mat-tree-node{padding-left:40px}.sm-tee-node{padding-left:40px}.sm-tree-node-name{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tree-node-name-row{padding-left:15px;padding-top:15px;display:flex;flex-direction:row;justify-content:space-between}.sm-tree-node-name-col{padding-left:15px;padding-top:15px;display:flex;flex-direction:column}.sm-tee-node-id{font-weight:lighter}.mat-tree-node:hover{cursor:pointer}.sm-tree-node-selected{background-color:var(--tree-active-background, var(--accent-color, #20b6a8));color:var(--tree-active-color, #ffffff)}::ng-deep .mat-icon-rtl-mirror{display:flex;flex-direction:row}.sm-tree-row{display:flex;flex-direction:row;flex:1;align-items:center}.sm-shortDescription-spacer{flex:1}.sm-tree-row.sm-tree-branch-new,.sm-tree-row.sm-tree-branch-new *{color:var(--success-color, #16a34a)}.sm-tree-row.sm-tree-branch-new .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-modified,.sm-tree-row.sm-tree-branch-modified *{color:var(--accent-color, #20b6a8)}.sm-tree-row.sm-tree-branch-modified .sm-tree-row-caption{font-weight:600}.sm-tree-row.sm-tree-branch-deleted,.sm-tree-row.sm-tree-branch-deleted *{color:var(--color-text-muted, #68778e)}.sm-tree-row.sm-tree-branch-deleted .sm-tree-row-caption{text-decoration:line-through}.sm-tree-row.sm-tree-branch-contains-change,.sm-tree-row.sm-tree-branch-contains-change *{color:var(--accent-color, #20b6a8)}.sm-tree-row.sm-tree-branch-foreign,.sm-tree-row.sm-tree-branch-own-other-view-context{border-left:3px solid;padding-left:6px}.sm-tree-row.sm-tree-branch-foreign{border-left-color:var(--warning-color, #d97706)}.sm-tree-row.sm-tree-branch-own-other-view-context{border-left-color:var(--info-color, #64748b)}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-caption,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-caption{font-style:italic}.sm-tree-row.sm-tree-branch-foreign .sm-tree-row-shortDescription,.sm-tree-row.sm-tree-branch-own-other-view-context .sm-tree-row-shortDescription{display:none}.sm-tree-node-selected .sm-tree-row,.sm-tree-node-selected .sm-tree-row-caption,.sm-tree-node-selected .sm-tree-row-shortDescription{color:inherit}.tree-loading{display:flex;justify-content:center;align-items:center;min-height:200px;width:100%}\n"] }]
|
|
16756
16818
|
}], ctorParameters: () => [], propDecorators: { trigger: [{
|
|
16757
16819
|
type: ViewChildren,
|
|
16758
16820
|
args: [MatMenuTrigger]
|
|
@@ -18646,6 +18708,11 @@ class SmartComponentApiClient {
|
|
|
18646
18708
|
this.dataChanged = new Subject();
|
|
18647
18709
|
this.inmediateDataChangeKeys = [];
|
|
18648
18710
|
this.blurDataChangeKeys = [];
|
|
18711
|
+
/**
|
|
18712
|
+
* The actions of the window descriptor of the dialog showing this view (its header), set by
|
|
18713
|
+
* the dialog. The backend binds keys to them on this view, so the keys fire them here.
|
|
18714
|
+
*/
|
|
18715
|
+
this.windowActions = [];
|
|
18649
18716
|
// check and calculate pageName
|
|
18650
18717
|
if (!this.pageName && !this._componentName) {
|
|
18651
18718
|
throw new Error('pageName or componentName must be specified!');
|
|
@@ -18707,10 +18774,18 @@ class SmartComponentApiClient {
|
|
|
18707
18774
|
fire: (code, identifier) => this.fireBoundAction(code, identifier),
|
|
18708
18775
|
});
|
|
18709
18776
|
}
|
|
18710
|
-
/**
|
|
18777
|
+
/**
|
|
18778
|
+
* The action a binding fires: the one of the code and identifier, or the first of the code,
|
|
18779
|
+
* among the actions of the view, then among the header actions of the dialog showing it.
|
|
18780
|
+
*/
|
|
18711
18781
|
findBoundAction(code, identifier) {
|
|
18712
|
-
|
|
18713
|
-
|
|
18782
|
+
const isBound = (uiAction) => uiAction.code === code && (identifier == null || uiAction.identifier === identifier);
|
|
18783
|
+
const entry = this.actionModels().find((model) => isBound(model.uiAction));
|
|
18784
|
+
if (entry) {
|
|
18785
|
+
return entry;
|
|
18786
|
+
}
|
|
18787
|
+
const windowAction = this.windowActions.find(isBound);
|
|
18788
|
+
return windowAction ? { serviceToUse: this, uiAction: windowAction } : undefined;
|
|
18714
18789
|
}
|
|
18715
18790
|
fireBoundAction(code, identifier) {
|
|
18716
18791
|
const entry = this.findBoundAction(code, identifier);
|
|
@@ -18787,8 +18862,8 @@ class SmartComponentApiClient {
|
|
|
18787
18862
|
async load() {
|
|
18788
18863
|
this.componentModelLoaded = false;
|
|
18789
18864
|
// Slot-hosted views (NORMAL/EMBEDDED) get their uuid injected at creation. DIALOG views
|
|
18790
|
-
// are
|
|
18791
|
-
//
|
|
18865
|
+
// are not slot-hosted: they read it from the dialog data, and fall back to the
|
|
18866
|
+
// pageName -> getUuidOfPage shim only when the dialog was opened without one.
|
|
18792
18867
|
const uuid = this.uuid ?? this.readDialogDataUuid() ?? this.viewContext.getUuidOfPage(this.pageName);
|
|
18793
18868
|
// console.log('[Embedded] load()', {
|
|
18794
18869
|
// pageName: this.pageName,
|