@scion/workbench 21.0.0-beta.4 → 21.0.0-beta.6
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.
|
@@ -6395,7 +6395,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
6395
6395
|
*/
|
|
6396
6396
|
function trackFocus(target, workbenchElement) {
|
|
6397
6397
|
const focusMonitor = inject(ɵWorkbenchFocusMonitor);
|
|
6398
|
-
|
|
6398
|
+
toObservable(focusMonitor.activeElement)
|
|
6399
6399
|
.pipe(startWith(focusMonitor.activeElement()), // Immediately subscribe to `focusin` events, required when the DOM element is focused right after invocation.
|
|
6400
6400
|
switchMap(activeWorkbenchElement => activeWorkbenchElement === workbenchElement ? EMPTY : merge(fromEvent(target, 'focusin', { once: true }), fromEvent(target, 'sci-microfrontend-focusin', { once: true }))), finalize(() => requestAnimationFrame(() => focusMonitor.unsetActiveElement(workbenchElement))), // Asynchronously unset the active workbench element to prevent a `null` focus during destruction until the next element gains focus.
|
|
6401
6401
|
takeUntilDestroyed())
|
|
@@ -6404,7 +6404,6 @@ function trackFocus(target, workbenchElement) {
|
|
|
6404
6404
|
});
|
|
6405
6405
|
return {
|
|
6406
6406
|
unsetActiveElement: () => focusMonitor.unsetActiveElement(workbenchElement),
|
|
6407
|
-
destroy: () => subscription.unsubscribe(),
|
|
6408
6407
|
};
|
|
6409
6408
|
}
|
|
6410
6409
|
class ɵWorkbenchFocusMonitor {
|
|
@@ -6426,7 +6425,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
6426
6425
|
}] });
|
|
6427
6426
|
|
|
6428
6427
|
/*
|
|
6429
|
-
* Copyright (c) 2018-
|
|
6428
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
6430
6429
|
*
|
|
6431
6430
|
* This program and the accompanying materials are made
|
|
6432
6431
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -6854,7 +6853,7 @@ class WbComponentPortal {
|
|
|
6854
6853
|
this.detach();
|
|
6855
6854
|
}
|
|
6856
6855
|
this._viewContainerRef.set(viewContainerRef);
|
|
6857
|
-
this._componentRef.update(componentRef => componentRef ?? createPortalComponent(this._componentType, { providers: this._options?.providers, injector: viewContainerRef.injector }));
|
|
6856
|
+
this._componentRef.update(componentRef => componentRef ?? createPortalComponent(this._componentType, { providers: this._options?.providers, injector: this._options?.injector ?? viewContainerRef.injector }));
|
|
6858
6857
|
this._logger.debug(() => 'Attaching portal', LoggerNames.LIFECYCLE, this._options?.debugName ?? this._componentType.name);
|
|
6859
6858
|
this._componentRef().changeDetectorRef.reattach();
|
|
6860
6859
|
this._viewContainerRef().insert(this._componentRef().hostView);
|
|
@@ -8330,7 +8329,7 @@ class MainAreaPartComponent {
|
|
|
8330
8329
|
});
|
|
8331
8330
|
}
|
|
8332
8331
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MainAreaPartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8333
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MainAreaPartComponent, isStandalone: true, selector: "wb-part[data-partid=\"part.main-area\"]", host: { properties: { "attr.data-grid": "dasherize(part.gridName())", "attr.data-active": "part.active() ? '' : null" } }, ngImport: i0, template: "@if (mainAreaGrid().root.visible) {\n <wb-grid [grid]=\"mainAreaGrid()\"\n [gridDropZone]=\"{\n dropRegionSize: 100,\n dropPlaceholderSize: 100,\n dropZoneAttributes: {\n 'data-grid': 'main-area',\n 'data-partid': part.id,\n }\n }\"\n [attr.data-grid]=\"'main-area'\"\n class=\"e2e-
|
|
8332
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MainAreaPartComponent, isStandalone: true, selector: "wb-part[data-partid=\"part.main-area\"]", host: { properties: { "attr.data-grid": "dasherize(part.gridName())", "attr.data-active": "part.active() ? '' : null" } }, ngImport: i0, template: "@if (mainAreaGrid().root.visible) {\n <wb-grid [grid]=\"mainAreaGrid()\"\n [gridDropZone]=\"{\n dropRegionSize: 100,\n dropPlaceholderSize: 100,\n dropZoneAttributes: {\n 'data-grid': 'main-area',\n 'data-partid': part.id,\n }\n }\"\n [attr.data-grid]=\"'main-area'\"\n class=\"e2e-slot\"/>\n} @else {\n <div wbViewDropZone\n [wbViewDropZoneRegions]=\"canDrop() && {center: true, north: false, south: false, west: false, east: false}\"\n [wbViewDropZoneAttributes]=\"{\n 'data-desktop': '',\n 'data-partid': part.id,\n }\"\n (wbViewDropZoneDrop)=\"onDesktopViewDrop($event)\"\n class=\"desktop e2e-part-slot e2e-slot\">\n @if (part.navigation()) {\n <ng-container *wbPortalOutlet=\"part.slot.portal; destroyOnDetach: false\"/>\n } @else {\n <ng-container *wbPortalOutlet=\"desktop.slot.portal; destroyOnDetach: false\"/>\n }\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column}:host>wb-grid{flex:auto}:host>div.desktop{flex:auto;display:grid;position:relative}\n"], dependencies: [{ kind: "component", type: GridComponent, selector: "wb-grid", inputs: ["grid", "gridDropZone"] }, { kind: "directive", type: ViewDropZoneDirective, selector: "[wbViewDropZone]", inputs: ["wbViewDropZoneRegions", "wbViewDropZoneAttributes", "wbViewDropZoneRegionSize", "wbViewDropZonePlaceholderSize"], outputs: ["wbViewDropZoneDrop"] }, { kind: "directive", type: WorkbenchPortalOutletDirective, selector: "ng-template[wbPortalOutlet]", inputs: ["wbPortalOutlet", "wbPortalOutletDestroyOnDetach"] }] });
|
|
8334
8333
|
}
|
|
8335
8334
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MainAreaPartComponent, decorators: [{
|
|
8336
8335
|
type: Component,
|
|
@@ -8341,7 +8340,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
8341
8340
|
], host: {
|
|
8342
8341
|
'[attr.data-grid]': 'dasherize(part.gridName())',
|
|
8343
8342
|
'[attr.data-active]': `part.active() ? '' : null`,
|
|
8344
|
-
}, template: "@if (mainAreaGrid().root.visible) {\n <wb-grid [grid]=\"mainAreaGrid()\"\n [gridDropZone]=\"{\n dropRegionSize: 100,\n dropPlaceholderSize: 100,\n dropZoneAttributes: {\n 'data-grid': 'main-area',\n 'data-partid': part.id,\n }\n }\"\n [attr.data-grid]=\"'main-area'\"\n class=\"e2e-
|
|
8343
|
+
}, template: "@if (mainAreaGrid().root.visible) {\n <wb-grid [grid]=\"mainAreaGrid()\"\n [gridDropZone]=\"{\n dropRegionSize: 100,\n dropPlaceholderSize: 100,\n dropZoneAttributes: {\n 'data-grid': 'main-area',\n 'data-partid': part.id,\n }\n }\"\n [attr.data-grid]=\"'main-area'\"\n class=\"e2e-slot\"/>\n} @else {\n <div wbViewDropZone\n [wbViewDropZoneRegions]=\"canDrop() && {center: true, north: false, south: false, west: false, east: false}\"\n [wbViewDropZoneAttributes]=\"{\n 'data-desktop': '',\n 'data-partid': part.id,\n }\"\n (wbViewDropZoneDrop)=\"onDesktopViewDrop($event)\"\n class=\"desktop e2e-part-slot e2e-slot\">\n @if (part.navigation()) {\n <ng-container *wbPortalOutlet=\"part.slot.portal; destroyOnDetach: false\"/>\n } @else {\n <ng-container *wbPortalOutlet=\"desktop.slot.portal; destroyOnDetach: false\"/>\n }\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column}:host>wb-grid{flex:auto}:host>div.desktop{flex:auto;display:grid;position:relative}\n"] }]
|
|
8345
8344
|
}] });
|
|
8346
8345
|
|
|
8347
8346
|
/*
|
|
@@ -9723,7 +9722,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
9723
9722
|
}] });
|
|
9724
9723
|
|
|
9725
9724
|
/*
|
|
9726
|
-
* Copyright (c) 2018-
|
|
9725
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
9727
9726
|
*
|
|
9728
9727
|
* This program and the accompanying materials are made
|
|
9729
9728
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -9745,7 +9744,8 @@ class WorkbenchDialogComponent {
|
|
|
9745
9744
|
headerHeight = signal(undefined, { ...(ngDevMode ? { debugName: "headerHeight" } : {}) });
|
|
9746
9745
|
transformTranslateX = signal(0, { ...(ngDevMode ? { debugName: "transformTranslateX" } : {}) });
|
|
9747
9746
|
transformTranslateY = signal(0, { ...(ngDevMode ? { debugName: "transformTranslateY" } : {}) });
|
|
9748
|
-
|
|
9747
|
+
slotAnchorName = this.dialog.id.replace('.', '_'); // Anchor must not contain a dot.
|
|
9748
|
+
dialogSlotBounds = viewChild.required('slot_bounds', { read: (ElementRef) });
|
|
9749
9749
|
constructor() {
|
|
9750
9750
|
this.setDialogOffset();
|
|
9751
9751
|
this.trackFocus();
|
|
@@ -9847,7 +9847,7 @@ class WorkbenchDialogComponent {
|
|
|
9847
9847
|
this.focus();
|
|
9848
9848
|
}
|
|
9849
9849
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9850
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: WorkbenchDialogComponent, isStandalone: true, selector: "wb-dialog", host: { listeners: { "keydown.escape": "onEscape($event)" }, properties: { "attr.data-dialogid": "dialog.id", "class.justified": "!dialog.padding()", "style.--\u0275dialog-transform-translate-x": "transformTranslateX()", "style.--\u0275dialog-transform-translate-y": "transformTranslateY()", "style.--\u0275dialog-min-height": "dialog.size.minHeight() ?? headerHeight()", "style.--\u0275dialog-height": "dialog.size.height()", "style.--\u0275dialog-max-height": "dialog.size.maxHeight()", "style.--\u0275dialog-min-width": "dialog.size.minWidth() ?? '100px'", "style.--\u0275dialog-width": "dialog.size.width()", "style.--\u0275dialog-max-width": "dialog.size.maxWidth()", "class": "dialog.cssClass()" } }, viewQueries: [{ propertyName: "_cdkTrapFocus", first: true, predicate: CdkTrapFocus, descendants: true, isSignal: true }, { propertyName: "_dialogElement", first: true, predicate: ["dialog_element"], descendants: true, isSignal: true }, { propertyName: "
|
|
9850
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: WorkbenchDialogComponent, isStandalone: true, selector: "wb-dialog", host: { listeners: { "keydown.escape": "onEscape($event)" }, properties: { "attr.data-dialogid": "dialog.id", "class.justified": "!dialog.padding()", "style.--\u0275dialog-transform-translate-x": "transformTranslateX()", "style.--\u0275dialog-transform-translate-y": "transformTranslateY()", "style.--\u0275dialog-min-height": "dialog.size.minHeight() ?? headerHeight()", "style.--\u0275dialog-height": "dialog.size.height()", "style.--\u0275dialog-max-height": "dialog.size.maxHeight()", "style.--\u0275dialog-min-width": "dialog.size.minWidth() ?? '100px'", "style.--\u0275dialog-width": "dialog.size.width()", "style.--\u0275dialog-max-width": "dialog.size.maxWidth()", "style.--\u0275slot-anchor": "`--${slotAnchorName}`", "class": "dialog.cssClass()" } }, viewQueries: [{ propertyName: "_cdkTrapFocus", first: true, predicate: CdkTrapFocus, descendants: true, isSignal: true }, { propertyName: "_dialogElement", first: true, predicate: ["dialog_element"], descendants: true, isSignal: true }, { propertyName: "dialogSlotBounds", first: true, predicate: ["slot_bounds"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div class=\"dialog e2e-dialog\"\n [class.blinking]=\"dialog.blinking$ | async\"\n [tabindex]=\"-1\"\n wbMovable [wbHandle]=\"header\" (wbMovableMove)=\"onMove($event)\"\n (mousedown)=\"onDialogMouseDown()\"\n wbResizable [wbResizableEnabled]=\"dialog.resizable()\" (wbResizableResize)=\"onResize($event)\"\n @enter\n [@.disabled]=\"!dialog.animate\"\n wbGlassPane\n #dialog_element>\n <div class=\"dialog-box e2e-dialog-box\" cdkTrapFocus>\n <header #header\n class=\"e2e-dialog-header\"\n [class.divider]=\"dialog.header?.divider() ?? true\"\n sciDimension (sciDimensionChange)=\"onHeaderDimensionChange($event)\">\n <ng-container *ngTemplateOutlet=\"dialog.header?.template ?? default_dialog_header\"/>\n </header>\n\n <sci-viewport class=\"e2e-dialog-slot\">\n <ng-container *ngComponentOutlet=\"dialog.component; inputs: dialog.inputs\"/>\n </sci-viewport>\n\n <!-- Extra DIV to capture bounds available to slotted content, excluding viewport content padding. May differ from the actual content size if content overflows or does not fill the slot. -->\n <div class=\"slot-bounds e2e-dialog-slot-bounds\" #slot_bounds></div>\n\n @if (dialog.footer || dialog.actions.length) {\n <footer class=\"e2e-dialog-footer\" [class.divider]=\"dialog.footer?.divider() ?? true\">\n <ng-container *ngTemplateOutlet=\"dialog.footer?.template ?? default_dialog_footer\"/>\n </footer>\n }\n </div>\n</div>\n\n<ng-template #default_dialog_header>\n <wb-dialog-header/>\n</ng-template>\n\n<ng-template #default_dialog_footer>\n <wb-dialog-footer/>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{--\\275 dialog-transform-translate-x: 0;--\\275 dialog-transform-translate-y: 0;--\\275 dialog-min-height: initial;--\\275 dialog-height: initial;--\\275 dialog-max-height: initial;--\\275 dialog-min-width: initial;--\\275 dialog-width: initial;--\\275 dialog-max-width: initial;--\\275 dialog-padding: var(--sci-workbench-dialog-padding)}:host.justified{--\\275 dialog-padding: 0}:host{display:flex;flex-direction:column;align-items:center;position:relative}:host>div.dialog{display:flex;flex-direction:column;position:absolute;top:3%;color:var(--sci-color-text);transform:translate(calc(1px * var(--\\275 dialog-transform-translate-x))) translateY(calc(1px * var(--\\275 dialog-transform-translate-y)));min-height:var(--\\275 dialog-min-height);height:var(--\\275 dialog-height);max-height:var(--\\275 dialog-max-height);min-width:var(--\\275 dialog-min-width);width:var(--\\275 dialog-width);max-width:var(--\\275 dialog-max-width);outline:none;pointer-events:auto}:host>div.dialog>div.dialog-box{flex:auto;display:flex;flex-direction:column;gap:calc(1.25 * var(--\\275 dialog-padding));border:1px solid var(--sci-color-border);border-radius:var(--sci-corner);background-color:var(--sci-color-background-elevation);box-shadow:var(--sci-elevation) var(--sci-static-color-black);overflow:hidden}:host>div.dialog>div.dialog-box>header{flex:none}:host>div.dialog>div.dialog-box>header.divider{border-bottom:1px solid var(--sci-color-border)}:host>div.dialog>div.dialog-box>sci-viewport{flex:auto;anchor-name:var(--\\275slot-anchor)}:host>div.dialog>div.dialog-box>sci-viewport::part(content){padding-inline:var(--\\275 dialog-padding)}:host>div.dialog>div.dialog-box>div.slot-bounds{position:absolute;position-anchor:var(--\\275slot-anchor);inset:anchor(top) anchor(right) anchor(bottom) anchor(left);margin-inline:var(--\\275 dialog-padding);visibility:hidden}:host>div.dialog>div.dialog-box>footer{flex:none}:host>div.dialog>div.dialog-box>footer.divider{border-top:1px solid var(--sci-color-border)}:host>div.dialog.blinking{animation-duration:50ms;animation-iteration-count:infinite;animation-name:blink-animation}@keyframes blink-animation{0%{transform:translate(calc(1px * var(--\\275 dialog-transform-translate-x) - 2px)) translateY(calc(1px * var(--\\275 dialog-transform-translate-y) - 1px))}to{transform:translate(calc(1px * var(--\\275 dialog-transform-translate-x) + 2px)) translateY(calc(1px * var(--\\275 dialog-transform-translate-y) + 1px))}}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: MovableDirective, selector: "[wbMovable]", inputs: ["wbHandle"], outputs: ["wbMovableMove"] }, { kind: "directive", type: ResizableDirective, selector: "[wbResizable]", inputs: ["wbResizableEnabled"], outputs: ["wbResizableResize"] }, { kind: "component", type: SciViewportComponent, selector: "sci-viewport", inputs: ["scrollbarStyle"], outputs: ["scroll"] }, { kind: "directive", type: SciDimensionDirective, selector: "[sciDimension]", inputs: ["emitOutsideAngular"], outputs: ["sciDimensionChange"] }, { kind: "component", type: DialogHeaderComponent, selector: "wb-dialog-header" }, { kind: "component", type: DialogFooterComponent, selector: "wb-dialog-footer" }, { kind: "directive", type: GlassPaneDirective, selector: "[wbGlassPane]" }, { kind: "pipe", type: AsyncPipe, name: "async" }], viewProviders: [
|
|
9851
9851
|
configureDialogGlassPane(),
|
|
9852
9852
|
], animations: [
|
|
9853
9853
|
trigger('enter', provideEnterAnimation()),
|
|
@@ -9882,9 +9882,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
9882
9882
|
'[style.--ɵdialog-min-width]': 'dialog.size.minWidth() ?? \'100px\'',
|
|
9883
9883
|
'[style.--ɵdialog-width]': 'dialog.size.width()',
|
|
9884
9884
|
'[style.--ɵdialog-max-width]': 'dialog.size.maxWidth()',
|
|
9885
|
+
'[style.--ɵslot-anchor]': '`--${slotAnchorName}`',
|
|
9885
9886
|
'[class]': 'dialog.cssClass()',
|
|
9886
|
-
}, template: "<div class=\"dialog e2e-dialog\"\n [class.blinking]=\"dialog.blinking$ | async\"\n [tabindex]=\"-1\"\n wbMovable [wbHandle]=\"header\" (wbMovableMove)=\"onMove($event)\"\n (mousedown)=\"onDialogMouseDown()\"\n wbResizable [wbResizableEnabled]=\"dialog.resizable()\" (wbResizableResize)=\"onResize($event)\"\n @enter\n [@.disabled]=\"!dialog.animate\"\n wbGlassPane\n #dialog_element>\n <div class=\"dialog-box e2e-dialog-box\" cdkTrapFocus>\n <header #header\n class=\"e2e-dialog-header\"\n [class.divider]=\"dialog.header?.divider() ?? true\"\n sciDimension (sciDimensionChange)=\"onHeaderDimensionChange($event)\">\n <ng-container *ngTemplateOutlet=\"dialog.header?.template ?? default_dialog_header\"/>\n </header>\n\n <sci-viewport class=\"
|
|
9887
|
-
}], ctorParameters: () => [], propDecorators: { _cdkTrapFocus: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkTrapFocus), { isSignal: true }] }], _dialogElement: [{ type: i0.ViewChild, args: ['dialog_element', { isSignal: true }] }],
|
|
9887
|
+
}, template: "<div class=\"dialog e2e-dialog\"\n [class.blinking]=\"dialog.blinking$ | async\"\n [tabindex]=\"-1\"\n wbMovable [wbHandle]=\"header\" (wbMovableMove)=\"onMove($event)\"\n (mousedown)=\"onDialogMouseDown()\"\n wbResizable [wbResizableEnabled]=\"dialog.resizable()\" (wbResizableResize)=\"onResize($event)\"\n @enter\n [@.disabled]=\"!dialog.animate\"\n wbGlassPane\n #dialog_element>\n <div class=\"dialog-box e2e-dialog-box\" cdkTrapFocus>\n <header #header\n class=\"e2e-dialog-header\"\n [class.divider]=\"dialog.header?.divider() ?? true\"\n sciDimension (sciDimensionChange)=\"onHeaderDimensionChange($event)\">\n <ng-container *ngTemplateOutlet=\"dialog.header?.template ?? default_dialog_header\"/>\n </header>\n\n <sci-viewport class=\"e2e-dialog-slot\">\n <ng-container *ngComponentOutlet=\"dialog.component; inputs: dialog.inputs\"/>\n </sci-viewport>\n\n <!-- Extra DIV to capture bounds available to slotted content, excluding viewport content padding. May differ from the actual content size if content overflows or does not fill the slot. -->\n <div class=\"slot-bounds e2e-dialog-slot-bounds\" #slot_bounds></div>\n\n @if (dialog.footer || dialog.actions.length) {\n <footer class=\"e2e-dialog-footer\" [class.divider]=\"dialog.footer?.divider() ?? true\">\n <ng-container *ngTemplateOutlet=\"dialog.footer?.template ?? default_dialog_footer\"/>\n </footer>\n }\n </div>\n</div>\n\n<ng-template #default_dialog_header>\n <wb-dialog-header/>\n</ng-template>\n\n<ng-template #default_dialog_footer>\n <wb-dialog-footer/>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{--\\275 dialog-transform-translate-x: 0;--\\275 dialog-transform-translate-y: 0;--\\275 dialog-min-height: initial;--\\275 dialog-height: initial;--\\275 dialog-max-height: initial;--\\275 dialog-min-width: initial;--\\275 dialog-width: initial;--\\275 dialog-max-width: initial;--\\275 dialog-padding: var(--sci-workbench-dialog-padding)}:host.justified{--\\275 dialog-padding: 0}:host{display:flex;flex-direction:column;align-items:center;position:relative}:host>div.dialog{display:flex;flex-direction:column;position:absolute;top:3%;color:var(--sci-color-text);transform:translate(calc(1px * var(--\\275 dialog-transform-translate-x))) translateY(calc(1px * var(--\\275 dialog-transform-translate-y)));min-height:var(--\\275 dialog-min-height);height:var(--\\275 dialog-height);max-height:var(--\\275 dialog-max-height);min-width:var(--\\275 dialog-min-width);width:var(--\\275 dialog-width);max-width:var(--\\275 dialog-max-width);outline:none;pointer-events:auto}:host>div.dialog>div.dialog-box{flex:auto;display:flex;flex-direction:column;gap:calc(1.25 * var(--\\275 dialog-padding));border:1px solid var(--sci-color-border);border-radius:var(--sci-corner);background-color:var(--sci-color-background-elevation);box-shadow:var(--sci-elevation) var(--sci-static-color-black);overflow:hidden}:host>div.dialog>div.dialog-box>header{flex:none}:host>div.dialog>div.dialog-box>header.divider{border-bottom:1px solid var(--sci-color-border)}:host>div.dialog>div.dialog-box>sci-viewport{flex:auto;anchor-name:var(--\\275slot-anchor)}:host>div.dialog>div.dialog-box>sci-viewport::part(content){padding-inline:var(--\\275 dialog-padding)}:host>div.dialog>div.dialog-box>div.slot-bounds{position:absolute;position-anchor:var(--\\275slot-anchor);inset:anchor(top) anchor(right) anchor(bottom) anchor(left);margin-inline:var(--\\275 dialog-padding);visibility:hidden}:host>div.dialog>div.dialog-box>footer{flex:none}:host>div.dialog>div.dialog-box>footer.divider{border-top:1px solid var(--sci-color-border)}:host>div.dialog.blinking{animation-duration:50ms;animation-iteration-count:infinite;animation-name:blink-animation}@keyframes blink-animation{0%{transform:translate(calc(1px * var(--\\275 dialog-transform-translate-x) - 2px)) translateY(calc(1px * var(--\\275 dialog-transform-translate-y) - 1px))}to{transform:translate(calc(1px * var(--\\275 dialog-transform-translate-x) + 2px)) translateY(calc(1px * var(--\\275 dialog-transform-translate-y) + 1px))}}\n"] }]
|
|
9888
|
+
}], ctorParameters: () => [], propDecorators: { _cdkTrapFocus: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkTrapFocus), { isSignal: true }] }], _dialogElement: [{ type: i0.ViewChild, args: ['dialog_element', { isSignal: true }] }], dialogSlotBounds: [{ type: i0.ViewChild, args: ['slot_bounds', { ...{ read: (ElementRef) }, isSignal: true }] }], onEscape: [{
|
|
9888
9889
|
type: HostListener,
|
|
9889
9890
|
args: ['keydown.escape', ['$event']]
|
|
9890
9891
|
}] } });
|
|
@@ -9916,7 +9917,7 @@ function configureDialogGlassPane() {
|
|
|
9916
9917
|
}
|
|
9917
9918
|
|
|
9918
9919
|
/*
|
|
9919
|
-
* Copyright (c) 2018-
|
|
9920
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
9920
9921
|
*
|
|
9921
9922
|
* This program and the accompanying materials are made
|
|
9922
9923
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -9925,96 +9926,17 @@ function configureDialogGlassPane() {
|
|
|
9925
9926
|
* SPDX-License-Identifier: EPL-2.0
|
|
9926
9927
|
*/
|
|
9927
9928
|
/**
|
|
9928
|
-
*
|
|
9929
|
-
*
|
|
9930
|
-
* A dialog is a visual element for focused interaction with the user, such as prompting the user for input or confirming actions.
|
|
9931
|
-
* The user can move and resize a dialog.
|
|
9932
|
-
*
|
|
9933
|
-
* Displayed on top of other content, a modal dialog blocks interaction with other parts of the application.
|
|
9934
|
-
*
|
|
9935
|
-
* ## Modality
|
|
9936
|
-
* A dialog can be context-modal or application-modal. Context-modal blocks a specific part of the application, as specified by the context;
|
|
9937
|
-
* application-modal blocks the workbench or browser viewport, based on {@link WorkbenchConfig.dialog.modalityScope}.
|
|
9938
|
-
*
|
|
9939
|
-
* ## Context
|
|
9940
|
-
* A dialog can be bound to a context (e.g., part or view), defaulting to the calling context.
|
|
9941
|
-
* The dialog is displayed only if the context is visible and closes when the context is disposed.
|
|
9942
|
-
*
|
|
9943
|
-
* ## Positioning
|
|
9944
|
-
* A dialog is opened in the center of its context, if any, unless opened from the peripheral area.
|
|
9945
|
-
*
|
|
9946
|
-
* ## Stacking
|
|
9947
|
-
* Dialogs are stacked per modality, with only the topmost dialog in each stack being interactive.
|
|
9948
|
-
*
|
|
9949
|
-
* ## Dialog Component
|
|
9950
|
-
* The dialog component can inject the {@link WorkbenchDialog} handle to interact with the dialog, such as setting the title or closing the dialog.
|
|
9951
|
-
* Inputs passed to the dialog are available as input properties in the dialog component.
|
|
9952
|
-
*
|
|
9953
|
-
* ## Dialog Header
|
|
9954
|
-
* By default, the dialog displays the title and a close button in the header. Alternatively, the dialog supports the use of a custom header.
|
|
9955
|
-
* To provide a custom header, add an Angular template to the HTML of the dialog component and decorate it with the `wbDialogHeader` directive.
|
|
9956
|
-
*
|
|
9957
|
-
* ```html
|
|
9958
|
-
* <ng-template wbDialogHeader>
|
|
9959
|
-
* <app-dialog-header/>
|
|
9960
|
-
* </ng-template>
|
|
9961
|
-
* ```
|
|
9962
|
-
*
|
|
9963
|
-
* ## Dialog Footer
|
|
9964
|
-
* A dialog has a default footer that displays actions defined in the HTML of the dialog component. An action is an Angular template decorated with
|
|
9965
|
-
* the `wbDialogAction` directive. Multiple actions are supported, rendered in modeling order, and can be left- or right-aligned.
|
|
9966
|
-
*
|
|
9967
|
-
* ```html
|
|
9968
|
-
* <!-- Checkbox -->
|
|
9969
|
-
* <ng-template wbDialogAction align="start">
|
|
9970
|
-
* <label>
|
|
9971
|
-
* <input type="checkbox"/>
|
|
9972
|
-
* Do not ask me again
|
|
9973
|
-
* </label>
|
|
9974
|
-
* </ng-template>
|
|
9975
|
-
*
|
|
9976
|
-
* <!-- OK Button -->
|
|
9977
|
-
* <ng-template wbDialogAction align="end">
|
|
9978
|
-
* <button (click)="...">OK</button>
|
|
9979
|
-
* </ng-template>
|
|
9980
|
-
*
|
|
9981
|
-
* <!-- Cancel Button -->
|
|
9982
|
-
* <ng-template wbDialogAction align="end">
|
|
9983
|
-
* <button (click)="...">Cancel</button>
|
|
9984
|
-
* </ng-template>
|
|
9985
|
-
* ```
|
|
9986
|
-
*
|
|
9987
|
-
* Alternatively, the dialog supports the use of a custom footer. To provide a custom footer, add an Angular template to the HTML of the dialog component and
|
|
9988
|
-
* decorate it with the `wbDialogFooter` directive.
|
|
9989
|
-
*
|
|
9990
|
-
* ```html
|
|
9991
|
-
* <ng-template wbDialogFooter>
|
|
9992
|
-
* <app-dialog-footer/>
|
|
9993
|
-
* </ng-template>
|
|
9994
|
-
* ```
|
|
9995
|
-
*
|
|
9996
|
-
* ## Styling
|
|
9997
|
-
* The following CSS variables can be set to customize the default look of a dialog.
|
|
9998
|
-
*
|
|
9999
|
-
* - `--sci-workbench-dialog-padding`
|
|
10000
|
-
* - `--sci-workbench-dialog-header-height`
|
|
10001
|
-
* - `--sci-workbench-dialog-header-background-color`
|
|
10002
|
-
* - `--sci-workbench-dialog-title-font-family`
|
|
10003
|
-
* - `--sci-workbench-dialog-title-font-weight`
|
|
10004
|
-
* - `--sci-workbench-dialog-title-font-size`
|
|
10005
|
-
* - `--sci-workbench-dialog-title-align`
|
|
9929
|
+
* Provides {@link WorkbenchDialogService} for dependency injection.
|
|
10006
9930
|
*/
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
9931
|
+
function provideWorkbenchDialogService() {
|
|
9932
|
+
return [
|
|
9933
|
+
ɵWorkbenchDialogService,
|
|
9934
|
+
{ provide: WorkbenchDialogService, useExisting: ɵWorkbenchDialogService },
|
|
9935
|
+
];
|
|
10010
9936
|
}
|
|
10011
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogService, decorators: [{
|
|
10012
|
-
type: Injectable,
|
|
10013
|
-
args: [{ providedIn: 'root', useExisting: ɵWorkbenchDialogService }]
|
|
10014
|
-
}] });
|
|
10015
9937
|
|
|
10016
9938
|
/*
|
|
10017
|
-
* Copyright (c) 2018-
|
|
9939
|
+
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
10018
9940
|
*
|
|
10019
9941
|
* This program and the accompanying materials are made
|
|
10020
9942
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -10022,95 +9944,87 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
10022
9944
|
*
|
|
10023
9945
|
* SPDX-License-Identifier: EPL-2.0
|
|
10024
9946
|
*/
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
9947
|
+
/**
|
|
9948
|
+
* Renders the content of a workbench popup.
|
|
9949
|
+
*/
|
|
9950
|
+
class WorkbenchPopupComponent {
|
|
9951
|
+
_host = inject(ElementRef).nativeElement;
|
|
9952
|
+
_cdkTrapFocus = viewChild.required('focus_trap', { read: CdkTrapFocus });
|
|
9953
|
+
popup = inject(ɵWorkbenchPopup);
|
|
10031
9954
|
constructor() {
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
insertionSortOrderFn = () => 0;
|
|
10035
|
-
onAction(key) {
|
|
10036
|
-
this.action.emit(key);
|
|
10037
|
-
}
|
|
10038
|
-
onArrowKey(index, direction) {
|
|
10039
|
-
const actionButtonCount = this._actionButtons().length;
|
|
10040
|
-
const newIndex = (direction === 'left' ? index - 1 : index + 1);
|
|
10041
|
-
this._actionButtons()[(newIndex + actionButtonCount) % actionButtonCount].nativeElement.focus();
|
|
9955
|
+
trackFocus(this._host, this.popup);
|
|
9956
|
+
this.focusInitialElement();
|
|
10042
9957
|
}
|
|
10043
|
-
|
|
10044
|
-
const
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
//
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
}
|
|
9958
|
+
focusInitialElement() {
|
|
9959
|
+
const effectRef = effect(() => {
|
|
9960
|
+
// [Angular 14] The initial focus must not be requested via `cdkTrapFocusAutoCapture` as this would restore
|
|
9961
|
+
// focus to the previously focused element when the `FocusTrap` is destroyed. This behavior is unwanted if the
|
|
9962
|
+
// popup is closed by losing focus. Otherwise, the newly focused element that caused the loss of focus and thus
|
|
9963
|
+
// the closing of the popup would immediately become unfocused again. This behavior could only be observed when
|
|
9964
|
+
// the popup loses focus by clicking on an element in a microfrontend.
|
|
9965
|
+
void this._cdkTrapFocus().focusTrap.focusInitialElementWhenReady();
|
|
9966
|
+
effectRef.destroy();
|
|
9967
|
+
}, { ...(ngDevMode ? { debugName: "effectRef" } : {}) });
|
|
10054
9968
|
}
|
|
10055
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
10056
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
9969
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9970
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.1", type: WorkbenchPopupComponent, isStandalone: true, selector: "wb-popup", host: { properties: { "attr.data-popupid": "popup.id", "style.width": "popup.size.width()", "style.min-width": "popup.size.minWidth()", "style.max-width": "popup.size.maxWidth()", "style.height": "popup.size.height()", "style.min-height": "popup.size.minHeight()", "style.max-height": "popup.size.maxHeight()", "class": "popup.cssClass()" } }, providers: [
|
|
9971
|
+
configurePopupGlassPane(),
|
|
9972
|
+
], viewQueries: [{ propertyName: "_cdkTrapFocus", first: true, predicate: ["focus_trap"], descendants: true, read: CdkTrapFocus, isSignal: true }], hostDirectives: [{ directive: GlassPaneDirective }], ngImport: i0, template: "<sci-viewport cdkTrapFocus class=\"e2e-popup-viewport\" #focus_trap>\n <ng-container *ngComponentOutlet=\"popup.component; inputs: popup.inputs\"/>\n</sci-viewport>\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;outline:none;border-radius:var(--sci-corner);overflow:hidden}\n"], dependencies: [{ kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: SciViewportComponent, selector: "sci-viewport", inputs: ["scrollbarStyle"], outputs: ["scroll"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }] });
|
|
10057
9973
|
}
|
|
10058
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
9974
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchPopupComponent, decorators: [{
|
|
10059
9975
|
type: Component,
|
|
10060
|
-
args: [{ selector: 'wb-
|
|
10061
|
-
|
|
10062
|
-
|
|
9976
|
+
args: [{ selector: 'wb-popup', imports: [
|
|
9977
|
+
CdkTrapFocus,
|
|
9978
|
+
SciViewportComponent,
|
|
9979
|
+
NgComponentOutlet,
|
|
9980
|
+
], hostDirectives: [
|
|
9981
|
+
GlassPaneDirective,
|
|
9982
|
+
], providers: [
|
|
9983
|
+
configurePopupGlassPane(),
|
|
10063
9984
|
], host: {
|
|
10064
|
-
'[attr.data-
|
|
10065
|
-
|
|
10066
|
-
|
|
9985
|
+
'[attr.data-popupid]': 'popup.id',
|
|
9986
|
+
'[style.width]': 'popup.size.width()',
|
|
9987
|
+
'[style.min-width]': 'popup.size.minWidth()',
|
|
9988
|
+
'[style.max-width]': 'popup.size.maxWidth()',
|
|
9989
|
+
'[style.height]': 'popup.size.height()',
|
|
9990
|
+
'[style.min-height]': 'popup.size.minHeight()',
|
|
9991
|
+
'[style.max-height]': 'popup.size.maxHeight()',
|
|
9992
|
+
'[class]': 'popup.cssClass()',
|
|
9993
|
+
}, template: "<sci-viewport cdkTrapFocus class=\"e2e-popup-viewport\" #focus_trap>\n <ng-container *ngComponentOutlet=\"popup.component; inputs: popup.inputs\"/>\n</sci-viewport>\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;outline:none;border-radius:var(--sci-corner);overflow:hidden}\n"] }]
|
|
9994
|
+
}], ctorParameters: () => [], propDecorators: { _cdkTrapFocus: [{ type: i0.ViewChild, args: ['focus_trap', { ...{ read: CdkTrapFocus }, isSignal: true }] }] } });
|
|
9995
|
+
/**
|
|
9996
|
+
* Blocks this popup when dialog(s) overlay it.
|
|
9997
|
+
*/
|
|
9998
|
+
function configurePopupGlassPane() {
|
|
9999
|
+
return [
|
|
10000
|
+
{
|
|
10001
|
+
provide: GLASS_PANE_BLOCKABLE,
|
|
10002
|
+
useFactory: () => inject(ɵWorkbenchPopup),
|
|
10003
|
+
},
|
|
10004
|
+
{
|
|
10005
|
+
provide: GLASS_PANE_OPTIONS,
|
|
10006
|
+
useFactory: () => ({ attributes: { 'data-popupid': inject(ɵWorkbenchPopup).id } }),
|
|
10007
|
+
},
|
|
10008
|
+
];
|
|
10009
|
+
}
|
|
10067
10010
|
|
|
10068
|
-
|
|
10069
|
-
*
|
|
10011
|
+
/**
|
|
10012
|
+
* A popup is a visual workbench element for displaying content above other content. The popup is positioned relative
|
|
10013
|
+
* to an anchor based on its preferred alignment. The anchor can be an element or a coordinate.
|
|
10070
10014
|
*
|
|
10071
|
-
*
|
|
10072
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10073
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10015
|
+
* The popup component can inject this handle to interact with the popup.
|
|
10074
10016
|
*
|
|
10075
|
-
*
|
|
10076
|
-
*/
|
|
10077
|
-
/**
|
|
10078
|
-
* Use this directive to replace the default dialog footer that renders actions contributed via the {@link WorkbenchDialogActionDirective} directive.
|
|
10017
|
+
* Popup inputs are available as input properties in the popup component.
|
|
10079
10018
|
*
|
|
10080
|
-
*
|
|
10019
|
+
* @see WorkbenchPopupService
|
|
10081
10020
|
*
|
|
10082
|
-
*
|
|
10083
|
-
* ```html
|
|
10084
|
-
* <ng-template wbDialogFooter>
|
|
10085
|
-
* <app-dialog-footer/>
|
|
10086
|
-
* </ng-template>
|
|
10087
|
-
* ```
|
|
10021
|
+
* @deprecated since version 21.0.0-beta.1. Replaced by `WorkbenchPopup`. Marked for removal in version 22.
|
|
10088
10022
|
*/
|
|
10089
|
-
class
|
|
10090
|
-
/**
|
|
10091
|
-
* Specifies if to display a visual separator between the dialog content and this footer.
|
|
10092
|
-
* Defaults to `true`.
|
|
10093
|
-
*/
|
|
10094
|
-
divider = input(undefined, { ...(ngDevMode ? { debugName: "divider" } : {}), transform: booleanAttribute });
|
|
10095
|
-
template = inject(TemplateRef);
|
|
10096
|
-
_footer;
|
|
10097
|
-
constructor() {
|
|
10098
|
-
const dialog = inject(ɵWorkbenchDialog);
|
|
10099
|
-
// Defer registering footer to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
10100
|
-
asapScheduler.schedule(() => this._footer = dialog.registerFooter(this));
|
|
10101
|
-
// Defer disposing footer to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
10102
|
-
inject(DestroyRef).onDestroy(() => asapScheduler.schedule(() => this._footer?.dispose()));
|
|
10103
|
-
}
|
|
10104
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
10105
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.1", type: WorkbenchDialogFooterDirective, isStandalone: true, selector: "ng-template[wbDialogFooter]", inputs: { divider: { classPropertyName: "divider", publicName: "divider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
10023
|
+
class Popup extends WorkbenchPopup {
|
|
10106
10024
|
}
|
|
10107
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogFooterDirective, decorators: [{
|
|
10108
|
-
type: Directive,
|
|
10109
|
-
args: [{ selector: 'ng-template[wbDialogFooter]' }]
|
|
10110
|
-
}], ctorParameters: () => [], propDecorators: { divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }] } });
|
|
10111
10025
|
|
|
10112
10026
|
/*
|
|
10113
|
-
* Copyright (c) 2018-
|
|
10027
|
+
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10114
10028
|
*
|
|
10115
10029
|
* This program and the accompanying materials are made
|
|
10116
10030
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -10119,90 +10033,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
10119
10033
|
* SPDX-License-Identifier: EPL-2.0
|
|
10120
10034
|
*/
|
|
10121
10035
|
/**
|
|
10122
|
-
*
|
|
10123
|
-
*
|
|
10124
|
-
* The host element of this modeling directive must be a <ng-template>. The header shares the lifecycle of the host element.
|
|
10125
|
-
*
|
|
10126
|
-
* **Example:**
|
|
10127
|
-
* ```html
|
|
10128
|
-
* <ng-template wbDialogHeader>
|
|
10129
|
-
* <app-dialog-header/>
|
|
10130
|
-
* </ng-template>
|
|
10131
|
-
* ```
|
|
10132
|
-
*/
|
|
10133
|
-
class WorkbenchDialogHeaderDirective {
|
|
10134
|
-
/**
|
|
10135
|
-
* Specifies if to display a visual separator between this header and the dialog content.
|
|
10136
|
-
* Defaults to `true`.
|
|
10137
|
-
*/
|
|
10138
|
-
divider = input(undefined, { ...(ngDevMode ? { debugName: "divider" } : {}), transform: booleanAttribute });
|
|
10139
|
-
template = inject(TemplateRef);
|
|
10140
|
-
_header;
|
|
10141
|
-
constructor() {
|
|
10142
|
-
const dialog = inject(ɵWorkbenchDialog);
|
|
10143
|
-
// Defer registering header to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
10144
|
-
asapScheduler.schedule(() => this._header = dialog.registerHeader(this));
|
|
10145
|
-
// Defer disposing header to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
10146
|
-
inject(DestroyRef).onDestroy(() => asapScheduler.schedule(() => this._header?.dispose()));
|
|
10147
|
-
}
|
|
10148
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
10149
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.1", type: WorkbenchDialogHeaderDirective, isStandalone: true, selector: "ng-template[wbDialogHeader]", inputs: { divider: { classPropertyName: "divider", publicName: "divider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
10150
|
-
}
|
|
10151
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogHeaderDirective, decorators: [{
|
|
10152
|
-
type: Directive,
|
|
10153
|
-
args: [{ selector: 'ng-template[wbDialogHeader]' }]
|
|
10154
|
-
}], ctorParameters: () => [], propDecorators: { divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }] } });
|
|
10155
|
-
|
|
10156
|
-
/*
|
|
10157
|
-
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
10158
|
-
*
|
|
10159
|
-
* This program and the accompanying materials are made
|
|
10160
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10161
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10162
|
-
*
|
|
10163
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10164
|
-
*/
|
|
10165
|
-
class MessageBoxHeaderComponent {
|
|
10166
|
-
title = input(undefined, { ...(ngDevMode ? { debugName: "title" } : {}) });
|
|
10167
|
-
severity = input.required({ ...(ngDevMode ? { debugName: "severity" } : {}) });
|
|
10168
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10169
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MessageBoxHeaderComponent, isStandalone: true, selector: "wb-message-box-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, severity: { classPropertyName: "severity", publicName: "severity", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-severity": "severity()" } }, ngImport: i0, template: "@if (title()) {\n <span class=\"title e2e-title\">{{(title() | wbText)()}}</span>\n}\n", styles: ["@charset \"UTF-8\";:host{--\\275message-box-severity-color: initial;display:grid;border-top:var(--sci-workbench-messagebox-severity-indicator-size) solid var(--\\275message-box-severity-color);padding-inline:var(--sci-workbench-messagebox-padding);padding-top:var(--sci-workbench-messagebox-padding);-webkit-user-select:none;user-select:none}:host[data-severity=info]{--\\275message-box-severity-color: var(--sci-color-accent)}:host[data-severity=warn]{--\\275message-box-severity-color: var(--sci-color-notice)}:host[data-severity=error]{--\\275message-box-severity-color: var(--sci-color-negative)}:host>span.title{word-break:break-word;white-space:pre-line;font-family:var(--sci-workbench-messagebox-title-font-family),sans-serif;font-size:var(--sci-workbench-messagebox-title-font-size);font-weight:var(--sci-workbench-messagebox-title-font-weight);text-align:var(--sci-workbench-messagebox-title-align)}\n"], dependencies: [{ kind: "pipe", type: TextPipe, name: "wbText" }] });
|
|
10170
|
-
}
|
|
10171
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxHeaderComponent, decorators: [{
|
|
10172
|
-
type: Component,
|
|
10173
|
-
args: [{ selector: 'wb-message-box-header', imports: [
|
|
10174
|
-
TextPipe,
|
|
10175
|
-
], host: {
|
|
10176
|
-
'[attr.data-severity]': 'severity()',
|
|
10177
|
-
}, template: "@if (title()) {\n <span class=\"title e2e-title\">{{(title() | wbText)()}}</span>\n}\n", styles: ["@charset \"UTF-8\";:host{--\\275message-box-severity-color: initial;display:grid;border-top:var(--sci-workbench-messagebox-severity-indicator-size) solid var(--\\275message-box-severity-color);padding-inline:var(--sci-workbench-messagebox-padding);padding-top:var(--sci-workbench-messagebox-padding);-webkit-user-select:none;user-select:none}:host[data-severity=info]{--\\275message-box-severity-color: var(--sci-color-accent)}:host[data-severity=warn]{--\\275message-box-severity-color: var(--sci-color-notice)}:host[data-severity=error]{--\\275message-box-severity-color: var(--sci-color-negative)}:host>span.title{word-break:break-word;white-space:pre-line;font-family:var(--sci-workbench-messagebox-title-font-family),sans-serif;font-size:var(--sci-workbench-messagebox-title-font-size);font-weight:var(--sci-workbench-messagebox-title-font-weight);text-align:var(--sci-workbench-messagebox-title-align)}\n"] }]
|
|
10178
|
-
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], severity: [{ type: i0.Input, args: [{ isSignal: true, alias: "severity", required: true }] }] } });
|
|
10179
|
-
|
|
10180
|
-
/*
|
|
10181
|
-
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
10182
|
-
*
|
|
10183
|
-
* This program and the accompanying materials are made
|
|
10184
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10185
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10186
|
-
*
|
|
10187
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10036
|
+
* DI token to register providers available for DI if in the context of a workbench popup.
|
|
10188
10037
|
*/
|
|
10038
|
+
const WORKBENCH_POPUP_CONTEXT = new InjectionToken('WORKBENCH_POPUP_CONTEXT');
|
|
10189
10039
|
/**
|
|
10190
|
-
*
|
|
10040
|
+
* Provides providers available for DI if in the context of a workbench popup.
|
|
10191
10041
|
*/
|
|
10192
|
-
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10042
|
+
function provideWorkbenchPopupContext() {
|
|
10043
|
+
return {
|
|
10044
|
+
provide: WORKBENCH_POPUP_CONTEXT,
|
|
10045
|
+
useFactory: () => [
|
|
10046
|
+
provideWorkbenchDialogService(),
|
|
10047
|
+
provideWorkbenchMessageBoxService(),
|
|
10048
|
+
provideWorkbenchPopupService(),
|
|
10049
|
+
],
|
|
10050
|
+
multi: true,
|
|
10051
|
+
};
|
|
10198
10052
|
}
|
|
10199
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: TypeofPipe, decorators: [{
|
|
10200
|
-
type: Pipe,
|
|
10201
|
-
args: [{ name: 'wbTypeof' }]
|
|
10202
|
-
}] });
|
|
10203
10053
|
|
|
10204
10054
|
/*
|
|
10205
|
-
* Copyright (c) 2018-
|
|
10055
|
+
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10206
10056
|
*
|
|
10207
10057
|
* This program and the accompanying materials are made
|
|
10208
10058
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -10210,453 +10060,166 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
10210
10060
|
*
|
|
10211
10061
|
* SPDX-License-Identifier: EPL-2.0
|
|
10212
10062
|
*/
|
|
10213
|
-
/**
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10063
|
+
/** @inheritDoc */
|
|
10064
|
+
class ɵWorkbenchPopup {
|
|
10065
|
+
id;
|
|
10066
|
+
component;
|
|
10067
|
+
invocationContext;
|
|
10068
|
+
_options;
|
|
10069
|
+
/** Injector for the popup; destroyed when the popup is closed. */
|
|
10070
|
+
injector = inject(Injector);
|
|
10071
|
+
_overlayRef;
|
|
10072
|
+
_focusMonitor = inject(WorkbenchFocusMonitor);
|
|
10073
|
+
_portal;
|
|
10074
|
+
_componentRef = signal(undefined, { ...(ngDevMode ? { debugName: "_componentRef" } : {}) });
|
|
10075
|
+
_popupOrigin;
|
|
10076
|
+
_cssClass = signal([], { ...(ngDevMode ? { debugName: "_cssClass" } : {}) });
|
|
10077
|
+
size;
|
|
10078
|
+
focused = computed(() => this._focusMonitor.activeElement()?.id === this.id, { ...(ngDevMode ? { debugName: "focused" } : {}) });
|
|
10079
|
+
attached;
|
|
10080
|
+
destroyed = signal(false, { ...(ngDevMode ? { debugName: "destroyed" } : {}) });
|
|
10081
|
+
bounds = boundingClientRect(computed(() => this._componentRef()?.location.nativeElement));
|
|
10082
|
+
blockedBy;
|
|
10083
|
+
// TODO [Angular 22] Remove with Angular 22. Used for backward compatiblity.
|
|
10084
|
+
input;
|
|
10085
|
+
result;
|
|
10086
|
+
constructor(id, component, invocationContext, _options) {
|
|
10087
|
+
this.id = id;
|
|
10088
|
+
this.component = component;
|
|
10089
|
+
this.invocationContext = invocationContext;
|
|
10090
|
+
this._options = _options;
|
|
10091
|
+
this._portal = this.createPortal();
|
|
10092
|
+
this.input = this._portal.injector?.get(LEGACY_POPUP_INPUT, undefined, { optional: true });
|
|
10093
|
+
this._popupOrigin = this.trackPopupOrigin();
|
|
10094
|
+
this._cssClass.set(Arrays.coerce(this._options.cssClass));
|
|
10095
|
+
this.size = new ɵWorkbenchPopupSize(this._options);
|
|
10096
|
+
this.blockedBy = inject(WorkbenchDialogRegistry).top(this.id);
|
|
10097
|
+
this.attached = this.monitorHostElementAttached();
|
|
10098
|
+
const positionStrategy = inject(Overlay).position()
|
|
10099
|
+
.flexibleConnectedTo({ x: 0, y: 0 })
|
|
10100
|
+
.withFlexibleDimensions(false)
|
|
10101
|
+
.withLockedPosition(false) // If locked, the popup won't attempt to reposition itself if not enough space available.
|
|
10102
|
+
.withPositions((() => {
|
|
10103
|
+
switch (this._options.align ?? 'north') {
|
|
10104
|
+
case 'north':
|
|
10105
|
+
return [NORTH, SOUTH, WEST, EAST];
|
|
10106
|
+
case 'south':
|
|
10107
|
+
return [SOUTH, NORTH, WEST, EAST];
|
|
10108
|
+
case 'west':
|
|
10109
|
+
return [WEST, EAST, NORTH, SOUTH];
|
|
10110
|
+
case 'east':
|
|
10111
|
+
return [EAST, WEST, NORTH, SOUTH];
|
|
10112
|
+
default:
|
|
10113
|
+
throw Error('[PopupPositionError] Illegal position; must be north, south, west or east');
|
|
10231
10114
|
}
|
|
10115
|
+
})());
|
|
10116
|
+
this._overlayRef = this.createOverlay(positionStrategy);
|
|
10117
|
+
const componentRef = this._overlayRef.attach(this._portal);
|
|
10118
|
+
const popupElement = componentRef.location.nativeElement;
|
|
10119
|
+
this._componentRef.set(componentRef);
|
|
10120
|
+
// Make the popup focusable to request focus.
|
|
10121
|
+
popupElement.setAttribute('tabindex', '-1');
|
|
10122
|
+
this.stickToAnchor(positionStrategy);
|
|
10123
|
+
this.repositionOnResize();
|
|
10124
|
+
this.bindToHostElement(popupElement);
|
|
10125
|
+
this.closeOnHostDestroy();
|
|
10126
|
+
this.closeOnFocusLoss(popupElement);
|
|
10127
|
+
this.closeOnEscape(popupElement);
|
|
10128
|
+
inject(DestroyRef).onDestroy(() => this.destroyed.set(true));
|
|
10129
|
+
}
|
|
10130
|
+
/**
|
|
10131
|
+
* Waits for the popup to close, resolving to its result or rejecting if closed with an error.
|
|
10132
|
+
*/
|
|
10133
|
+
waitForClose() {
|
|
10134
|
+
return new Promise((resolve, reject) => {
|
|
10135
|
+
this.injector.get(DestroyRef).onDestroy(() => {
|
|
10136
|
+
this.result instanceof Error ? reject(this.result) : resolve(this.result);
|
|
10137
|
+
});
|
|
10232
10138
|
});
|
|
10233
10139
|
}
|
|
10234
|
-
|
|
10235
|
-
|
|
10140
|
+
/**
|
|
10141
|
+
* Creates a portal to render {@link WorkbenchPopupComponent} in the popup's injection context.
|
|
10142
|
+
*/
|
|
10143
|
+
createPortal() {
|
|
10144
|
+
const injector = Injector.create({
|
|
10145
|
+
parent: this._options.injector ?? inject(Injector),
|
|
10146
|
+
providers: [
|
|
10147
|
+
{ provide: ɵWorkbenchPopup, useValue: this },
|
|
10148
|
+
{ provide: WorkbenchPopup, useExisting: ɵWorkbenchPopup },
|
|
10149
|
+
{ provide: Popup, useExisting: ɵWorkbenchPopup },
|
|
10150
|
+
{ provide: WORKBENCH_ELEMENT, useExisting: ɵWorkbenchPopup },
|
|
10151
|
+
inject(WORKBENCH_POPUP_CONTEXT, { optional: true }) ?? [],
|
|
10152
|
+
this._options.providers ?? [],
|
|
10153
|
+
],
|
|
10154
|
+
});
|
|
10155
|
+
inject(DestroyRef).onDestroy(() => injector.destroy());
|
|
10156
|
+
return new ComponentPortal(WorkbenchPopupComponent, null, injector);
|
|
10236
10157
|
}
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
|
|
10158
|
+
/**
|
|
10159
|
+
* Creates a dedicated overlay per popup to place it on top of previously created overlays, such as dialogs, popups, dropdowns, etc.
|
|
10160
|
+
*/
|
|
10161
|
+
createOverlay(positionStrategy) {
|
|
10162
|
+
return inject(Overlay).create({
|
|
10163
|
+
panelClass: 'wb-popup',
|
|
10164
|
+
hasBackdrop: false,
|
|
10165
|
+
positionStrategy: positionStrategy,
|
|
10166
|
+
scrollStrategy: inject(Overlay).scrollStrategies.noop(),
|
|
10167
|
+
disposeOnNavigation: true,
|
|
10168
|
+
});
|
|
10169
|
+
}
|
|
10170
|
+
/**
|
|
10171
|
+
* Moves the popup with the anchor.
|
|
10172
|
+
*/
|
|
10173
|
+
stickToAnchor(positionStrategy) {
|
|
10174
|
+
effect(() => {
|
|
10175
|
+
const origin = this._popupOrigin();
|
|
10176
|
+
untracked(() => {
|
|
10177
|
+
if (origin) {
|
|
10178
|
+
positionStrategy.setOrigin(origin);
|
|
10179
|
+
this._overlayRef.updatePosition();
|
|
10180
|
+
}
|
|
10181
|
+
});
|
|
10182
|
+
});
|
|
10183
|
+
}
|
|
10184
|
+
/**
|
|
10185
|
+
* Monitors attachment of the host element.
|
|
10186
|
+
*/
|
|
10187
|
+
monitorHostElementAttached() {
|
|
10188
|
+
if (this.invocationContext) {
|
|
10189
|
+
return this.invocationContext.attached;
|
|
10240
10190
|
}
|
|
10191
|
+
const workbenchComponentRef = inject(WORKBENCH_COMPONENT_REF);
|
|
10192
|
+
return computed(() => !!workbenchComponentRef());
|
|
10241
10193
|
}
|
|
10242
|
-
|
|
10243
|
-
|
|
10194
|
+
/**
|
|
10195
|
+
* Repositions the popup position when resized.
|
|
10196
|
+
*/
|
|
10197
|
+
repositionOnResize() {
|
|
10198
|
+
const zone = inject(NgZone);
|
|
10199
|
+
fromResize$(this._overlayRef.overlayElement)
|
|
10200
|
+
.pipe(observeIn(fn => zone.run(fn)), takeUntilDestroyed())
|
|
10201
|
+
.subscribe(() => {
|
|
10202
|
+
this._overlayRef.updatePosition();
|
|
10203
|
+
});
|
|
10244
10204
|
}
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
// Ensure host element to be focusable in order to close the message box on Escape keystroke.
|
|
10264
|
-
'[attr.tabindex]': '-1',
|
|
10265
|
-
'[class.empty]': 'empty()',
|
|
10266
|
-
'[class.content-selectable]': 'options()?.contentSelectable',
|
|
10267
|
-
'[class.has-title]': '!!this.options()?.title',
|
|
10268
|
-
'(keydown.escape)': 'onEscape()',
|
|
10269
|
-
}, template: "@let options = this.options() ?? {};\n<ng-template wbDialogHeader [divider]=\"false\">\n <wb-message-box-header [title]=\"options.title\" [severity]=\"options.severity ?? 'info'\"/>\n</ng-template>\n\n@let message = this.message();\n<div class=\"message e2e-message\" [class.text]=\"message | wbTypeof:'string'\" sciDimension (sciDimensionChange)=\"onContentDimensionChange($event)\">\n @if (message | wbTypeof:'string') {\n {{($any(message) | wbText)()}}\n } @else {\n <ng-container *ngComponentOutlet=\"message; inputs: options.inputs\"/>\n }\n</div>\n\n<ng-template wbDialogFooter>\n <wb-message-box-footer [actions]=\"options.actions ?? {ok: '%workbench.ok.action'}\"\n [severity]=\"options.severity ?? 'info'\"\n (action)=\"onAction($event)\"\n (keydown.escape)=\"onEscape()\"\n (preferredSizeChange)=\"onFooterPreferredSizeChange($event)\"/>\n</ng-template>\n", styles: [":host{display:grid;outline:none;padding-inline:var(--sci-workbench-messagebox-padding);padding-bottom:var(--sci-workbench-messagebox-padding)}:host.has-title:not(.empty){padding-top:var(--sci-workbench-messagebox-padding)}:host:not(.content-selectable){-webkit-user-select:none;user-select:none}:host>div.message.text{word-break:break-word;white-space:pre-line;text-align:var(--sci-workbench-messagebox-text-align)}\n"] }]
|
|
10270
|
-
}], ctorParameters: () => [], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }] } });
|
|
10271
|
-
function nullIfEmptyMessage(message) {
|
|
10272
|
-
return message !== '' ? message : null;
|
|
10273
|
-
}
|
|
10274
|
-
|
|
10275
|
-
/**
|
|
10276
|
-
* Provides a standardized dialog for presenting a message to the user, such as an info, warning or alert,
|
|
10277
|
-
* or for prompting the user for confirmation. The message can be plain text or a component, allowing for
|
|
10278
|
-
* structured content or input prompts.
|
|
10279
|
-
*
|
|
10280
|
-
* Displayed on top of other content, a modal message box blocks interaction with other parts of the application.
|
|
10281
|
-
*
|
|
10282
|
-
* ## Modality
|
|
10283
|
-
* A message box can be context-modal or application-modal. Context-modal blocks a specific part of the application, as specified by the context;
|
|
10284
|
-
* application-modal blocks the workbench or browser viewport, based on {@link WorkbenchConfig.dialog.modalityScope}.
|
|
10285
|
-
*
|
|
10286
|
-
* ## Context
|
|
10287
|
-
* A message box can be bound to a context (e.g., part or view), defaulting to the calling context.
|
|
10288
|
-
* The message box is displayed only if the context is visible and closes when the context is disposed.
|
|
10289
|
-
*
|
|
10290
|
-
* ## Positioning
|
|
10291
|
-
* A message box is opened in the center of its context, if any, unless opened from the peripheral area.
|
|
10292
|
-
*
|
|
10293
|
-
* ## Stacking
|
|
10294
|
-
* Message boxes are stacked per modality, with only the topmost message box in each stack being interactive.
|
|
10295
|
-
*
|
|
10296
|
-
* ## Styling
|
|
10297
|
-
* The following CSS variables can be set to customize the default look of a message box.
|
|
10298
|
-
*
|
|
10299
|
-
* - `--sci-workbench-messagebox-max-width`
|
|
10300
|
-
* - `--sci-workbench-messagebox-severity-indicator-size`
|
|
10301
|
-
* - `--sci-workbench-messagebox-padding`
|
|
10302
|
-
* - `--sci-workbench-messagebox-text-align`
|
|
10303
|
-
* - `--sci-workbench-messagebox-title-align`
|
|
10304
|
-
* - `--sci-workbench-messagebox-title-font-family`
|
|
10305
|
-
* - `--sci-workbench-messagebox-title-font-weight`
|
|
10306
|
-
* - `--sci-workbench-messagebox-title-font-size`
|
|
10307
|
-
*/
|
|
10308
|
-
class WorkbenchMessageBoxService {
|
|
10309
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10310
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, providedIn: 'root', useExisting: ɵWorkbenchMessageBoxService });
|
|
10311
|
-
}
|
|
10312
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, decorators: [{
|
|
10313
|
-
type: Injectable,
|
|
10314
|
-
args: [{ providedIn: 'root', useExisting: ɵWorkbenchMessageBoxService }]
|
|
10315
|
-
}] });
|
|
10316
|
-
|
|
10317
|
-
/*
|
|
10318
|
-
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
10319
|
-
*
|
|
10320
|
-
* This program and the accompanying materials are made
|
|
10321
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10322
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10323
|
-
*
|
|
10324
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10325
|
-
*/
|
|
10326
|
-
/** @inheritDoc */
|
|
10327
|
-
class ɵWorkbenchMessageBoxService {
|
|
10328
|
-
_workbenchDialogService = inject(WorkbenchDialogService);
|
|
10329
|
-
_zone = inject(NgZone);
|
|
10330
|
-
constructor() {
|
|
10331
|
-
this.installServiceLifecycleLogger();
|
|
10332
|
-
}
|
|
10333
|
-
/**
|
|
10334
|
-
* @inheritDoc
|
|
10335
|
-
*/
|
|
10336
|
-
async open(message, options) {
|
|
10337
|
-
assertNotInReactiveContext(this.open, 'Call WorkbenchMessageBoxService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
10338
|
-
// Ensure to run in Angular zone to display the message box even if called from outside the Angular zone, e.g. from an error handler.
|
|
10339
|
-
if (!NgZone.isInAngularZone()) {
|
|
10340
|
-
return this._zone.run(() => this.open(message, options));
|
|
10341
|
-
}
|
|
10342
|
-
return (await this._workbenchDialogService.open(WorkbenchMessageBoxComponent, {
|
|
10343
|
-
inputs: { message, options },
|
|
10344
|
-
modality: options?.modality,
|
|
10345
|
-
injector: options?.injector,
|
|
10346
|
-
providers: options?.providers,
|
|
10347
|
-
cssClass: options?.cssClass,
|
|
10348
|
-
context: options?.context,
|
|
10349
|
-
animate: true,
|
|
10350
|
-
}));
|
|
10351
|
-
}
|
|
10352
|
-
installServiceLifecycleLogger() {
|
|
10353
|
-
const logger = inject(Logger);
|
|
10354
|
-
const workbenchElement = inject(WORKBENCH_ELEMENT, { optional: true });
|
|
10355
|
-
logger.debug(() => `Constructing WorkbenchMessageBoxService [context=${workbenchElement?.id}]`, LoggerNames.LIFECYCLE);
|
|
10356
|
-
inject(DestroyRef).onDestroy(() => logger.debug(() => `Destroying WorkbenchMessageBoxService [context=${workbenchElement?.id}]'`, LoggerNames.LIFECYCLE));
|
|
10357
|
-
}
|
|
10358
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10359
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, providedIn: 'root' });
|
|
10360
|
-
}
|
|
10361
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, decorators: [{
|
|
10362
|
-
type: Injectable,
|
|
10363
|
-
args: [{ providedIn: 'root' }]
|
|
10364
|
-
}], ctorParameters: () => [] });
|
|
10365
|
-
/**
|
|
10366
|
-
* Provides {@link WorkbenchDialogService} for dependency injection.
|
|
10367
|
-
*/
|
|
10368
|
-
function provideWorkbenchMessageBoxService() {
|
|
10369
|
-
return [
|
|
10370
|
-
ɵWorkbenchMessageBoxService,
|
|
10371
|
-
{ provide: WorkbenchMessageBoxService, useExisting: ɵWorkbenchMessageBoxService },
|
|
10372
|
-
];
|
|
10373
|
-
}
|
|
10374
|
-
|
|
10375
|
-
/*
|
|
10376
|
-
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
10377
|
-
*
|
|
10378
|
-
* This program and the accompanying materials are made
|
|
10379
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10380
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10381
|
-
*
|
|
10382
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10383
|
-
*/
|
|
10384
|
-
/**
|
|
10385
|
-
* Renders the content of a workbench popup.
|
|
10386
|
-
*/
|
|
10387
|
-
class WorkbenchPopupComponent {
|
|
10388
|
-
_host = inject(ElementRef).nativeElement;
|
|
10389
|
-
_cdkTrapFocus = viewChild.required('focus_trap', { read: CdkTrapFocus });
|
|
10390
|
-
popup = inject(ɵWorkbenchPopup);
|
|
10391
|
-
constructor() {
|
|
10392
|
-
trackFocus(this._host, this.popup);
|
|
10393
|
-
this.focusInitialElement();
|
|
10394
|
-
}
|
|
10395
|
-
focusInitialElement() {
|
|
10396
|
-
const effectRef = effect(() => {
|
|
10397
|
-
// [Angular 14] The initial focus must not be requested via `cdkTrapFocusAutoCapture` as this would restore
|
|
10398
|
-
// focus to the previously focused element when the `FocusTrap` is destroyed. This behavior is unwanted if the
|
|
10399
|
-
// popup is closed by losing focus. Otherwise, the newly focused element that caused the loss of focus and thus
|
|
10400
|
-
// the closing of the popup would immediately become unfocused again. This behavior could only be observed when
|
|
10401
|
-
// the popup loses focus by clicking on an element in a microfrontend.
|
|
10402
|
-
void this._cdkTrapFocus().focusTrap.focusInitialElementWhenReady();
|
|
10403
|
-
effectRef.destroy();
|
|
10404
|
-
}, { ...(ngDevMode ? { debugName: "effectRef" } : {}) });
|
|
10405
|
-
}
|
|
10406
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10407
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.1", type: WorkbenchPopupComponent, isStandalone: true, selector: "wb-popup", host: { properties: { "attr.data-popupid": "popup.id", "style.width": "popup.size.width()", "style.min-width": "popup.size.minWidth()", "style.max-width": "popup.size.maxWidth()", "style.height": "popup.size.height()", "style.min-height": "popup.size.minHeight()", "style.max-height": "popup.size.maxHeight()", "class": "popup.cssClass()" } }, providers: [
|
|
10408
|
-
configurePopupGlassPane(),
|
|
10409
|
-
], viewQueries: [{ propertyName: "_cdkTrapFocus", first: true, predicate: ["focus_trap"], descendants: true, read: CdkTrapFocus, isSignal: true }], hostDirectives: [{ directive: GlassPaneDirective }], ngImport: i0, template: "<sci-viewport cdkTrapFocus class=\"e2e-popup-viewport\" #focus_trap>\n <ng-container *ngComponentOutlet=\"popup.component; inputs: popup.inputs\"/>\n</sci-viewport>\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;outline:none;border-radius:var(--sci-corner);overflow:hidden}\n"], dependencies: [{ kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: SciViewportComponent, selector: "sci-viewport", inputs: ["scrollbarStyle"], outputs: ["scroll"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }] });
|
|
10410
|
-
}
|
|
10411
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchPopupComponent, decorators: [{
|
|
10412
|
-
type: Component,
|
|
10413
|
-
args: [{ selector: 'wb-popup', imports: [
|
|
10414
|
-
CdkTrapFocus,
|
|
10415
|
-
SciViewportComponent,
|
|
10416
|
-
NgComponentOutlet,
|
|
10417
|
-
], hostDirectives: [
|
|
10418
|
-
GlassPaneDirective,
|
|
10419
|
-
], providers: [
|
|
10420
|
-
configurePopupGlassPane(),
|
|
10421
|
-
], host: {
|
|
10422
|
-
'[attr.data-popupid]': 'popup.id',
|
|
10423
|
-
'[style.width]': 'popup.size.width()',
|
|
10424
|
-
'[style.min-width]': 'popup.size.minWidth()',
|
|
10425
|
-
'[style.max-width]': 'popup.size.maxWidth()',
|
|
10426
|
-
'[style.height]': 'popup.size.height()',
|
|
10427
|
-
'[style.min-height]': 'popup.size.minHeight()',
|
|
10428
|
-
'[style.max-height]': 'popup.size.maxHeight()',
|
|
10429
|
-
'[class]': 'popup.cssClass()',
|
|
10430
|
-
}, template: "<sci-viewport cdkTrapFocus class=\"e2e-popup-viewport\" #focus_trap>\n <ng-container *ngComponentOutlet=\"popup.component; inputs: popup.inputs\"/>\n</sci-viewport>\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;outline:none;border-radius:var(--sci-corner);overflow:hidden}\n"] }]
|
|
10431
|
-
}], ctorParameters: () => [], propDecorators: { _cdkTrapFocus: [{ type: i0.ViewChild, args: ['focus_trap', { ...{ read: CdkTrapFocus }, isSignal: true }] }] } });
|
|
10432
|
-
/**
|
|
10433
|
-
* Blocks this popup when dialog(s) overlay it.
|
|
10434
|
-
*/
|
|
10435
|
-
function configurePopupGlassPane() {
|
|
10436
|
-
return [
|
|
10437
|
-
{
|
|
10438
|
-
provide: GLASS_PANE_BLOCKABLE,
|
|
10439
|
-
useFactory: () => inject(ɵWorkbenchPopup),
|
|
10440
|
-
},
|
|
10441
|
-
{
|
|
10442
|
-
provide: GLASS_PANE_OPTIONS,
|
|
10443
|
-
useFactory: () => ({ attributes: { 'data-popupid': inject(ɵWorkbenchPopup).id } }),
|
|
10444
|
-
},
|
|
10445
|
-
];
|
|
10446
|
-
}
|
|
10447
|
-
|
|
10448
|
-
/**
|
|
10449
|
-
* A popup is a visual workbench element for displaying content above other content. The popup is positioned relative
|
|
10450
|
-
* to an anchor based on its preferred alignment. The anchor can be an element or a coordinate.
|
|
10451
|
-
*
|
|
10452
|
-
* The popup component can inject this handle to interact with the popup.
|
|
10453
|
-
*
|
|
10454
|
-
* Popup inputs are available as input properties in the popup component.
|
|
10455
|
-
*
|
|
10456
|
-
* @see WorkbenchPopupService
|
|
10457
|
-
*
|
|
10458
|
-
* @deprecated since version 21.0.0-beta.1. Replaced by `WorkbenchPopup`. Marked for removal in version 22.
|
|
10459
|
-
*/
|
|
10460
|
-
class Popup extends WorkbenchPopup {
|
|
10461
|
-
}
|
|
10462
|
-
|
|
10463
|
-
/*
|
|
10464
|
-
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10465
|
-
*
|
|
10466
|
-
* This program and the accompanying materials are made
|
|
10467
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10468
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10469
|
-
*
|
|
10470
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10471
|
-
*/
|
|
10472
|
-
/**
|
|
10473
|
-
* DI token to register providers available for DI if in the context of a workbench popup.
|
|
10474
|
-
*/
|
|
10475
|
-
const WORKBENCH_POPUP_CONTEXT = new InjectionToken('WORKBENCH_POPUP_CONTEXT');
|
|
10476
|
-
/**
|
|
10477
|
-
* Provides providers available for DI if in the context of a workbench popup.
|
|
10478
|
-
*/
|
|
10479
|
-
function provideWorkbenchPopupContext() {
|
|
10480
|
-
return {
|
|
10481
|
-
provide: WORKBENCH_POPUP_CONTEXT,
|
|
10482
|
-
useFactory: () => [
|
|
10483
|
-
provideWorkbenchDialogService(),
|
|
10484
|
-
provideWorkbenchMessageBoxService(),
|
|
10485
|
-
provideWorkbenchPopupService(),
|
|
10486
|
-
],
|
|
10487
|
-
multi: true,
|
|
10488
|
-
};
|
|
10489
|
-
}
|
|
10490
|
-
|
|
10491
|
-
/*
|
|
10492
|
-
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10493
|
-
*
|
|
10494
|
-
* This program and the accompanying materials are made
|
|
10495
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10496
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10497
|
-
*
|
|
10498
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10499
|
-
*/
|
|
10500
|
-
/** @inheritDoc */
|
|
10501
|
-
class ɵWorkbenchPopup {
|
|
10502
|
-
id;
|
|
10503
|
-
component;
|
|
10504
|
-
invocationContext;
|
|
10505
|
-
_options;
|
|
10506
|
-
/** Injector for the popup; destroyed when the popup is closed. */
|
|
10507
|
-
injector = inject(Injector);
|
|
10508
|
-
_overlayRef;
|
|
10509
|
-
_focusMonitor = inject(WorkbenchFocusMonitor);
|
|
10510
|
-
_portal;
|
|
10511
|
-
_componentRef = signal(undefined, { ...(ngDevMode ? { debugName: "_componentRef" } : {}) });
|
|
10512
|
-
_popupOrigin;
|
|
10513
|
-
_cssClass = signal([], { ...(ngDevMode ? { debugName: "_cssClass" } : {}) });
|
|
10514
|
-
size;
|
|
10515
|
-
focused = computed(() => this._focusMonitor.activeElement()?.id === this.id, { ...(ngDevMode ? { debugName: "focused" } : {}) });
|
|
10516
|
-
attached;
|
|
10517
|
-
destroyed = signal(false, { ...(ngDevMode ? { debugName: "destroyed" } : {}) });
|
|
10518
|
-
bounds = boundingClientRect(computed(() => this._componentRef()?.location.nativeElement));
|
|
10519
|
-
blockedBy;
|
|
10520
|
-
// TODO [Angular 22] Remove with Angular 22. Used for backward compatiblity.
|
|
10521
|
-
input;
|
|
10522
|
-
result;
|
|
10523
|
-
constructor(id, component, invocationContext, _options) {
|
|
10524
|
-
this.id = id;
|
|
10525
|
-
this.component = component;
|
|
10526
|
-
this.invocationContext = invocationContext;
|
|
10527
|
-
this._options = _options;
|
|
10528
|
-
this._portal = this.createPortal();
|
|
10529
|
-
this.input = this._portal.injector?.get(LEGACY_POPUP_INPUT, undefined, { optional: true });
|
|
10530
|
-
this._popupOrigin = this.trackPopupOrigin();
|
|
10531
|
-
this._cssClass.set(Arrays.coerce(this._options.cssClass));
|
|
10532
|
-
this.size = new ɵWorkbenchPopupSize(this._options);
|
|
10533
|
-
this.blockedBy = inject(WorkbenchDialogRegistry).top(this.id);
|
|
10534
|
-
this.attached = this.monitorHostElementAttached();
|
|
10535
|
-
const positionStrategy = inject(Overlay).position()
|
|
10536
|
-
.flexibleConnectedTo({ x: 0, y: 0 })
|
|
10537
|
-
.withFlexibleDimensions(false)
|
|
10538
|
-
.withLockedPosition(false) // If locked, the popup won't attempt to reposition itself if not enough space available.
|
|
10539
|
-
.withPositions((() => {
|
|
10540
|
-
switch (this._options.align ?? 'north') {
|
|
10541
|
-
case 'north':
|
|
10542
|
-
return [NORTH, SOUTH, WEST, EAST];
|
|
10543
|
-
case 'south':
|
|
10544
|
-
return [SOUTH, NORTH, WEST, EAST];
|
|
10545
|
-
case 'west':
|
|
10546
|
-
return [WEST, EAST, NORTH, SOUTH];
|
|
10547
|
-
case 'east':
|
|
10548
|
-
return [EAST, WEST, NORTH, SOUTH];
|
|
10549
|
-
default:
|
|
10550
|
-
throw Error('[PopupPositionError] Illegal position; must be north, south, west or east');
|
|
10551
|
-
}
|
|
10552
|
-
})());
|
|
10553
|
-
this._overlayRef = this.createOverlay(positionStrategy);
|
|
10554
|
-
const componentRef = this._overlayRef.attach(this._portal);
|
|
10555
|
-
const popupElement = componentRef.location.nativeElement;
|
|
10556
|
-
this._componentRef.set(componentRef);
|
|
10557
|
-
// Make the popup focusable to request focus.
|
|
10558
|
-
popupElement.setAttribute('tabindex', '-1');
|
|
10559
|
-
this.stickToAnchor(positionStrategy);
|
|
10560
|
-
this.repositionOnResize();
|
|
10561
|
-
this.bindToHostElement(popupElement);
|
|
10562
|
-
this.closeOnHostDestroy();
|
|
10563
|
-
this.closeOnFocusLoss(popupElement);
|
|
10564
|
-
this.closeOnEscape(popupElement);
|
|
10565
|
-
inject(DestroyRef).onDestroy(() => this.destroyed.set(true));
|
|
10566
|
-
}
|
|
10567
|
-
/**
|
|
10568
|
-
* Waits for the popup to close, resolving to its result or rejecting if closed with an error.
|
|
10569
|
-
*/
|
|
10570
|
-
waitForClose() {
|
|
10571
|
-
return new Promise((resolve, reject) => {
|
|
10572
|
-
this.injector.get(DestroyRef).onDestroy(() => {
|
|
10573
|
-
this.result instanceof Error ? reject(this.result) : resolve(this.result);
|
|
10574
|
-
});
|
|
10575
|
-
});
|
|
10576
|
-
}
|
|
10577
|
-
/**
|
|
10578
|
-
* Creates a portal to render {@link WorkbenchPopupComponent} in the popup's injection context.
|
|
10579
|
-
*/
|
|
10580
|
-
createPortal() {
|
|
10581
|
-
const injector = Injector.create({
|
|
10582
|
-
parent: this._options.injector ?? inject(Injector),
|
|
10583
|
-
providers: [
|
|
10584
|
-
{ provide: ɵWorkbenchPopup, useValue: this },
|
|
10585
|
-
{ provide: WorkbenchPopup, useExisting: ɵWorkbenchPopup },
|
|
10586
|
-
{ provide: Popup, useExisting: ɵWorkbenchPopup },
|
|
10587
|
-
{ provide: WORKBENCH_ELEMENT, useExisting: ɵWorkbenchPopup },
|
|
10588
|
-
inject(WORKBENCH_POPUP_CONTEXT, { optional: true }) ?? [],
|
|
10589
|
-
this._options.providers ?? [],
|
|
10590
|
-
],
|
|
10591
|
-
});
|
|
10592
|
-
inject(DestroyRef).onDestroy(() => injector.destroy());
|
|
10593
|
-
return new ComponentPortal(WorkbenchPopupComponent, null, injector);
|
|
10594
|
-
}
|
|
10595
|
-
/**
|
|
10596
|
-
* Creates a dedicated overlay per popup to place it on top of previously created overlays, such as dialogs, popups, dropdowns, etc.
|
|
10597
|
-
*/
|
|
10598
|
-
createOverlay(positionStrategy) {
|
|
10599
|
-
return inject(Overlay).create({
|
|
10600
|
-
panelClass: 'wb-popup',
|
|
10601
|
-
hasBackdrop: false,
|
|
10602
|
-
positionStrategy: positionStrategy,
|
|
10603
|
-
scrollStrategy: inject(Overlay).scrollStrategies.noop(),
|
|
10604
|
-
disposeOnNavigation: true,
|
|
10605
|
-
});
|
|
10606
|
-
}
|
|
10607
|
-
/**
|
|
10608
|
-
* Moves the popup with the anchor.
|
|
10609
|
-
*/
|
|
10610
|
-
stickToAnchor(positionStrategy) {
|
|
10611
|
-
effect(() => {
|
|
10612
|
-
const origin = this._popupOrigin();
|
|
10613
|
-
untracked(() => {
|
|
10614
|
-
if (origin) {
|
|
10615
|
-
positionStrategy.setOrigin(origin);
|
|
10616
|
-
this._overlayRef.updatePosition();
|
|
10617
|
-
}
|
|
10618
|
-
});
|
|
10619
|
-
});
|
|
10620
|
-
}
|
|
10621
|
-
/**
|
|
10622
|
-
* Monitors attachment of the host element.
|
|
10623
|
-
*/
|
|
10624
|
-
monitorHostElementAttached() {
|
|
10625
|
-
if (this.invocationContext) {
|
|
10626
|
-
return this.invocationContext.attached;
|
|
10627
|
-
}
|
|
10628
|
-
const workbenchComponentRef = inject(WORKBENCH_COMPONENT_REF);
|
|
10629
|
-
return computed(() => !!workbenchComponentRef());
|
|
10630
|
-
}
|
|
10631
|
-
/**
|
|
10632
|
-
* Repositions the popup position when resized.
|
|
10633
|
-
*/
|
|
10634
|
-
repositionOnResize() {
|
|
10635
|
-
const zone = inject(NgZone);
|
|
10636
|
-
fromResize$(this._overlayRef.overlayElement)
|
|
10637
|
-
.pipe(observeIn(fn => zone.run(fn)), takeUntilDestroyed())
|
|
10638
|
-
.subscribe(() => {
|
|
10639
|
-
this._overlayRef.updatePosition();
|
|
10640
|
-
});
|
|
10641
|
-
}
|
|
10642
|
-
/**
|
|
10643
|
-
* Closes the popup on focus loss, if configured.
|
|
10644
|
-
*/
|
|
10645
|
-
closeOnFocusLoss(popupElement) {
|
|
10646
|
-
const focusMonitor = inject(FocusMonitor);
|
|
10647
|
-
if (this._options.closeStrategy?.onFocusLost ?? true) {
|
|
10648
|
-
effect(onCleanup => {
|
|
10649
|
-
if (!this.attached() || !this._popupOrigin()) {
|
|
10650
|
-
return;
|
|
10651
|
-
}
|
|
10652
|
-
untracked(() => {
|
|
10653
|
-
const subscription = focusMonitor.monitor(popupElement, true)
|
|
10654
|
-
.pipe(filter((focusOrigin) => !focusOrigin))
|
|
10655
|
-
.subscribe(() => this.close(this.result));
|
|
10656
|
-
onCleanup(() => subscription.unsubscribe());
|
|
10657
|
-
});
|
|
10658
|
-
});
|
|
10659
|
-
}
|
|
10205
|
+
/**
|
|
10206
|
+
* Closes the popup on focus loss, if configured.
|
|
10207
|
+
*/
|
|
10208
|
+
closeOnFocusLoss(popupElement) {
|
|
10209
|
+
const focusMonitor = inject(FocusMonitor);
|
|
10210
|
+
if (this._options.closeStrategy?.onFocusLost ?? true) {
|
|
10211
|
+
effect(onCleanup => {
|
|
10212
|
+
if (!this.attached() || !this._popupOrigin()) {
|
|
10213
|
+
return;
|
|
10214
|
+
}
|
|
10215
|
+
untracked(() => {
|
|
10216
|
+
const subscription = focusMonitor.monitor(popupElement, true)
|
|
10217
|
+
.pipe(filter((focusOrigin) => !focusOrigin))
|
|
10218
|
+
.subscribe(() => this.close(this.result));
|
|
10219
|
+
onCleanup(() => subscription.unsubscribe());
|
|
10220
|
+
});
|
|
10221
|
+
});
|
|
10222
|
+
}
|
|
10660
10223
|
}
|
|
10661
10224
|
/**
|
|
10662
10225
|
* Closes the popup on escape keystroke.
|
|
@@ -10923,6 +10486,38 @@ const LEGACY_POPUP_INPUT = new InjectionToken('LEGACY_POPUP_INPUT');
|
|
|
10923
10486
|
*
|
|
10924
10487
|
* SPDX-License-Identifier: EPL-2.0
|
|
10925
10488
|
*/
|
|
10489
|
+
/**
|
|
10490
|
+
* Registry for {@link WorkbenchNotification} elements.
|
|
10491
|
+
*/
|
|
10492
|
+
class WorkbenchNotificationRegistry extends WorkbenchElementRegistry {
|
|
10493
|
+
/**
|
|
10494
|
+
* Gets the most recently opened notification.
|
|
10495
|
+
*/
|
|
10496
|
+
top;
|
|
10497
|
+
constructor() {
|
|
10498
|
+
super({
|
|
10499
|
+
nullElementErrorFn: notificationId => Error(`[NullNotificationError] Notification '${notificationId}' not found.`),
|
|
10500
|
+
onUnregister: notification => notification.destroy(),
|
|
10501
|
+
});
|
|
10502
|
+
this.top = computed(() => this.elements().at(-1), { ...(ngDevMode ? { debugName: "top" } : {}) });
|
|
10503
|
+
}
|
|
10504
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10505
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationRegistry, providedIn: 'root' });
|
|
10506
|
+
}
|
|
10507
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationRegistry, decorators: [{
|
|
10508
|
+
type: Injectable,
|
|
10509
|
+
args: [{ providedIn: 'root' }]
|
|
10510
|
+
}], ctorParameters: () => [] });
|
|
10511
|
+
|
|
10512
|
+
/*
|
|
10513
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
10514
|
+
*
|
|
10515
|
+
* This program and the accompanying materials are made
|
|
10516
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
10517
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10518
|
+
*
|
|
10519
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
10520
|
+
*/
|
|
10926
10521
|
/**
|
|
10927
10522
|
* Creates the invocation context for given element.
|
|
10928
10523
|
*
|
|
@@ -10978,7 +10573,76 @@ function createInvocationContext(elementId, options) {
|
|
|
10978
10573
|
peripheral: signal(false),
|
|
10979
10574
|
};
|
|
10980
10575
|
}
|
|
10981
|
-
|
|
10576
|
+
else if (isNotificationId(contextualElementId)) {
|
|
10577
|
+
const notification = injector.get(WorkbenchNotificationRegistry).get(contextualElementId);
|
|
10578
|
+
return {
|
|
10579
|
+
elementId: notification.id,
|
|
10580
|
+
attached: computed(() => !notification.destroyed()),
|
|
10581
|
+
bounds: notification.bounds,
|
|
10582
|
+
destroyed: notification.destroyed,
|
|
10583
|
+
peripheral: signal(true),
|
|
10584
|
+
};
|
|
10585
|
+
}
|
|
10586
|
+
return null;
|
|
10587
|
+
}
|
|
10588
|
+
|
|
10589
|
+
/*
|
|
10590
|
+
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
10591
|
+
*
|
|
10592
|
+
* This program and the accompanying materials are made
|
|
10593
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
10594
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10595
|
+
*
|
|
10596
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
10597
|
+
*/
|
|
10598
|
+
/** @inheritDoc */
|
|
10599
|
+
class ɵWorkbenchPopupService {
|
|
10600
|
+
_injector = inject(Injector);
|
|
10601
|
+
_rootInjector = inject(ApplicationRef).injector;
|
|
10602
|
+
_popupRegistry = inject(WorkbenchPopupRegistry);
|
|
10603
|
+
_zone = inject(NgZone);
|
|
10604
|
+
/** @inheritDoc */
|
|
10605
|
+
async open(component, options) {
|
|
10606
|
+
assertNotInReactiveContext(this.open, 'Call WorkbenchPopupService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
10607
|
+
// Ensure to run in Angular zone to display the popup even when called from outside the Angular zone.
|
|
10608
|
+
if (!NgZone.isInAngularZone()) {
|
|
10609
|
+
return this._zone.run(() => this.open(component, options));
|
|
10610
|
+
}
|
|
10611
|
+
const popup = this.createPopup(component, options);
|
|
10612
|
+
this._popupRegistry.register(popup.id, popup);
|
|
10613
|
+
try {
|
|
10614
|
+
return await popup.waitForClose();
|
|
10615
|
+
}
|
|
10616
|
+
finally {
|
|
10617
|
+
this._popupRegistry.unregister(popup.id);
|
|
10618
|
+
}
|
|
10619
|
+
}
|
|
10620
|
+
/**
|
|
10621
|
+
* Creates the popup handle.
|
|
10622
|
+
*/
|
|
10623
|
+
createPopup(component, options) {
|
|
10624
|
+
// Construct the handle in an injection context that shares the popup's lifecycle, allowing for automatic cleanup of effects and RxJS interop functions.
|
|
10625
|
+
const popupId = options.id ?? computePopupId();
|
|
10626
|
+
const popupInjector = Injector.create({
|
|
10627
|
+
parent: this._rootInjector, // use root injector to be independent of service construction context
|
|
10628
|
+
providers: [],
|
|
10629
|
+
name: `Workbench Popup ${popupId}`,
|
|
10630
|
+
});
|
|
10631
|
+
const invocationContext = createPopupInvocationContext(options, this._injector);
|
|
10632
|
+
return runInInjectionContext(popupInjector, () => new ɵWorkbenchPopup(popupId, component, invocationContext, options));
|
|
10633
|
+
}
|
|
10634
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10635
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, providedIn: 'root' });
|
|
10636
|
+
}
|
|
10637
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, decorators: [{
|
|
10638
|
+
type: Injectable,
|
|
10639
|
+
args: [{ providedIn: 'root' }]
|
|
10640
|
+
}] });
|
|
10641
|
+
/**
|
|
10642
|
+
* Computes the popup's invocation context based on passsed options and injection context.
|
|
10643
|
+
*/
|
|
10644
|
+
function createPopupInvocationContext(options, injector) {
|
|
10645
|
+
return createInvocationContext(options.context && (typeof options.context === 'object' ? options.context.viewId : options.context), { injector });
|
|
10982
10646
|
}
|
|
10983
10647
|
|
|
10984
10648
|
/*
|
|
@@ -11077,7 +10741,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
11077
10741
|
}] });
|
|
11078
10742
|
|
|
11079
10743
|
/*
|
|
11080
|
-
* Copyright (c) 2018-
|
|
10744
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
11081
10745
|
*
|
|
11082
10746
|
* This program and the accompanying materials are made
|
|
11083
10747
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -11085,55 +10749,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
11085
10749
|
*
|
|
11086
10750
|
* SPDX-License-Identifier: EPL-2.0
|
|
11087
10751
|
*/
|
|
11088
|
-
/** @inheritDoc */
|
|
11089
|
-
class ɵWorkbenchPopupService {
|
|
11090
|
-
_injector = inject(Injector);
|
|
11091
|
-
_rootInjector = inject(ApplicationRef).injector;
|
|
11092
|
-
_popupRegistry = inject(WorkbenchPopupRegistry);
|
|
11093
|
-
_zone = inject(NgZone);
|
|
11094
|
-
/** @inheritDoc */
|
|
11095
|
-
async open(component, options) {
|
|
11096
|
-
assertNotInReactiveContext(this.open, 'Call WorkbenchPopupService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
11097
|
-
// Ensure to run in Angular zone to display the popup even when called from outside the Angular zone.
|
|
11098
|
-
if (!NgZone.isInAngularZone()) {
|
|
11099
|
-
return this._zone.run(() => this.open(component, options));
|
|
11100
|
-
}
|
|
11101
|
-
const popup = this.createPopup(component, options);
|
|
11102
|
-
this._popupRegistry.register(popup.id, popup);
|
|
11103
|
-
try {
|
|
11104
|
-
return await popup.waitForClose();
|
|
11105
|
-
}
|
|
11106
|
-
finally {
|
|
11107
|
-
this._popupRegistry.unregister(popup.id);
|
|
11108
|
-
}
|
|
11109
|
-
}
|
|
11110
|
-
/**
|
|
11111
|
-
* Creates the popup handle.
|
|
11112
|
-
*/
|
|
11113
|
-
createPopup(component, options) {
|
|
11114
|
-
// Construct the handle in an injection context that shares the popup's lifecycle, allowing for automatic cleanup of effects and RxJS interop functions.
|
|
11115
|
-
const popupId = options.id ?? computePopupId();
|
|
11116
|
-
const popupInjector = Injector.create({
|
|
11117
|
-
parent: this._rootInjector, // use root injector to be independent of service construction context
|
|
11118
|
-
providers: [],
|
|
11119
|
-
name: `Workbench Popup ${popupId}`,
|
|
11120
|
-
});
|
|
11121
|
-
const invocationContext = createPopupInvocationContext(options, this._injector);
|
|
11122
|
-
return runInInjectionContext(popupInjector, () => new ɵWorkbenchPopup(popupId, component, invocationContext, options));
|
|
11123
|
-
}
|
|
11124
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11125
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, providedIn: 'root' });
|
|
11126
|
-
}
|
|
11127
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, decorators: [{
|
|
11128
|
-
type: Injectable,
|
|
11129
|
-
args: [{ providedIn: 'root' }]
|
|
11130
|
-
}] });
|
|
11131
|
-
/**
|
|
11132
|
-
* Computes the popup's invocation context based on passsed options and injection context.
|
|
11133
|
-
*/
|
|
11134
|
-
function createPopupInvocationContext(options, injector) {
|
|
11135
|
-
return createInvocationContext(options.context && (typeof options.context === 'object' ? options.context.viewId : options.context), { injector });
|
|
11136
|
-
}
|
|
11137
10752
|
/**
|
|
11138
10753
|
* Provides {@link WorkbenchPopupService} for dependency injection.
|
|
11139
10754
|
*/
|
|
@@ -11175,7 +10790,7 @@ function provideWorkbenchDialogContext() {
|
|
|
11175
10790
|
}
|
|
11176
10791
|
|
|
11177
10792
|
/*
|
|
11178
|
-
* Copyright (c) 2018-
|
|
10793
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
11179
10794
|
*
|
|
11180
10795
|
* This program and the accompanying materials are made
|
|
11181
10796
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -11210,7 +10825,7 @@ class ɵWorkbenchDialog {
|
|
|
11210
10825
|
focused = computed(() => this._focusMonitor.activeElement()?.id === this.id, { ...(ngDevMode ? { debugName: "focused" } : {}) });
|
|
11211
10826
|
attached;
|
|
11212
10827
|
destroyed = signal(false, { ...(ngDevMode ? { debugName: "destroyed" } : {}) });
|
|
11213
|
-
bounds = boundingClientRect(computed(() => this._componentRef()?.instance.
|
|
10828
|
+
bounds = boundingClientRect(computed(() => this._componentRef()?.instance.dialogSlotBounds()));
|
|
11214
10829
|
modal;
|
|
11215
10830
|
blinking$ = new BehaviorSubject(false);
|
|
11216
10831
|
header;
|
|
@@ -11420,155 +11035,605 @@ class ɵWorkbenchDialog {
|
|
|
11420
11035
|
if (this.invocationContext) {
|
|
11421
11036
|
return this.invocationContext.attached;
|
|
11422
11037
|
}
|
|
11423
|
-
if (this._workbenchConfig.dialog?.modalityScope === 'viewport') {
|
|
11424
|
-
return computed(() => true);
|
|
11038
|
+
if (this._workbenchConfig.dialog?.modalityScope === 'viewport') {
|
|
11039
|
+
return computed(() => true);
|
|
11040
|
+
}
|
|
11041
|
+
const workbenchComponentRef = inject(WORKBENCH_COMPONENT_REF);
|
|
11042
|
+
return computed(() => !!workbenchComponentRef());
|
|
11043
|
+
}
|
|
11044
|
+
/**
|
|
11045
|
+
* Binds this dialog to its workbench host element, displaying it only when the host element is attached.
|
|
11046
|
+
*
|
|
11047
|
+
* Dialogs opened in non-peripheral area are displayed in the center of the host.
|
|
11048
|
+
*/
|
|
11049
|
+
bindToHostElement() {
|
|
11050
|
+
if (!this.invocationContext && this._workbenchConfig.dialog?.modalityScope === 'viewport') {
|
|
11051
|
+
setStyle(this._overlayRef.hostElement, { inset: '0' });
|
|
11052
|
+
}
|
|
11053
|
+
else {
|
|
11054
|
+
const viewDragService = inject(ViewDragService);
|
|
11055
|
+
const workbenchComponentBounds = inject(WORKBENCH_COMPONENT_BOUNDS);
|
|
11056
|
+
const document = inject(DOCUMENT);
|
|
11057
|
+
effect(() => {
|
|
11058
|
+
const visible = this.attached() && !viewDragService.dragging();
|
|
11059
|
+
// Maintain position and size when hidden to prevent flickering when visible again and to support for virtual scrolling in dialog content.
|
|
11060
|
+
if (!visible) {
|
|
11061
|
+
setStyle(this._overlayRef.overlayElement, { visibility: 'hidden' }); // Hide via `visibility` instead of `display` property to retain the size.
|
|
11062
|
+
return;
|
|
11063
|
+
}
|
|
11064
|
+
// IMPORTANT: Track host bounds only if visible to prevent flickering.
|
|
11065
|
+
// Align dialog relative to contextual element if opened in non-peripheral area.
|
|
11066
|
+
const hostBounds = this.invocationContext?.peripheral() === false ? this.invocationContext.bounds() : workbenchComponentBounds();
|
|
11067
|
+
if (!hostBounds) {
|
|
11068
|
+
setStyle(this._overlayRef.overlayElement, { visibility: 'hidden' }); // Hide via `visibility` instead of `display` property to retain the size.
|
|
11069
|
+
return;
|
|
11070
|
+
}
|
|
11071
|
+
setStyle(this._overlayRef.overlayElement, { visibility: null });
|
|
11072
|
+
// Center the dialog horizontally within the host bounds.
|
|
11073
|
+
// Shift the overlay instead of fitting it to the host bounds, so the dialog can grow beyond host bounds
|
|
11074
|
+
// if not specifying dialog size via a dialog handle.
|
|
11075
|
+
const { left, top, width } = hostBounds;
|
|
11076
|
+
const viewportCenter = document.documentElement.offsetWidth / 2;
|
|
11077
|
+
const dialogCenter = left + width / 2;
|
|
11078
|
+
const xDelta = -1 * (viewportCenter - dialogCenter);
|
|
11079
|
+
setStyle(this._overlayRef.hostElement, {
|
|
11080
|
+
transform: `translateX(${Math.round(xDelta)}px) translateY(${Math.round(top)}px)`, // round offset to avoid blurry dialog
|
|
11081
|
+
});
|
|
11082
|
+
});
|
|
11083
|
+
}
|
|
11084
|
+
}
|
|
11085
|
+
/**
|
|
11086
|
+
* Computes if this dialog is blocked by another dialog.
|
|
11087
|
+
*/
|
|
11088
|
+
computeBlocked() {
|
|
11089
|
+
const dialogRegistry = inject(WorkbenchDialogRegistry);
|
|
11090
|
+
const topInThisContext = dialogRegistry.top(this.id);
|
|
11091
|
+
const topInInvocationContext = dialogRegistry.top(this.invocationContext?.elementId);
|
|
11092
|
+
return computed(() => {
|
|
11093
|
+
// Get the top dialog in the context spawned by this dialog.
|
|
11094
|
+
if (topInThisContext()) {
|
|
11095
|
+
return topInThisContext();
|
|
11096
|
+
}
|
|
11097
|
+
// Get the top dialog in the context this dialog was opened in.
|
|
11098
|
+
if (topInInvocationContext() !== this) {
|
|
11099
|
+
return topInInvocationContext();
|
|
11100
|
+
}
|
|
11101
|
+
return null;
|
|
11102
|
+
});
|
|
11103
|
+
}
|
|
11104
|
+
blinkOnRequest() {
|
|
11105
|
+
this._blink$
|
|
11106
|
+
.pipe(switchMap(() => of(true).pipe(concatWith(of(false).pipe(delay(300))))), distinctUntilChanged(), takeUntilDestroyed())
|
|
11107
|
+
.subscribe(this.blinking$);
|
|
11108
|
+
}
|
|
11109
|
+
/**
|
|
11110
|
+
* Closes the dialog when the context element is destroyed.
|
|
11111
|
+
*/
|
|
11112
|
+
closeOnHostDestroy() {
|
|
11113
|
+
if (this.invocationContext) {
|
|
11114
|
+
effect(() => {
|
|
11115
|
+
if (this.invocationContext.destroyed()) {
|
|
11116
|
+
untracked(() => this.close());
|
|
11117
|
+
}
|
|
11118
|
+
});
|
|
11119
|
+
}
|
|
11120
|
+
}
|
|
11121
|
+
/**
|
|
11122
|
+
* Destroys this dialog and associated resources.
|
|
11123
|
+
*/
|
|
11124
|
+
destroy() {
|
|
11125
|
+
if (!this.destroyed()) {
|
|
11126
|
+
this.injector.destroy();
|
|
11127
|
+
this._overlayRef.dispose();
|
|
11128
|
+
}
|
|
11129
|
+
}
|
|
11130
|
+
}
|
|
11131
|
+
/** @inheritDoc */
|
|
11132
|
+
class ɵWorkbenchDialogSize {
|
|
11133
|
+
_height = signal(undefined, { ...(ngDevMode ? { debugName: "_height" } : {}) });
|
|
11134
|
+
_width = signal(undefined, { ...(ngDevMode ? { debugName: "_width" } : {}) });
|
|
11135
|
+
_minHeight = signal(undefined, { ...(ngDevMode ? { debugName: "_minHeight" } : {}) });
|
|
11136
|
+
_maxHeight = signal(undefined, { ...(ngDevMode ? { debugName: "_maxHeight" } : {}) });
|
|
11137
|
+
_minWidth = signal(undefined, { ...(ngDevMode ? { debugName: "_minWidth" } : {}) });
|
|
11138
|
+
_maxWidth = signal(undefined, { ...(ngDevMode ? { debugName: "_maxWidth" } : {}) });
|
|
11139
|
+
/** @inheritDoc */
|
|
11140
|
+
get height() {
|
|
11141
|
+
return this._height;
|
|
11142
|
+
}
|
|
11143
|
+
/** @inheritDoc */
|
|
11144
|
+
set height(height) {
|
|
11145
|
+
untracked(() => this._height.set(height));
|
|
11146
|
+
}
|
|
11147
|
+
/** @inheritDoc */
|
|
11148
|
+
get width() {
|
|
11149
|
+
return this._width;
|
|
11150
|
+
}
|
|
11151
|
+
/** @inheritDoc */
|
|
11152
|
+
set width(width) {
|
|
11153
|
+
untracked(() => this._width.set(width));
|
|
11154
|
+
}
|
|
11155
|
+
/** @inheritDoc */
|
|
11156
|
+
get minHeight() {
|
|
11157
|
+
return this._minHeight;
|
|
11158
|
+
}
|
|
11159
|
+
/** @inheritDoc */
|
|
11160
|
+
set minHeight(minHeight) {
|
|
11161
|
+
untracked(() => this._minHeight.set(minHeight));
|
|
11162
|
+
}
|
|
11163
|
+
/** @inheritDoc */
|
|
11164
|
+
get maxHeight() {
|
|
11165
|
+
return this._maxHeight;
|
|
11166
|
+
}
|
|
11167
|
+
/** @inheritDoc */
|
|
11168
|
+
set maxHeight(maxHeight) {
|
|
11169
|
+
untracked(() => this._maxHeight.set(maxHeight));
|
|
11170
|
+
}
|
|
11171
|
+
/** @inheritDoc */
|
|
11172
|
+
get minWidth() {
|
|
11173
|
+
return this._minWidth;
|
|
11174
|
+
}
|
|
11175
|
+
/** @inheritDoc */
|
|
11176
|
+
set minWidth(minWidth) {
|
|
11177
|
+
untracked(() => this._minWidth.set(minWidth));
|
|
11178
|
+
}
|
|
11179
|
+
/** @inheritDoc */
|
|
11180
|
+
get maxWidth() {
|
|
11181
|
+
return this._maxWidth;
|
|
11182
|
+
}
|
|
11183
|
+
/** @inheritDoc */
|
|
11184
|
+
set maxWidth(maxWidth) {
|
|
11185
|
+
untracked(() => this._maxWidth.set(maxWidth));
|
|
11186
|
+
}
|
|
11187
|
+
}
|
|
11188
|
+
|
|
11189
|
+
/*
|
|
11190
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11191
|
+
*
|
|
11192
|
+
* This program and the accompanying materials are made
|
|
11193
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11194
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11195
|
+
*
|
|
11196
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11197
|
+
*/
|
|
11198
|
+
/** @inheritDoc */
|
|
11199
|
+
class ɵWorkbenchDialogService {
|
|
11200
|
+
_injector = inject(Injector);
|
|
11201
|
+
_rootInjector = inject(ApplicationRef).injector;
|
|
11202
|
+
_dialogRegistry = inject(WorkbenchDialogRegistry);
|
|
11203
|
+
_document = inject(DOCUMENT);
|
|
11204
|
+
_zone = inject(NgZone);
|
|
11205
|
+
constructor() {
|
|
11206
|
+
this.installServiceLifecycleLogger();
|
|
11207
|
+
}
|
|
11208
|
+
/** @inheritDoc */
|
|
11209
|
+
async open(component, options) {
|
|
11210
|
+
assertNotInReactiveContext(this.open, 'Call WorkbenchDialogService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
11211
|
+
// Ensure to run in Angular zone to display the dialog even when called from outside the Angular zone.
|
|
11212
|
+
if (!NgZone.isInAngularZone()) {
|
|
11213
|
+
return this._zone.run(() => this.open(component, options));
|
|
11214
|
+
}
|
|
11215
|
+
// Delay the opening of a context-modal dialog until all application-modal dialogs are closed.
|
|
11216
|
+
// Otherwise, the context-modal dialog would overlap already opened application-modal dialogs.
|
|
11217
|
+
const invocationContext = createDialogInvocationContext(options ?? {}, this._injector);
|
|
11218
|
+
if (invocationContext) {
|
|
11219
|
+
await this.waitUntilApplicationModalDialogsClosed();
|
|
11220
|
+
}
|
|
11221
|
+
// Create the dialog.
|
|
11222
|
+
const dialog = this.createDialog(component, invocationContext, options ?? {});
|
|
11223
|
+
this._dialogRegistry.register(dialog.id, dialog);
|
|
11224
|
+
// Capture focused element to restore focus when closing the dialog.
|
|
11225
|
+
const previouslyFocusedElement = this._document.activeElement instanceof HTMLElement ? this._document.activeElement : undefined;
|
|
11226
|
+
try {
|
|
11227
|
+
return await dialog.waitForClose();
|
|
11228
|
+
}
|
|
11229
|
+
finally {
|
|
11230
|
+
this._dialogRegistry.unregister(dialog.id);
|
|
11231
|
+
// Restore focus to previously focused element when closing the last dialog in the current context.
|
|
11232
|
+
if (previouslyFocusedElement && !this._dialogRegistry.top(invocationContext?.elementId)()) {
|
|
11233
|
+
previouslyFocusedElement.focus();
|
|
11234
|
+
}
|
|
11425
11235
|
}
|
|
11426
|
-
const workbenchComponentRef = inject(WORKBENCH_COMPONENT_REF);
|
|
11427
|
-
return computed(() => !!workbenchComponentRef());
|
|
11428
11236
|
}
|
|
11429
11237
|
/**
|
|
11430
|
-
*
|
|
11431
|
-
*
|
|
11432
|
-
* Dialogs opened in non-peripheral area are displayed in the center of the host.
|
|
11238
|
+
* Creates the dialog handle.
|
|
11433
11239
|
*/
|
|
11434
|
-
|
|
11435
|
-
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
const visible = this.attached() && !viewDragService.dragging();
|
|
11444
|
-
// Maintain position and size when hidden to prevent flickering when visible again and to support for virtual scrolling in dialog content.
|
|
11445
|
-
if (!visible) {
|
|
11446
|
-
setStyle(this._overlayRef.overlayElement, { visibility: 'hidden' }); // Hide via `visibility` instead of `display` property to retain the size.
|
|
11447
|
-
return;
|
|
11448
|
-
}
|
|
11449
|
-
// IMPORTANT: Track host bounds only if visible to prevent flickering.
|
|
11450
|
-
// Align dialog relative to contextual element if opened in non-peripheral area.
|
|
11451
|
-
const hostBounds = this.invocationContext?.peripheral() === false ? this.invocationContext.bounds() : workbenchComponentBounds();
|
|
11452
|
-
if (!hostBounds) {
|
|
11453
|
-
setStyle(this._overlayRef.overlayElement, { visibility: 'hidden' }); // Hide via `visibility` instead of `display` property to retain the size.
|
|
11454
|
-
return;
|
|
11455
|
-
}
|
|
11456
|
-
setStyle(this._overlayRef.overlayElement, { visibility: null });
|
|
11457
|
-
// Center the dialog horizontally within the host bounds.
|
|
11458
|
-
// Shift the overlay instead of fitting it to the host bounds, so the dialog can grow beyond host bounds
|
|
11459
|
-
// if not specifying dialog size via a dialog handle.
|
|
11460
|
-
const { left, top, width } = hostBounds;
|
|
11461
|
-
const viewportCenter = document.documentElement.offsetWidth / 2;
|
|
11462
|
-
const dialogCenter = left + width / 2;
|
|
11463
|
-
const xDelta = -1 * (viewportCenter - dialogCenter);
|
|
11464
|
-
setStyle(this._overlayRef.hostElement, {
|
|
11465
|
-
transform: `translateX(${Math.round(xDelta)}px) translateY(${Math.round(top)}px)`, // round offset to avoid blurry dialog
|
|
11466
|
-
});
|
|
11467
|
-
});
|
|
11468
|
-
}
|
|
11240
|
+
createDialog(component, invocationContext, options) {
|
|
11241
|
+
// Construct the handle in an injection context that shares the dialog's lifecycle, allowing for automatic cleanup of effects and RxJS interop functions.
|
|
11242
|
+
const dialogId = computeDialogId();
|
|
11243
|
+
const dialogInjector = Injector.create({
|
|
11244
|
+
parent: this._rootInjector, // use root injector to be independent of service construction context
|
|
11245
|
+
providers: [],
|
|
11246
|
+
name: `Workbench Dialog ${dialogId}`,
|
|
11247
|
+
});
|
|
11248
|
+
return runInInjectionContext(dialogInjector, () => new ɵWorkbenchDialog(dialogId, component, invocationContext, options));
|
|
11469
11249
|
}
|
|
11470
11250
|
/**
|
|
11471
|
-
*
|
|
11251
|
+
* Returns a Promise that resolves when all application modal-dialogs are closed. If none are opened, the Promise resolves immediately.
|
|
11472
11252
|
*/
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
const
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
// Get the top dialog in the context spawned by this dialog.
|
|
11479
|
-
if (topInThisContext()) {
|
|
11480
|
-
return topInThisContext();
|
|
11481
|
-
}
|
|
11482
|
-
// Get the top dialog in the context this dialog was opened in.
|
|
11483
|
-
if (topInInvocationContext() !== this) {
|
|
11484
|
-
return topInInvocationContext();
|
|
11485
|
-
}
|
|
11486
|
-
return null;
|
|
11487
|
-
});
|
|
11253
|
+
async waitUntilApplicationModalDialogsClosed() {
|
|
11254
|
+
// Use root injector to be independent of service construction context.
|
|
11255
|
+
const injector = Injector.create({ parent: this._rootInjector, providers: [] });
|
|
11256
|
+
await firstValueFrom(toObservable(this._dialogRegistry.top(), { injector }).pipe(filter(top => !top)));
|
|
11257
|
+
injector.destroy();
|
|
11488
11258
|
}
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11259
|
+
installServiceLifecycleLogger() {
|
|
11260
|
+
const logger = inject(Logger);
|
|
11261
|
+
const workbenchElement = inject(WORKBENCH_ELEMENT, { optional: true });
|
|
11262
|
+
logger.debug(() => `Constructing WorkbenchDialogService [context=${workbenchElement?.id}]`, LoggerNames.LIFECYCLE);
|
|
11263
|
+
inject(DestroyRef).onDestroy(() => logger.debug(() => `Destroying WorkbenchDialogService [context=${workbenchElement?.id}]'`, LoggerNames.LIFECYCLE));
|
|
11264
|
+
}
|
|
11265
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11266
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchDialogService, providedIn: 'root' });
|
|
11267
|
+
}
|
|
11268
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchDialogService, decorators: [{
|
|
11269
|
+
type: Injectable,
|
|
11270
|
+
args: [{ providedIn: 'root' }]
|
|
11271
|
+
}], ctorParameters: () => [] });
|
|
11272
|
+
/**
|
|
11273
|
+
* Computes the dialog's invocation context based on passsed options and injection context.
|
|
11274
|
+
*/
|
|
11275
|
+
function createDialogInvocationContext(options, injector) {
|
|
11276
|
+
if (options.modality === 'application') {
|
|
11277
|
+
return null;
|
|
11278
|
+
}
|
|
11279
|
+
return createInvocationContext(options.context && (typeof options.context === 'object' ? options.context.viewId : options.context), { injector });
|
|
11280
|
+
}
|
|
11281
|
+
|
|
11282
|
+
/*
|
|
11283
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11284
|
+
*
|
|
11285
|
+
* This program and the accompanying materials are made
|
|
11286
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11287
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11288
|
+
*
|
|
11289
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11290
|
+
*/
|
|
11291
|
+
/**
|
|
11292
|
+
* Enables the display of a component in a dialog.
|
|
11293
|
+
*
|
|
11294
|
+
* A dialog is a visual element for focused interaction with the user, such as prompting the user for input or confirming actions.
|
|
11295
|
+
* The user can move and resize a dialog.
|
|
11296
|
+
*
|
|
11297
|
+
* Displayed on top of other content, a modal dialog blocks interaction with other parts of the application.
|
|
11298
|
+
*
|
|
11299
|
+
* ## Modality
|
|
11300
|
+
* A dialog can be context-modal or application-modal. Context-modal blocks a specific part of the application, as specified by the context;
|
|
11301
|
+
* application-modal blocks the workbench or browser viewport, based on {@link WorkbenchConfig.dialog.modalityScope}.
|
|
11302
|
+
*
|
|
11303
|
+
* ## Context
|
|
11304
|
+
* A dialog can be bound to a context (e.g., part or view), defaulting to the calling context.
|
|
11305
|
+
* The dialog is displayed only if the context is visible and closes when the context is disposed.
|
|
11306
|
+
*
|
|
11307
|
+
* ## Positioning
|
|
11308
|
+
* A dialog is opened in the center of its context, if any, unless opened from the peripheral area.
|
|
11309
|
+
*
|
|
11310
|
+
* ## Stacking
|
|
11311
|
+
* Dialogs are stacked per modality, with only the topmost dialog in each stack being interactive.
|
|
11312
|
+
*
|
|
11313
|
+
* ## Dialog Component
|
|
11314
|
+
* The dialog component can inject the {@link WorkbenchDialog} handle to interact with the dialog, such as setting the title or closing the dialog.
|
|
11315
|
+
* Inputs passed to the dialog are available as input properties in the dialog component.
|
|
11316
|
+
*
|
|
11317
|
+
* ## Dialog Header
|
|
11318
|
+
* By default, the dialog displays the title and a close button in the header. Alternatively, the dialog supports the use of a custom header.
|
|
11319
|
+
* To provide a custom header, add an Angular template to the HTML of the dialog component and decorate it with the `wbDialogHeader` directive.
|
|
11320
|
+
*
|
|
11321
|
+
* ```html
|
|
11322
|
+
* <ng-template wbDialogHeader>
|
|
11323
|
+
* <app-dialog-header/>
|
|
11324
|
+
* </ng-template>
|
|
11325
|
+
* ```
|
|
11326
|
+
*
|
|
11327
|
+
* ## Dialog Footer
|
|
11328
|
+
* A dialog has a default footer that displays actions defined in the HTML of the dialog component. An action is an Angular template decorated with
|
|
11329
|
+
* the `wbDialogAction` directive. Multiple actions are supported, rendered in modeling order, and can be left- or right-aligned.
|
|
11330
|
+
*
|
|
11331
|
+
* ```html
|
|
11332
|
+
* <!-- Checkbox -->
|
|
11333
|
+
* <ng-template wbDialogAction align="start">
|
|
11334
|
+
* <label>
|
|
11335
|
+
* <input type="checkbox"/>
|
|
11336
|
+
* Do not ask me again
|
|
11337
|
+
* </label>
|
|
11338
|
+
* </ng-template>
|
|
11339
|
+
*
|
|
11340
|
+
* <!-- OK Button -->
|
|
11341
|
+
* <ng-template wbDialogAction align="end">
|
|
11342
|
+
* <button (click)="...">OK</button>
|
|
11343
|
+
* </ng-template>
|
|
11344
|
+
*
|
|
11345
|
+
* <!-- Cancel Button -->
|
|
11346
|
+
* <ng-template wbDialogAction align="end">
|
|
11347
|
+
* <button (click)="...">Cancel</button>
|
|
11348
|
+
* </ng-template>
|
|
11349
|
+
* ```
|
|
11350
|
+
*
|
|
11351
|
+
* Alternatively, the dialog supports the use of a custom footer. To provide a custom footer, add an Angular template to the HTML of the dialog component and
|
|
11352
|
+
* decorate it with the `wbDialogFooter` directive.
|
|
11353
|
+
*
|
|
11354
|
+
* ```html
|
|
11355
|
+
* <ng-template wbDialogFooter>
|
|
11356
|
+
* <app-dialog-footer/>
|
|
11357
|
+
* </ng-template>
|
|
11358
|
+
* ```
|
|
11359
|
+
*
|
|
11360
|
+
* ## Styling
|
|
11361
|
+
* The following CSS variables can be set to customize the default look of a dialog.
|
|
11362
|
+
*
|
|
11363
|
+
* - `--sci-workbench-dialog-padding`
|
|
11364
|
+
* - `--sci-workbench-dialog-header-height`
|
|
11365
|
+
* - `--sci-workbench-dialog-header-background-color`
|
|
11366
|
+
* - `--sci-workbench-dialog-title-font-family`
|
|
11367
|
+
* - `--sci-workbench-dialog-title-font-weight`
|
|
11368
|
+
* - `--sci-workbench-dialog-title-font-size`
|
|
11369
|
+
* - `--sci-workbench-dialog-title-align`
|
|
11370
|
+
*/
|
|
11371
|
+
class WorkbenchDialogService {
|
|
11372
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11373
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogService, providedIn: 'root', useExisting: ɵWorkbenchDialogService });
|
|
11374
|
+
}
|
|
11375
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogService, decorators: [{
|
|
11376
|
+
type: Injectable,
|
|
11377
|
+
args: [{ providedIn: 'root', useExisting: ɵWorkbenchDialogService }]
|
|
11378
|
+
}] });
|
|
11379
|
+
|
|
11380
|
+
/*
|
|
11381
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11382
|
+
*
|
|
11383
|
+
* This program and the accompanying materials are made
|
|
11384
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11385
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11386
|
+
*
|
|
11387
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11388
|
+
*/
|
|
11389
|
+
class MessageBoxFooterComponent {
|
|
11390
|
+
actions = input.required({ ...(ngDevMode ? { debugName: "actions" } : {}) });
|
|
11391
|
+
severity = input.required({ ...(ngDevMode ? { debugName: "severity" } : {}) });
|
|
11392
|
+
action = output();
|
|
11393
|
+
preferredSizeChange = output();
|
|
11394
|
+
_actionButtons = viewChildren('action_button', { ...(ngDevMode ? { debugName: "_actionButtons" } : {}) });
|
|
11395
|
+
constructor() {
|
|
11396
|
+
void this.emitPreferredSize();
|
|
11397
|
+
}
|
|
11398
|
+
insertionSortOrderFn = () => 0;
|
|
11399
|
+
onAction(key) {
|
|
11400
|
+
this.action.emit(key);
|
|
11401
|
+
}
|
|
11402
|
+
onArrowKey(index, direction) {
|
|
11403
|
+
const actionButtonCount = this._actionButtons().length;
|
|
11404
|
+
const newIndex = (direction === 'left' ? index - 1 : index + 1);
|
|
11405
|
+
this._actionButtons()[(newIndex + actionButtonCount) % actionButtonCount].nativeElement.focus();
|
|
11406
|
+
}
|
|
11407
|
+
async emitPreferredSize() {
|
|
11408
|
+
const host = inject(ElementRef).nativeElement;
|
|
11409
|
+
host.classList.add('calculating-min-width');
|
|
11410
|
+
try {
|
|
11411
|
+
// Wait for the CSS class to take effect, then wait an animation frame to avoid the error: "ResizeObserver loop completed with undelivered notifications".
|
|
11412
|
+
await firstValueFrom(fromResize$(host).pipe(observeOn(animationFrameScheduler)));
|
|
11413
|
+
this.preferredSizeChange.emit(host.offsetWidth);
|
|
11414
|
+
}
|
|
11415
|
+
finally {
|
|
11416
|
+
host.classList.remove('calculating-min-width');
|
|
11417
|
+
}
|
|
11493
11418
|
}
|
|
11419
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11420
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MessageBoxFooterComponent, isStandalone: true, selector: "wb-message-box-footer", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: true, transformFunction: null }, severity: { classPropertyName: "severity", publicName: "severity", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { action: "action", preferredSizeChange: "preferredSizeChange" }, host: { properties: { "attr.data-severity": "severity()" } }, viewQueries: [{ propertyName: "_actionButtons", predicate: ["action_button"], descendants: true, isSignal: true }], ngImport: i0, template: "@for (action of actions() | keyvalue:insertionSortOrderFn; track action.key) {\n <button #action_button\n (click)=\"onAction(action.key)\"\n (keydown.arrowLeft)=\"onArrowKey($index, 'left')\"\n (keydown.arrowRight)=\"onArrowKey($index, 'right')\"\n [attr.data-action]=\"action.key\"\n class=\"action e2e-action\">\n {{(action.value | wbText)()}}\n </button>\n\n @if (!$last) {\n <span class=\"divider\"></span>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{--\\275message-box-severity-color: initial;display:flex;height:3em;background-color:var(--sci-color-background-secondary);color:var(--sci-color-text)}:host[data-severity=info]{--\\275message-box-severity-color: var(--sci-color-accent)}:host[data-severity=warn]{--\\275message-box-severity-color: var(--sci-color-notice)}:host[data-severity=error]{--\\275message-box-severity-color: var(--sci-color-negative)}:host.calculating-min-width{position:absolute}:host>button.action:is(button,#sci-reset){all:unset;flex:1;margin:2px;border:1px solid transparent;border-radius:var(--sci-corner-small);transition:border-color ease-in-out .15s;cursor:var(--sci-workbench-messagebox-action-cursor);-webkit-user-select:none;user-select:none;text-align:center;min-width:7.5em;padding-inline:.5em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}:host>button.action:is(button,#sci-reset):focus,:host>button.action:is(button,#sci-reset):active{outline:none;color:var(--\\275message-box-severity-color);border-color:var(--\\275message-box-severity-color)}:host>button.action:is(button,#sci-reset):hover{background-color:var(--sci-workbench-messagebox-action-background-color-hover)}:host>span.divider{width:1px;background-color:var(--sci-color-border)}\n"], dependencies: [{ kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: TextPipe, name: "wbText" }] });
|
|
11421
|
+
}
|
|
11422
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxFooterComponent, decorators: [{
|
|
11423
|
+
type: Component,
|
|
11424
|
+
args: [{ selector: 'wb-message-box-footer', imports: [
|
|
11425
|
+
KeyValuePipe,
|
|
11426
|
+
TextPipe,
|
|
11427
|
+
], host: {
|
|
11428
|
+
'[attr.data-severity]': 'severity()',
|
|
11429
|
+
}, template: "@for (action of actions() | keyvalue:insertionSortOrderFn; track action.key) {\n <button #action_button\n (click)=\"onAction(action.key)\"\n (keydown.arrowLeft)=\"onArrowKey($index, 'left')\"\n (keydown.arrowRight)=\"onArrowKey($index, 'right')\"\n [attr.data-action]=\"action.key\"\n class=\"action e2e-action\">\n {{(action.value | wbText)()}}\n </button>\n\n @if (!$last) {\n <span class=\"divider\"></span>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{--\\275message-box-severity-color: initial;display:flex;height:3em;background-color:var(--sci-color-background-secondary);color:var(--sci-color-text)}:host[data-severity=info]{--\\275message-box-severity-color: var(--sci-color-accent)}:host[data-severity=warn]{--\\275message-box-severity-color: var(--sci-color-notice)}:host[data-severity=error]{--\\275message-box-severity-color: var(--sci-color-negative)}:host.calculating-min-width{position:absolute}:host>button.action:is(button,#sci-reset){all:unset;flex:1;margin:2px;border:1px solid transparent;border-radius:var(--sci-corner-small);transition:border-color ease-in-out .15s;cursor:var(--sci-workbench-messagebox-action-cursor);-webkit-user-select:none;user-select:none;text-align:center;min-width:7.5em;padding-inline:.5em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}:host>button.action:is(button,#sci-reset):focus,:host>button.action:is(button,#sci-reset):active{outline:none;color:var(--\\275message-box-severity-color);border-color:var(--\\275message-box-severity-color)}:host>button.action:is(button,#sci-reset):hover{background-color:var(--sci-workbench-messagebox-action-background-color-hover)}:host>span.divider{width:1px;background-color:var(--sci-color-border)}\n"] }]
|
|
11430
|
+
}], ctorParameters: () => [], propDecorators: { actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: true }] }], severity: [{ type: i0.Input, args: [{ isSignal: true, alias: "severity", required: true }] }], action: [{ type: i0.Output, args: ["action"] }], preferredSizeChange: [{ type: i0.Output, args: ["preferredSizeChange"] }], _actionButtons: [{ type: i0.ViewChildren, args: ['action_button', { isSignal: true }] }] } });
|
|
11431
|
+
|
|
11432
|
+
/*
|
|
11433
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11434
|
+
*
|
|
11435
|
+
* This program and the accompanying materials are made
|
|
11436
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11437
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11438
|
+
*
|
|
11439
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11440
|
+
*/
|
|
11441
|
+
/**
|
|
11442
|
+
* Use this directive to replace the default dialog footer that renders actions contributed via the {@link WorkbenchDialogActionDirective} directive.
|
|
11443
|
+
*
|
|
11444
|
+
* The host element of this modeling directive must be a <ng-template>. The footer shares the lifecycle of the host element.
|
|
11445
|
+
*
|
|
11446
|
+
* **Example:**
|
|
11447
|
+
* ```html
|
|
11448
|
+
* <ng-template wbDialogFooter>
|
|
11449
|
+
* <app-dialog-footer/>
|
|
11450
|
+
* </ng-template>
|
|
11451
|
+
* ```
|
|
11452
|
+
*/
|
|
11453
|
+
class WorkbenchDialogFooterDirective {
|
|
11494
11454
|
/**
|
|
11495
|
-
*
|
|
11455
|
+
* Specifies if to display a visual separator between the dialog content and this footer.
|
|
11456
|
+
* Defaults to `true`.
|
|
11496
11457
|
*/
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11458
|
+
divider = input(undefined, { ...(ngDevMode ? { debugName: "divider" } : {}), transform: booleanAttribute });
|
|
11459
|
+
template = inject(TemplateRef);
|
|
11460
|
+
_footer;
|
|
11461
|
+
constructor() {
|
|
11462
|
+
const dialog = inject(ɵWorkbenchDialog);
|
|
11463
|
+
// Defer registering footer to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
11464
|
+
asapScheduler.schedule(() => this._footer = dialog.registerFooter(this));
|
|
11465
|
+
// Defer disposing footer to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
11466
|
+
inject(DestroyRef).onDestroy(() => asapScheduler.schedule(() => this._footer?.dispose()));
|
|
11505
11467
|
}
|
|
11468
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11469
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.1", type: WorkbenchDialogFooterDirective, isStandalone: true, selector: "ng-template[wbDialogFooter]", inputs: { divider: { classPropertyName: "divider", publicName: "divider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
11470
|
+
}
|
|
11471
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogFooterDirective, decorators: [{
|
|
11472
|
+
type: Directive,
|
|
11473
|
+
args: [{ selector: 'ng-template[wbDialogFooter]' }]
|
|
11474
|
+
}], ctorParameters: () => [], propDecorators: { divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }] } });
|
|
11475
|
+
|
|
11476
|
+
/*
|
|
11477
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11478
|
+
*
|
|
11479
|
+
* This program and the accompanying materials are made
|
|
11480
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11481
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11482
|
+
*
|
|
11483
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11484
|
+
*/
|
|
11485
|
+
/**
|
|
11486
|
+
* Use this directive to replace the default dialog header that displays the title and a close button.
|
|
11487
|
+
*
|
|
11488
|
+
* The host element of this modeling directive must be a <ng-template>. The header shares the lifecycle of the host element.
|
|
11489
|
+
*
|
|
11490
|
+
* **Example:**
|
|
11491
|
+
* ```html
|
|
11492
|
+
* <ng-template wbDialogHeader>
|
|
11493
|
+
* <app-dialog-header/>
|
|
11494
|
+
* </ng-template>
|
|
11495
|
+
* ```
|
|
11496
|
+
*/
|
|
11497
|
+
class WorkbenchDialogHeaderDirective {
|
|
11506
11498
|
/**
|
|
11507
|
-
*
|
|
11499
|
+
* Specifies if to display a visual separator between this header and the dialog content.
|
|
11500
|
+
* Defaults to `true`.
|
|
11508
11501
|
*/
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11502
|
+
divider = input(undefined, { ...(ngDevMode ? { debugName: "divider" } : {}), transform: booleanAttribute });
|
|
11503
|
+
template = inject(TemplateRef);
|
|
11504
|
+
_header;
|
|
11505
|
+
constructor() {
|
|
11506
|
+
const dialog = inject(ɵWorkbenchDialog);
|
|
11507
|
+
// Defer registering header to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
11508
|
+
asapScheduler.schedule(() => this._header = dialog.registerHeader(this));
|
|
11509
|
+
// Defer disposing header to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
11510
|
+
inject(DestroyRef).onDestroy(() => asapScheduler.schedule(() => this._header?.dispose()));
|
|
11514
11511
|
}
|
|
11512
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11513
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.1", type: WorkbenchDialogHeaderDirective, isStandalone: true, selector: "ng-template[wbDialogHeader]", inputs: { divider: { classPropertyName: "divider", publicName: "divider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
11515
11514
|
}
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
}
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11515
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogHeaderDirective, decorators: [{
|
|
11516
|
+
type: Directive,
|
|
11517
|
+
args: [{ selector: 'ng-template[wbDialogHeader]' }]
|
|
11518
|
+
}], ctorParameters: () => [], propDecorators: { divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }] } });
|
|
11519
|
+
|
|
11520
|
+
/*
|
|
11521
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11522
|
+
*
|
|
11523
|
+
* This program and the accompanying materials are made
|
|
11524
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11525
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11526
|
+
*
|
|
11527
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11528
|
+
*/
|
|
11529
|
+
class MessageBoxHeaderComponent {
|
|
11530
|
+
title = input(undefined, { ...(ngDevMode ? { debugName: "title" } : {}) });
|
|
11531
|
+
severity = input.required({ ...(ngDevMode ? { debugName: "severity" } : {}) });
|
|
11532
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11533
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MessageBoxHeaderComponent, isStandalone: true, selector: "wb-message-box-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, severity: { classPropertyName: "severity", publicName: "severity", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-severity": "severity()" } }, ngImport: i0, template: "@if (title()) {\n <span class=\"title e2e-title\">{{(title() | wbText)()}}</span>\n}\n", styles: ["@charset \"UTF-8\";:host{--\\275message-box-severity-color: initial;display:grid;border-top:var(--sci-workbench-messagebox-severity-indicator-size) solid var(--\\275message-box-severity-color);padding-inline:var(--sci-workbench-messagebox-padding);padding-top:var(--sci-workbench-messagebox-padding);-webkit-user-select:none;user-select:none}:host[data-severity=info]{--\\275message-box-severity-color: var(--sci-color-accent)}:host[data-severity=warn]{--\\275message-box-severity-color: var(--sci-color-notice)}:host[data-severity=error]{--\\275message-box-severity-color: var(--sci-color-negative)}:host>span.title{word-break:break-word;white-space:pre-line;font-family:var(--sci-workbench-messagebox-title-font-family),sans-serif;font-size:var(--sci-workbench-messagebox-title-font-size);font-weight:var(--sci-workbench-messagebox-title-font-weight);text-align:var(--sci-workbench-messagebox-title-align)}\n"], dependencies: [{ kind: "pipe", type: TextPipe, name: "wbText" }] });
|
|
11534
|
+
}
|
|
11535
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxHeaderComponent, decorators: [{
|
|
11536
|
+
type: Component,
|
|
11537
|
+
args: [{ selector: 'wb-message-box-header', imports: [
|
|
11538
|
+
TextPipe,
|
|
11539
|
+
], host: {
|
|
11540
|
+
'[attr.data-severity]': 'severity()',
|
|
11541
|
+
}, template: "@if (title()) {\n <span class=\"title e2e-title\">{{(title() | wbText)()}}</span>\n}\n", styles: ["@charset \"UTF-8\";:host{--\\275message-box-severity-color: initial;display:grid;border-top:var(--sci-workbench-messagebox-severity-indicator-size) solid var(--\\275message-box-severity-color);padding-inline:var(--sci-workbench-messagebox-padding);padding-top:var(--sci-workbench-messagebox-padding);-webkit-user-select:none;user-select:none}:host[data-severity=info]{--\\275message-box-severity-color: var(--sci-color-accent)}:host[data-severity=warn]{--\\275message-box-severity-color: var(--sci-color-notice)}:host[data-severity=error]{--\\275message-box-severity-color: var(--sci-color-negative)}:host>span.title{word-break:break-word;white-space:pre-line;font-family:var(--sci-workbench-messagebox-title-font-family),sans-serif;font-size:var(--sci-workbench-messagebox-title-font-size);font-weight:var(--sci-workbench-messagebox-title-font-weight);text-align:var(--sci-workbench-messagebox-title-align)}\n"] }]
|
|
11542
|
+
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], severity: [{ type: i0.Input, args: [{ isSignal: true, alias: "severity", required: true }] }] } });
|
|
11543
|
+
|
|
11544
|
+
/*
|
|
11545
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
11546
|
+
*
|
|
11547
|
+
* This program and the accompanying materials are made
|
|
11548
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11549
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11550
|
+
*
|
|
11551
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11552
|
+
*/
|
|
11553
|
+
/**
|
|
11554
|
+
* Tests if the object is of the specified type.
|
|
11555
|
+
*/
|
|
11556
|
+
class TypeofPipe {
|
|
11557
|
+
transform(object, type) {
|
|
11558
|
+
return typeof object === type;
|
|
11551
11559
|
}
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11560
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: TypeofPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
11561
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.1", ngImport: i0, type: TypeofPipe, isStandalone: true, name: "wbTypeof" });
|
|
11562
|
+
}
|
|
11563
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: TypeofPipe, decorators: [{
|
|
11564
|
+
type: Pipe,
|
|
11565
|
+
args: [{ name: 'wbTypeof' }]
|
|
11566
|
+
}] });
|
|
11567
|
+
|
|
11568
|
+
/*
|
|
11569
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11570
|
+
*
|
|
11571
|
+
* This program and the accompanying materials are made
|
|
11572
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11573
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11574
|
+
*
|
|
11575
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11576
|
+
*/
|
|
11577
|
+
/**
|
|
11578
|
+
* Renders the workbench message box.
|
|
11579
|
+
*
|
|
11580
|
+
* This component is designed to be opened in a workbench dialog.
|
|
11581
|
+
*/
|
|
11582
|
+
class WorkbenchMessageBoxComponent {
|
|
11583
|
+
message = input.required({ ...(ngDevMode ? { debugName: "message" } : {}), transform: nullIfEmptyMessage });
|
|
11584
|
+
options = input(undefined, { ...(ngDevMode ? { debugName: "options" } : {}) });
|
|
11585
|
+
_dialog = inject(ɵWorkbenchDialog);
|
|
11586
|
+
empty = signal(false, { ...(ngDevMode ? { debugName: "empty" } : {}) });
|
|
11587
|
+
constructor() {
|
|
11588
|
+
this._dialog.closable = false;
|
|
11589
|
+
this._dialog.resizable = false;
|
|
11590
|
+
this._dialog.padding = false;
|
|
11591
|
+
// Limit the maximum messagebox width if text message to break the message.
|
|
11592
|
+
effect(() => {
|
|
11593
|
+
if (typeof this.message() === 'string' || this.message() === null) {
|
|
11594
|
+
this._dialog.size.maxWidth = 'var(--sci-workbench-messagebox-max-width)';
|
|
11595
|
+
}
|
|
11596
|
+
});
|
|
11555
11597
|
}
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
return this._minWidth;
|
|
11598
|
+
onAction(action) {
|
|
11599
|
+
this._dialog.close(action);
|
|
11559
11600
|
}
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11601
|
+
onEscape() {
|
|
11602
|
+
if ('cancel' in (this.options()?.actions ?? {})) {
|
|
11603
|
+
this._dialog.close('cancel');
|
|
11604
|
+
}
|
|
11563
11605
|
}
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
return this._maxWidth;
|
|
11606
|
+
onFooterPreferredSizeChange(preferredSize) {
|
|
11607
|
+
this._dialog.size.minWidth = `${preferredSize}px`;
|
|
11567
11608
|
}
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
untracked(() => this._maxWidth.set(maxWidth));
|
|
11609
|
+
onContentDimensionChange(dimension) {
|
|
11610
|
+
this.empty.set(!dimension.offsetHeight);
|
|
11571
11611
|
}
|
|
11612
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11613
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: WorkbenchMessageBoxComponent, isStandalone: true, selector: "wb-message-box", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown.escape": "onEscape()" }, properties: { "attr.tabindex": "-1", "class.empty": "empty()", "class.content-selectable": "options()?.contentSelectable", "class.has-title": "!!this.options()?.title" } }, ngImport: i0, template: "@let options = this.options() ?? {};\n<ng-template wbDialogHeader [divider]=\"false\">\n <wb-message-box-header [title]=\"options.title\" [severity]=\"options.severity ?? 'info'\"/>\n</ng-template>\n\n@let message = this.message();\n<div class=\"slot e2e-slot\" [class.text]=\"message | wbTypeof:'string'\" sciDimension (sciDimensionChange)=\"onContentDimensionChange($event)\">\n @if (message | wbTypeof:'string') {\n {{($any(message) | wbText)()}}\n } @else {\n <ng-container *ngComponentOutlet=\"message; inputs: options.inputs\"/>\n }\n</div>\n\n<ng-template wbDialogFooter>\n <wb-message-box-footer [actions]=\"options.actions ?? {ok: '%workbench.ok.action'}\"\n [severity]=\"options.severity ?? 'info'\"\n (action)=\"onAction($event)\"\n (keydown.escape)=\"onEscape()\"\n (preferredSizeChange)=\"onFooterPreferredSizeChange($event)\"/>\n</ng-template>\n", styles: [":host{display:grid;outline:none;padding-inline:var(--sci-workbench-messagebox-padding);padding-bottom:var(--sci-workbench-messagebox-padding)}:host.has-title:not(.empty){padding-top:var(--sci-workbench-messagebox-padding)}:host:not(.content-selectable){-webkit-user-select:none;user-select:none}:host>div.slot.text{word-break:break-word;white-space:pre-line;text-align:var(--sci-workbench-messagebox-text-align)}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: SciDimensionDirective, selector: "[sciDimension]", inputs: ["emitOutsideAngular"], outputs: ["sciDimensionChange"] }, { kind: "directive", type: WorkbenchDialogHeaderDirective, selector: "ng-template[wbDialogHeader]", inputs: ["divider"] }, { kind: "directive", type: WorkbenchDialogFooterDirective, selector: "ng-template[wbDialogFooter]", inputs: ["divider"] }, { kind: "component", type: MessageBoxHeaderComponent, selector: "wb-message-box-header", inputs: ["title", "severity"] }, { kind: "component", type: MessageBoxFooterComponent, selector: "wb-message-box-footer", inputs: ["actions", "severity"], outputs: ["action", "preferredSizeChange"] }, { kind: "pipe", type: TypeofPipe, name: "wbTypeof" }, { kind: "pipe", type: TextPipe, name: "wbText" }] });
|
|
11614
|
+
}
|
|
11615
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxComponent, decorators: [{
|
|
11616
|
+
type: Component,
|
|
11617
|
+
args: [{ selector: 'wb-message-box', imports: [
|
|
11618
|
+
NgComponentOutlet,
|
|
11619
|
+
SciDimensionDirective,
|
|
11620
|
+
WorkbenchDialogHeaderDirective,
|
|
11621
|
+
WorkbenchDialogFooterDirective,
|
|
11622
|
+
MessageBoxHeaderComponent,
|
|
11623
|
+
MessageBoxFooterComponent,
|
|
11624
|
+
TypeofPipe,
|
|
11625
|
+
TextPipe,
|
|
11626
|
+
], host: {
|
|
11627
|
+
// Ensure host element to be focusable in order to close the message box on Escape keystroke.
|
|
11628
|
+
'[attr.tabindex]': '-1',
|
|
11629
|
+
'[class.empty]': 'empty()',
|
|
11630
|
+
'[class.content-selectable]': 'options()?.contentSelectable',
|
|
11631
|
+
'[class.has-title]': '!!this.options()?.title',
|
|
11632
|
+
'(keydown.escape)': 'onEscape()',
|
|
11633
|
+
}, template: "@let options = this.options() ?? {};\n<ng-template wbDialogHeader [divider]=\"false\">\n <wb-message-box-header [title]=\"options.title\" [severity]=\"options.severity ?? 'info'\"/>\n</ng-template>\n\n@let message = this.message();\n<div class=\"slot e2e-slot\" [class.text]=\"message | wbTypeof:'string'\" sciDimension (sciDimensionChange)=\"onContentDimensionChange($event)\">\n @if (message | wbTypeof:'string') {\n {{($any(message) | wbText)()}}\n } @else {\n <ng-container *ngComponentOutlet=\"message; inputs: options.inputs\"/>\n }\n</div>\n\n<ng-template wbDialogFooter>\n <wb-message-box-footer [actions]=\"options.actions ?? {ok: '%workbench.ok.action'}\"\n [severity]=\"options.severity ?? 'info'\"\n (action)=\"onAction($event)\"\n (keydown.escape)=\"onEscape()\"\n (preferredSizeChange)=\"onFooterPreferredSizeChange($event)\"/>\n</ng-template>\n", styles: [":host{display:grid;outline:none;padding-inline:var(--sci-workbench-messagebox-padding);padding-bottom:var(--sci-workbench-messagebox-padding)}:host.has-title:not(.empty){padding-top:var(--sci-workbench-messagebox-padding)}:host:not(.content-selectable){-webkit-user-select:none;user-select:none}:host>div.slot.text{word-break:break-word;white-space:pre-line;text-align:var(--sci-workbench-messagebox-text-align)}\n"] }]
|
|
11634
|
+
}], ctorParameters: () => [], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }] } });
|
|
11635
|
+
function nullIfEmptyMessage(message) {
|
|
11636
|
+
return message !== '' ? message : null;
|
|
11572
11637
|
}
|
|
11573
11638
|
|
|
11574
11639
|
/*
|
|
@@ -11581,95 +11646,103 @@ class ɵWorkbenchDialogSize {
|
|
|
11581
11646
|
* SPDX-License-Identifier: EPL-2.0
|
|
11582
11647
|
*/
|
|
11583
11648
|
/** @inheritDoc */
|
|
11584
|
-
class
|
|
11585
|
-
|
|
11586
|
-
_rootInjector = inject(ApplicationRef).injector;
|
|
11587
|
-
_dialogRegistry = inject(WorkbenchDialogRegistry);
|
|
11588
|
-
_document = inject(DOCUMENT);
|
|
11649
|
+
class ɵWorkbenchMessageBoxService {
|
|
11650
|
+
_workbenchDialogService = inject(WorkbenchDialogService);
|
|
11589
11651
|
_zone = inject(NgZone);
|
|
11590
11652
|
constructor() {
|
|
11591
11653
|
this.installServiceLifecycleLogger();
|
|
11592
11654
|
}
|
|
11593
|
-
/** @inheritDoc */
|
|
11594
|
-
async open(component, options) {
|
|
11595
|
-
assertNotInReactiveContext(this.open, 'Call WorkbenchDialogService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
11596
|
-
// Ensure to run in Angular zone to display the dialog even when called from outside the Angular zone.
|
|
11597
|
-
if (!NgZone.isInAngularZone()) {
|
|
11598
|
-
return this._zone.run(() => this.open(component, options));
|
|
11599
|
-
}
|
|
11600
|
-
// Delay the opening of a context-modal dialog until all application-modal dialogs are closed.
|
|
11601
|
-
// Otherwise, the context-modal dialog would overlap already opened application-modal dialogs.
|
|
11602
|
-
const invocationContext = createDialogInvocationContext(options ?? {}, this._injector);
|
|
11603
|
-
if (invocationContext) {
|
|
11604
|
-
await this.waitUntilApplicationModalDialogsClosed();
|
|
11605
|
-
}
|
|
11606
|
-
// Create the dialog.
|
|
11607
|
-
const dialog = this.createDialog(component, invocationContext, options ?? {});
|
|
11608
|
-
this._dialogRegistry.register(dialog.id, dialog);
|
|
11609
|
-
// Capture focused element to restore focus when closing the dialog.
|
|
11610
|
-
const previouslyFocusedElement = this._document.activeElement instanceof HTMLElement ? this._document.activeElement : undefined;
|
|
11611
|
-
try {
|
|
11612
|
-
return await dialog.waitForClose();
|
|
11613
|
-
}
|
|
11614
|
-
finally {
|
|
11615
|
-
this._dialogRegistry.unregister(dialog.id);
|
|
11616
|
-
// Restore focus to previously focused element when closing the last dialog in the current context.
|
|
11617
|
-
if (previouslyFocusedElement && !this._dialogRegistry.top(invocationContext?.elementId)()) {
|
|
11618
|
-
previouslyFocusedElement.focus();
|
|
11619
|
-
}
|
|
11620
|
-
}
|
|
11621
|
-
}
|
|
11622
|
-
/**
|
|
11623
|
-
* Creates the dialog handle.
|
|
11624
|
-
*/
|
|
11625
|
-
createDialog(component, invocationContext, options) {
|
|
11626
|
-
// Construct the handle in an injection context that shares the dialog's lifecycle, allowing for automatic cleanup of effects and RxJS interop functions.
|
|
11627
|
-
const dialogId = computeDialogId();
|
|
11628
|
-
const dialogInjector = Injector.create({
|
|
11629
|
-
parent: this._rootInjector, // use root injector to be independent of service construction context
|
|
11630
|
-
providers: [],
|
|
11631
|
-
name: `Workbench Dialog ${dialogId}`,
|
|
11632
|
-
});
|
|
11633
|
-
return runInInjectionContext(dialogInjector, () => new ɵWorkbenchDialog(dialogId, component, invocationContext, options));
|
|
11634
|
-
}
|
|
11635
11655
|
/**
|
|
11636
|
-
*
|
|
11656
|
+
* @inheritDoc
|
|
11637
11657
|
*/
|
|
11638
|
-
async
|
|
11639
|
-
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
|
|
11658
|
+
async open(message, options) {
|
|
11659
|
+
assertNotInReactiveContext(this.open, 'Call WorkbenchMessageBoxService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
11660
|
+
// Ensure to run in Angular zone to display the message box even if called from outside the Angular zone, e.g. from an error handler.
|
|
11661
|
+
if (!NgZone.isInAngularZone()) {
|
|
11662
|
+
return this._zone.run(() => this.open(message, options));
|
|
11663
|
+
}
|
|
11664
|
+
return (await this._workbenchDialogService.open(WorkbenchMessageBoxComponent, {
|
|
11665
|
+
inputs: { message, options },
|
|
11666
|
+
modality: options?.modality,
|
|
11667
|
+
injector: options?.injector,
|
|
11668
|
+
providers: options?.providers,
|
|
11669
|
+
cssClass: options?.cssClass,
|
|
11670
|
+
context: options?.context,
|
|
11671
|
+
animate: true,
|
|
11672
|
+
}));
|
|
11643
11673
|
}
|
|
11644
11674
|
installServiceLifecycleLogger() {
|
|
11645
11675
|
const logger = inject(Logger);
|
|
11646
11676
|
const workbenchElement = inject(WORKBENCH_ELEMENT, { optional: true });
|
|
11647
|
-
logger.debug(() => `Constructing
|
|
11648
|
-
inject(DestroyRef).onDestroy(() => logger.debug(() => `Destroying
|
|
11677
|
+
logger.debug(() => `Constructing WorkbenchMessageBoxService [context=${workbenchElement?.id}]`, LoggerNames.LIFECYCLE);
|
|
11678
|
+
inject(DestroyRef).onDestroy(() => logger.debug(() => `Destroying WorkbenchMessageBoxService [context=${workbenchElement?.id}]'`, LoggerNames.LIFECYCLE));
|
|
11649
11679
|
}
|
|
11650
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
11651
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
11680
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11681
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, providedIn: 'root' });
|
|
11652
11682
|
}
|
|
11653
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
11683
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, decorators: [{
|
|
11654
11684
|
type: Injectable,
|
|
11655
11685
|
args: [{ providedIn: 'root' }]
|
|
11656
11686
|
}], ctorParameters: () => [] });
|
|
11687
|
+
|
|
11657
11688
|
/**
|
|
11658
|
-
*
|
|
11689
|
+
* Provides a standardized dialog for presenting a message to the user, such as an info, warning or alert,
|
|
11690
|
+
* or for prompting the user for confirmation. The message can be plain text or a component, allowing for
|
|
11691
|
+
* structured content or input prompts.
|
|
11692
|
+
*
|
|
11693
|
+
* Displayed on top of other content, a modal message box blocks interaction with other parts of the application.
|
|
11694
|
+
*
|
|
11695
|
+
* ## Modality
|
|
11696
|
+
* A message box can be context-modal or application-modal. Context-modal blocks a specific part of the application, as specified by the context;
|
|
11697
|
+
* application-modal blocks the workbench or browser viewport, based on {@link WorkbenchConfig.dialog.modalityScope}.
|
|
11698
|
+
*
|
|
11699
|
+
* ## Context
|
|
11700
|
+
* A message box can be bound to a context (e.g., part or view), defaulting to the calling context.
|
|
11701
|
+
* The message box is displayed only if the context is visible and closes when the context is disposed.
|
|
11702
|
+
*
|
|
11703
|
+
* ## Positioning
|
|
11704
|
+
* A message box is opened in the center of its context, if any, unless opened from the peripheral area.
|
|
11705
|
+
*
|
|
11706
|
+
* ## Stacking
|
|
11707
|
+
* Message boxes are stacked per modality, with only the topmost message box in each stack being interactive.
|
|
11708
|
+
*
|
|
11709
|
+
* ## Styling
|
|
11710
|
+
* The following CSS variables can be set to customize the default look of a message box.
|
|
11711
|
+
*
|
|
11712
|
+
* - `--sci-workbench-messagebox-max-width`
|
|
11713
|
+
* - `--sci-workbench-messagebox-severity-indicator-size`
|
|
11714
|
+
* - `--sci-workbench-messagebox-padding`
|
|
11715
|
+
* - `--sci-workbench-messagebox-text-align`
|
|
11716
|
+
* - `--sci-workbench-messagebox-title-align`
|
|
11717
|
+
* - `--sci-workbench-messagebox-title-font-family`
|
|
11718
|
+
* - `--sci-workbench-messagebox-title-font-weight`
|
|
11719
|
+
* - `--sci-workbench-messagebox-title-font-size`
|
|
11659
11720
|
*/
|
|
11660
|
-
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
}
|
|
11664
|
-
return createInvocationContext(options.context && (typeof options.context === 'object' ? options.context.viewId : options.context), { injector });
|
|
11721
|
+
class WorkbenchMessageBoxService {
|
|
11722
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11723
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, providedIn: 'root', useExisting: ɵWorkbenchMessageBoxService });
|
|
11665
11724
|
}
|
|
11725
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, decorators: [{
|
|
11726
|
+
type: Injectable,
|
|
11727
|
+
args: [{ providedIn: 'root', useExisting: ɵWorkbenchMessageBoxService }]
|
|
11728
|
+
}] });
|
|
11729
|
+
|
|
11730
|
+
/*
|
|
11731
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
11732
|
+
*
|
|
11733
|
+
* This program and the accompanying materials are made
|
|
11734
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11735
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11736
|
+
*
|
|
11737
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11738
|
+
*/
|
|
11666
11739
|
/**
|
|
11667
|
-
* Provides {@link
|
|
11740
|
+
* Provides {@link WorkbenchMessageBoxService} for dependency injection.
|
|
11668
11741
|
*/
|
|
11669
|
-
function
|
|
11742
|
+
function provideWorkbenchMessageBoxService() {
|
|
11670
11743
|
return [
|
|
11671
|
-
|
|
11672
|
-
{ provide:
|
|
11744
|
+
ɵWorkbenchMessageBoxService,
|
|
11745
|
+
{ provide: WorkbenchMessageBoxService, useExisting: ɵWorkbenchMessageBoxService },
|
|
11673
11746
|
];
|
|
11674
11747
|
}
|
|
11675
11748
|
|
|
@@ -12651,6 +12724,11 @@ class ViewTabComponent {
|
|
|
12651
12724
|
event.stopPropagation();
|
|
12652
12725
|
event.preventDefault();
|
|
12653
12726
|
}
|
|
12727
|
+
onMouseDown(event) {
|
|
12728
|
+
if (event.button === 1) { // primary aux button
|
|
12729
|
+
event.preventDefault(); // prevent middle-click scrolling; necessary for aux click to work
|
|
12730
|
+
}
|
|
12731
|
+
}
|
|
12654
12732
|
onDragStart(event) {
|
|
12655
12733
|
if (!event.dataTransfer) {
|
|
12656
12734
|
return;
|
|
@@ -12715,7 +12793,7 @@ class ViewTabComponent {
|
|
|
12715
12793
|
});
|
|
12716
12794
|
}
|
|
12717
12795
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ViewTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12718
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: ViewTabComponent, isStandalone: true, selector: "wb-view-tab", inputs: { view: { classPropertyName: "view", publicName: "viewId", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "onClick()", "auxclick": "onAuxClick($event)", "contextmenu": "onContextmenu($event)", "dragstart": "onDragStart($event)", "dragend": "onDragEnd()" }, properties: { "attr.data-viewid": "view().id", "attr.data-active": "view().active() ? '' : null", "attr.data-dirty": "view().dirty() ? '' : null", "attr.data-focus-within-view": "view().focused() ? '' : null", "attr.draggable": "true", "attr.tabindex": "-1", "class.view-drag": "viewDragService.dragging()", "class": "view().classList.asList()", "style.--sci-workbench-tab-title-offset-right": "viewTitleOffsetRight()" } }, ngImport: i0, template: "<!-- IMPORTANT: THIS HTML FILE IS ALSO USED BY `ViewTabDragImageComponent` -->\n\n@if (view().active()) {\n <div class=\"corner-radius start\">\n <div class=\"circle\"></div>\n </div>\n}\n\n<div class=\"content\">\n <ng-container *cdkPortalOutlet=\"viewTabContentPortal()\"/>\n</div>\n\n@if (view().active()) {\n <div class=\"corner-radius end\">\n <div class=\"circle\"></div>\n </div>\n}\n\n@if (view().closable()) {\n <button (click)=\"onClose($event)\"\n [title]=\"('%workbench.close_tab.tooltip;close_others_modifier=Alt' | wbText)()\"\n [disabled]=\"!view().isClosable()\"\n class=\"close e2e-close\">\n <wb-icon icon=\"workbench.close\"/>\n </button>\n}\n", styles: [":host{display:grid;align-items:center;padding-left:var(--sci-workbench-tab-padding-inline);padding-right:var(--sci-workbench-tab-padding-inline);position:relative;-webkit-user-select:none;user-select:none;cursor:var(--sci-workbench-tab-cursor);box-sizing:border-box;outline:none;border-top:var(--sci-workbench-tab-border-top-width) solid transparent;border-left:var(--sci-workbench-tab-border-width) solid transparent;border-right:var(--sci-workbench-tab-border-width) solid transparent;border-top-left-radius:var(--sci-workbench-tab-border-radius);border-top-right-radius:var(--sci-workbench-tab-border-radius)}:host[data-active]{cursor:default;border-left-color:var(--sci-workbench-tab-border-color);border-right-color:var(--sci-workbench-tab-border-color);border-top-color:var(--sci-workbench-tab-border-color);background-color:var(--sci-workbench-view-background-color)}wb-part[data-peripheral] :host[data-active]{background-color:var(--sci-workbench-view-peripheral-background-color)}:host[data-active]>div.content{color:var(--sci-workbench-tab-text-color-active)}:host[data-active][data-focus-within-view]>div.content{color:var(--sci-workbench-part-active-tab-text-color-active)}:host>div.content{display:inline-grid;font-family:var(--sci-workbench-tab-font-family),sans-serif;font-size:var(--sci-workbench-tab-font-size);font-weight:var(--sci-workbench-tab-font-weight);min-width:var(--sci-workbench-tab-min-width);max-width:var(--sci-workbench-tab-max-width);isolation:isolate;transform:translateY(calc(-1 * var(--sci-workbench-tab-border-top-width)))}:host>button.close:is(button,#sci-reset){all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-corner);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-workbench-button-cursor)}:host>button.close:is(button,#sci-reset):hover:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-hover)}:host>button.close:is(button,#sci-reset):active:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-active)}:host>button.close:is(button,#sci-reset):focus:not(:focus-visible){outline:none}:host>button.close:is(button,#sci-reset):focus-visible{outline:var(--sci-workbench-button-outline-width-focus) solid var(--sci-color-accent)}:host>button.close:is(button,#sci-reset):disabled{color:var(--sci-color-gray-500)}:host>button.close:is(button,#sci-reset){position:absolute;right:calc(var(--sci-workbench-tab-padding-inline) - .125em);visibility:hidden;padding:.125em;border-radius:var(--sci-corner-small);transform:translateY(calc(-1 * var(--sci-workbench-tab-border-top-width)))}:host[data-active]>button.close:is(button,#sci-reset),:host:hover:not(.view-drag)>button.close:is(button,#sci-reset){visibility:visible}@container style(--sci-workbench-tab-background-color-hover){:host:hover:not([data-active]):not(.view-drag):before{content:\"\";position:absolute;place-self:start center;box-sizing:border-box;height:calc(100% - var(--sci-workbench-tab-padding-block-hover) - var(--sci-workbench-part-bar-border-bottom-width));width:calc(100% - var(--sci-workbench-tab-padding-inline-hover) + 2 * var(--sci-workbench-tab-border-width));background-color:var(--sci-workbench-tab-background-color-hover);border:var(--sci-workbench-tab-border-width) solid var(--sci-workbench-tab-background-color-hover);border-radius:var(--sci-workbench-tab-border-radius);pointer-events:none}:host:hover:not([data-active]):not(.view-drag)>button.close:is(button,#sci-reset):not(:disabled):hover{background-color:color-mix(in srgb,var(--sci-workbench-tab-background-color-hover) 90%,light-dark(var(--sci-static-color-black),var(--sci-static-color-white)))}}:host>div.corner-radius{height:var(--sci-workbench-tab-border-radius);width:var(--sci-workbench-tab-border-radius);overflow:hidden;position:absolute;bottom:0}:host>div.corner-radius>div.circle{position:absolute;top:calc(-2 * var(--sci-workbench-tab-border-radius));width:calc(2 * var(--sci-workbench-tab-border-radius));height:calc(2 * var(--sci-workbench-tab-border-radius));border:var(--sci-workbench-tab-border-radius) solid var(--sci-workbench-view-background-color);border-radius:50%;box-shadow:inset 0 0 0 var(--sci-workbench-tab-border-width) var(--sci-workbench-tab-border-color);box-sizing:content-box}wb-part[data-peripheral] :host>div.corner-radius>div.circle{border-color:var(--sci-workbench-view-peripheral-background-color)}:host>div.corner-radius.start{left:calc(-1 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.start>div.circle{left:calc(-2 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.end{right:calc(-1 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.end>div.circle{right:calc(-2 * var(--sci-workbench-tab-border-radius))}@container viewtab (height >= 3.5rem){:host>button.close:is(button,#sci-reset){top:5px;right:5px}}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "component", type: IconComponent, selector: "wb-icon", inputs: ["icon"] }, { kind: "pipe", type: TextPipe, name: "wbText" }] });
|
|
12796
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: ViewTabComponent, isStandalone: true, selector: "wb-view-tab", inputs: { view: { classPropertyName: "view", publicName: "viewId", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "onClick()", "auxclick": "onAuxClick($event)", "contextmenu": "onContextmenu($event)", "mousedown": "onMouseDown($event)", "dragstart": "onDragStart($event)", "dragend": "onDragEnd()" }, properties: { "attr.data-viewid": "view().id", "attr.data-active": "view().active() ? '' : null", "attr.data-dirty": "view().dirty() ? '' : null", "attr.data-focus-within-view": "view().focused() ? '' : null", "attr.draggable": "true", "attr.tabindex": "-1", "class.view-drag": "viewDragService.dragging()", "class": "view().classList.asList()", "style.--sci-workbench-tab-title-offset-right": "viewTitleOffsetRight()" } }, ngImport: i0, template: "<!-- IMPORTANT: THIS HTML FILE IS ALSO USED BY `ViewTabDragImageComponent` -->\n\n@if (view().active()) {\n <div class=\"corner-radius start\">\n <div class=\"circle\"></div>\n </div>\n}\n\n<div class=\"content\">\n <ng-container *cdkPortalOutlet=\"viewTabContentPortal()\"/>\n</div>\n\n@if (view().active()) {\n <div class=\"corner-radius end\">\n <div class=\"circle\"></div>\n </div>\n}\n\n@if (view().closable()) {\n <button (click)=\"onClose($event)\"\n [title]=\"('%workbench.close_tab.tooltip;close_others_modifier=Alt' | wbText)()\"\n [disabled]=\"!view().isClosable()\"\n class=\"close e2e-close\">\n <wb-icon icon=\"workbench.close\"/>\n </button>\n}\n", styles: [":host{display:grid;align-items:center;padding-left:var(--sci-workbench-tab-padding-inline);padding-right:var(--sci-workbench-tab-padding-inline);position:relative;-webkit-user-select:none;user-select:none;cursor:var(--sci-workbench-tab-cursor);box-sizing:border-box;outline:none;border-top:var(--sci-workbench-tab-border-top-width) solid transparent;border-left:var(--sci-workbench-tab-border-width) solid transparent;border-right:var(--sci-workbench-tab-border-width) solid transparent;border-top-left-radius:var(--sci-workbench-tab-border-radius);border-top-right-radius:var(--sci-workbench-tab-border-radius)}:host[data-active]{cursor:default;border-left-color:var(--sci-workbench-tab-border-color);border-right-color:var(--sci-workbench-tab-border-color);border-top-color:var(--sci-workbench-tab-border-color);background-color:var(--sci-workbench-view-background-color)}wb-part[data-peripheral] :host[data-active]{background-color:var(--sci-workbench-view-peripheral-background-color)}:host[data-active]>div.content{color:var(--sci-workbench-tab-text-color-active)}:host[data-active][data-focus-within-view]>div.content{color:var(--sci-workbench-part-active-tab-text-color-active)}:host>div.content{display:inline-grid;font-family:var(--sci-workbench-tab-font-family),sans-serif;font-size:var(--sci-workbench-tab-font-size);font-weight:var(--sci-workbench-tab-font-weight);min-width:var(--sci-workbench-tab-min-width);max-width:var(--sci-workbench-tab-max-width);isolation:isolate;transform:translateY(calc(-1 * var(--sci-workbench-tab-border-top-width)))}:host>button.close:is(button,#sci-reset){all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-corner);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-workbench-button-cursor)}:host>button.close:is(button,#sci-reset):hover:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-hover)}:host>button.close:is(button,#sci-reset):active:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-active)}:host>button.close:is(button,#sci-reset):focus:not(:focus-visible){outline:none}:host>button.close:is(button,#sci-reset):focus-visible{outline:var(--sci-workbench-button-outline-width-focus) solid var(--sci-color-accent)}:host>button.close:is(button,#sci-reset):disabled{color:var(--sci-color-gray-500)}:host>button.close:is(button,#sci-reset){position:absolute;right:calc(var(--sci-workbench-tab-padding-inline) - .125em);visibility:hidden;padding:.125em;border-radius:var(--sci-corner-small);transform:translateY(calc(-1 * var(--sci-workbench-tab-border-top-width)))}:host[data-active]>button.close:is(button,#sci-reset),:host:hover:not(.view-drag)>button.close:is(button,#sci-reset){visibility:visible}@container style(--sci-workbench-tab-background-color-hover){:host:hover:not([data-active]):not(.view-drag):before{content:\"\";position:absolute;place-self:start center;box-sizing:border-box;height:calc(100% - var(--sci-workbench-tab-padding-block-hover) - var(--sci-workbench-part-bar-border-bottom-width));width:calc(100% - var(--sci-workbench-tab-padding-inline-hover) + 2 * var(--sci-workbench-tab-border-width));background-color:var(--sci-workbench-tab-background-color-hover);border:var(--sci-workbench-tab-border-width) solid var(--sci-workbench-tab-background-color-hover);border-radius:var(--sci-workbench-tab-border-radius);pointer-events:none}:host:hover:not([data-active]):not(.view-drag)>button.close:is(button,#sci-reset):not(:disabled):hover{background-color:color-mix(in srgb,var(--sci-workbench-tab-background-color-hover) 90%,light-dark(var(--sci-static-color-black),var(--sci-static-color-white)))}}:host>div.corner-radius{height:var(--sci-workbench-tab-border-radius);width:var(--sci-workbench-tab-border-radius);overflow:hidden;position:absolute;bottom:0}:host>div.corner-radius>div.circle{position:absolute;top:calc(-2 * var(--sci-workbench-tab-border-radius));width:calc(2 * var(--sci-workbench-tab-border-radius));height:calc(2 * var(--sci-workbench-tab-border-radius));border:var(--sci-workbench-tab-border-radius) solid var(--sci-workbench-view-background-color);border-radius:50%;box-shadow:inset 0 0 0 var(--sci-workbench-tab-border-width) var(--sci-workbench-tab-border-color);box-sizing:content-box}wb-part[data-peripheral] :host>div.corner-radius>div.circle{border-color:var(--sci-workbench-view-peripheral-background-color)}:host>div.corner-radius.start{left:calc(-1 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.start>div.circle{left:calc(-2 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.end{right:calc(-1 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.end>div.circle{right:calc(-2 * var(--sci-workbench-tab-border-radius))}@container viewtab (height >= 3.5rem){:host>button.close:is(button,#sci-reset){top:5px;right:5px}}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "component", type: IconComponent, selector: "wb-icon", inputs: ["icon"] }, { kind: "pipe", type: TextPipe, name: "wbText" }] });
|
|
12719
12797
|
}
|
|
12720
12798
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ViewTabComponent, decorators: [{
|
|
12721
12799
|
type: Component,
|
|
@@ -12736,6 +12814,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
12736
12814
|
'(click)': 'onClick()',
|
|
12737
12815
|
'(auxclick)': 'onAuxClick($event)',
|
|
12738
12816
|
'(contextmenu)': 'onContextmenu($event)',
|
|
12817
|
+
'(mousedown)': 'onMouseDown($event)',
|
|
12739
12818
|
'(dragstart)': 'onDragStart($event)',
|
|
12740
12819
|
'(dragend)': 'onDragEnd()',
|
|
12741
12820
|
}, template: "<!-- IMPORTANT: THIS HTML FILE IS ALSO USED BY `ViewTabDragImageComponent` -->\n\n@if (view().active()) {\n <div class=\"corner-radius start\">\n <div class=\"circle\"></div>\n </div>\n}\n\n<div class=\"content\">\n <ng-container *cdkPortalOutlet=\"viewTabContentPortal()\"/>\n</div>\n\n@if (view().active()) {\n <div class=\"corner-radius end\">\n <div class=\"circle\"></div>\n </div>\n}\n\n@if (view().closable()) {\n <button (click)=\"onClose($event)\"\n [title]=\"('%workbench.close_tab.tooltip;close_others_modifier=Alt' | wbText)()\"\n [disabled]=\"!view().isClosable()\"\n class=\"close e2e-close\">\n <wb-icon icon=\"workbench.close\"/>\n </button>\n}\n", styles: [":host{display:grid;align-items:center;padding-left:var(--sci-workbench-tab-padding-inline);padding-right:var(--sci-workbench-tab-padding-inline);position:relative;-webkit-user-select:none;user-select:none;cursor:var(--sci-workbench-tab-cursor);box-sizing:border-box;outline:none;border-top:var(--sci-workbench-tab-border-top-width) solid transparent;border-left:var(--sci-workbench-tab-border-width) solid transparent;border-right:var(--sci-workbench-tab-border-width) solid transparent;border-top-left-radius:var(--sci-workbench-tab-border-radius);border-top-right-radius:var(--sci-workbench-tab-border-radius)}:host[data-active]{cursor:default;border-left-color:var(--sci-workbench-tab-border-color);border-right-color:var(--sci-workbench-tab-border-color);border-top-color:var(--sci-workbench-tab-border-color);background-color:var(--sci-workbench-view-background-color)}wb-part[data-peripheral] :host[data-active]{background-color:var(--sci-workbench-view-peripheral-background-color)}:host[data-active]>div.content{color:var(--sci-workbench-tab-text-color-active)}:host[data-active][data-focus-within-view]>div.content{color:var(--sci-workbench-part-active-tab-text-color-active)}:host>div.content{display:inline-grid;font-family:var(--sci-workbench-tab-font-family),sans-serif;font-size:var(--sci-workbench-tab-font-size);font-weight:var(--sci-workbench-tab-font-weight);min-width:var(--sci-workbench-tab-min-width);max-width:var(--sci-workbench-tab-max-width);isolation:isolate;transform:translateY(calc(-1 * var(--sci-workbench-tab-border-top-width)))}:host>button.close:is(button,#sci-reset){all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-corner);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-workbench-button-cursor)}:host>button.close:is(button,#sci-reset):hover:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-hover)}:host>button.close:is(button,#sci-reset):active:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-active)}:host>button.close:is(button,#sci-reset):focus:not(:focus-visible){outline:none}:host>button.close:is(button,#sci-reset):focus-visible{outline:var(--sci-workbench-button-outline-width-focus) solid var(--sci-color-accent)}:host>button.close:is(button,#sci-reset):disabled{color:var(--sci-color-gray-500)}:host>button.close:is(button,#sci-reset){position:absolute;right:calc(var(--sci-workbench-tab-padding-inline) - .125em);visibility:hidden;padding:.125em;border-radius:var(--sci-corner-small);transform:translateY(calc(-1 * var(--sci-workbench-tab-border-top-width)))}:host[data-active]>button.close:is(button,#sci-reset),:host:hover:not(.view-drag)>button.close:is(button,#sci-reset){visibility:visible}@container style(--sci-workbench-tab-background-color-hover){:host:hover:not([data-active]):not(.view-drag):before{content:\"\";position:absolute;place-self:start center;box-sizing:border-box;height:calc(100% - var(--sci-workbench-tab-padding-block-hover) - var(--sci-workbench-part-bar-border-bottom-width));width:calc(100% - var(--sci-workbench-tab-padding-inline-hover) + 2 * var(--sci-workbench-tab-border-width));background-color:var(--sci-workbench-tab-background-color-hover);border:var(--sci-workbench-tab-border-width) solid var(--sci-workbench-tab-background-color-hover);border-radius:var(--sci-workbench-tab-border-radius);pointer-events:none}:host:hover:not([data-active]):not(.view-drag)>button.close:is(button,#sci-reset):not(:disabled):hover{background-color:color-mix(in srgb,var(--sci-workbench-tab-background-color-hover) 90%,light-dark(var(--sci-static-color-black),var(--sci-static-color-white)))}}:host>div.corner-radius{height:var(--sci-workbench-tab-border-radius);width:var(--sci-workbench-tab-border-radius);overflow:hidden;position:absolute;bottom:0}:host>div.corner-radius>div.circle{position:absolute;top:calc(-2 * var(--sci-workbench-tab-border-radius));width:calc(2 * var(--sci-workbench-tab-border-radius));height:calc(2 * var(--sci-workbench-tab-border-radius));border:var(--sci-workbench-tab-border-radius) solid var(--sci-workbench-view-background-color);border-radius:50%;box-shadow:inset 0 0 0 var(--sci-workbench-tab-border-width) var(--sci-workbench-tab-border-color);box-sizing:content-box}wb-part[data-peripheral] :host>div.corner-radius>div.circle{border-color:var(--sci-workbench-view-peripheral-background-color)}:host>div.corner-radius.start{left:calc(-1 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.start>div.circle{left:calc(-2 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.end{right:calc(-1 * var(--sci-workbench-tab-border-radius))}:host>div.corner-radius.end>div.circle{right:calc(-2 * var(--sci-workbench-tab-border-radius))}@container viewtab (height >= 3.5rem){:host>button.close:is(button,#sci-reset){top:5px;right:5px}}\n"] }]
|
|
@@ -13680,7 +13759,7 @@ class PartComponent {
|
|
|
13680
13759
|
inject(DestroyRef).onDestroy(() => logger.debug(() => `Destroying PartComponent [partId=${this.part.id}]'`, LoggerNames.LIFECYCLE));
|
|
13681
13760
|
}
|
|
13682
13761
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13683
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: PartComponent, isStandalone: true, selector: "wb-part", host: { properties: { "attr.data-partid": "part.id", "attr.data-peripheral": "part.peripheral() ? '' : null", "attr.data-grid": "dasherize(part.gridName())", "attr.data-active": "part.active() ? '' : null", "attr.data-referencepart": "part.referencePart() ? '' : null", "attr.tabindex": "-1", "class": "part.classList.asList()" } }, ngImport: i0, template: "@if (part.title() || part.views().length || part.actions().length || part.canMinimize()) {\n <wb-part-bar/>\n}\n\n@if (part.views().length) {\n <!-- Prevent splitting if there is no active view, i.e, when dragging the last view out of the tabbar. -->\n @let canSplit = !!part.activeView();\n <div wbViewDropZone\n [wbViewDropZoneRegionSize]=\".25\"\n [wbViewDropZonePlaceholderSize]=\".5\"\n [wbViewDropZoneAttributes]=\"{'data-partid': part.id}\"\n [wbViewDropZoneRegions]=\"canDrop() && {center: true, north: canSplit, south: canSplit, west: canSplit, east: canSplit}\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"
|
|
13762
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: PartComponent, isStandalone: true, selector: "wb-part", host: { properties: { "attr.data-partid": "part.id", "attr.data-peripheral": "part.peripheral() ? '' : null", "attr.data-grid": "dasherize(part.gridName())", "attr.data-active": "part.active() ? '' : null", "attr.data-referencepart": "part.referencePart() ? '' : null", "attr.tabindex": "-1", "class": "part.classList.asList()" } }, ngImport: i0, template: "@if (part.title() || part.views().length || part.actions().length || part.canMinimize()) {\n <wb-part-bar/>\n}\n\n@if (part.views().length) {\n <!-- Prevent splitting if there is no active view, i.e, when dragging the last view out of the tabbar. -->\n @let canSplit = !!part.activeView();\n <div wbViewDropZone\n [wbViewDropZoneRegionSize]=\".25\"\n [wbViewDropZonePlaceholderSize]=\".5\"\n [wbViewDropZoneAttributes]=\"{'data-partid': part.id}\"\n [wbViewDropZoneRegions]=\"canDrop() && {center: true, north: canSplit, south: canSplit, west: canSplit, east: canSplit}\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"slot e2e-slot e2e-view-slot\">\n <ng-container *wbPortalOutlet=\"part.activeView()?.slot!.portal; destroyOnDetach: false\"/>\n </div>\n} @else {\n <div wbViewDropZone\n [wbViewDropZoneRegions]=\"canDrop() && {center: false, north: true, south: true, west: true, east: true}\"\n [wbViewDropZoneAttributes]=\"{'data-partid': part.id}\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"slot e2e-slot e2e-part-slot\">\n <ng-container *wbPortalOutlet=\"part.slot.portal; destroyOnDetach: false\"/>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;outline:none;background-color:var(--sci-workbench-part-background-color);overflow:hidden}:host[data-peripheral]{background-color:var(--sci-workbench-part-peripheral-background-color)}:host>wb-part-bar{flex:none}:host>div.slot{flex:auto;display:grid;position:relative}\n"], dependencies: [{ kind: "component", type: PartBarComponent, selector: "wb-part-bar" }, { kind: "directive", type: ViewDropZoneDirective, selector: "[wbViewDropZone]", inputs: ["wbViewDropZoneRegions", "wbViewDropZoneAttributes", "wbViewDropZoneRegionSize", "wbViewDropZonePlaceholderSize"], outputs: ["wbViewDropZoneDrop"] }, { kind: "directive", type: WorkbenchPortalOutletDirective, selector: "ng-template[wbPortalOutlet]", inputs: ["wbPortalOutlet", "wbPortalOutletDestroyOnDetach"] }] });
|
|
13684
13763
|
}
|
|
13685
13764
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PartComponent, decorators: [{
|
|
13686
13765
|
type: Component,
|
|
@@ -13696,7 +13775,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
13696
13775
|
'[attr.data-referencepart]': `part.referencePart() ? '' : null`,
|
|
13697
13776
|
'[attr.tabindex]': '-1',
|
|
13698
13777
|
'[class]': 'part.classList.asList()',
|
|
13699
|
-
}, template: "@if (part.title() || part.views().length || part.actions().length || part.canMinimize()) {\n <wb-part-bar/>\n}\n\n@if (part.views().length) {\n <!-- Prevent splitting if there is no active view, i.e, when dragging the last view out of the tabbar. -->\n @let canSplit = !!part.activeView();\n <div wbViewDropZone\n [wbViewDropZoneRegionSize]=\".25\"\n [wbViewDropZonePlaceholderSize]=\".5\"\n [wbViewDropZoneAttributes]=\"{'data-partid': part.id}\"\n [wbViewDropZoneRegions]=\"canDrop() && {center: true, north: canSplit, south: canSplit, west: canSplit, east: canSplit}\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"
|
|
13778
|
+
}, template: "@if (part.title() || part.views().length || part.actions().length || part.canMinimize()) {\n <wb-part-bar/>\n}\n\n@if (part.views().length) {\n <!-- Prevent splitting if there is no active view, i.e, when dragging the last view out of the tabbar. -->\n @let canSplit = !!part.activeView();\n <div wbViewDropZone\n [wbViewDropZoneRegionSize]=\".25\"\n [wbViewDropZonePlaceholderSize]=\".5\"\n [wbViewDropZoneAttributes]=\"{'data-partid': part.id}\"\n [wbViewDropZoneRegions]=\"canDrop() && {center: true, north: canSplit, south: canSplit, west: canSplit, east: canSplit}\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"slot e2e-slot e2e-view-slot\">\n <ng-container *wbPortalOutlet=\"part.activeView()?.slot!.portal; destroyOnDetach: false\"/>\n </div>\n} @else {\n <div wbViewDropZone\n [wbViewDropZoneRegions]=\"canDrop() && {center: false, north: true, south: true, west: true, east: true}\"\n [wbViewDropZoneAttributes]=\"{'data-partid': part.id}\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"slot e2e-slot e2e-part-slot\">\n <ng-container *wbPortalOutlet=\"part.slot.portal; destroyOnDetach: false\"/>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;outline:none;background-color:var(--sci-workbench-part-background-color);overflow:hidden}:host[data-peripheral]{background-color:var(--sci-workbench-part-peripheral-background-color)}:host>wb-part-bar{flex:none}:host>div.slot{flex:auto;display:grid;position:relative}\n"] }]
|
|
13700
13779
|
}], ctorParameters: () => [] });
|
|
13701
13780
|
|
|
13702
13781
|
/*
|
|
@@ -17770,18 +17849,209 @@ class ɵNotification {
|
|
|
17770
17849
|
setCssClass(cssClass) {
|
|
17771
17850
|
this._notification.cssClass = cssClass;
|
|
17772
17851
|
}
|
|
17773
|
-
/** @inheritDoc */
|
|
17774
|
-
close() {
|
|
17775
|
-
this._notification.close();
|
|
17852
|
+
/** @inheritDoc */
|
|
17853
|
+
close() {
|
|
17854
|
+
this._notification.close();
|
|
17855
|
+
}
|
|
17856
|
+
}
|
|
17857
|
+
/**
|
|
17858
|
+
* TODO [Angular 22] Remove with Angular 22. Used for backward compatiblity.
|
|
17859
|
+
*/
|
|
17860
|
+
const LEGACY_NOTIFICATION_INPUT = `${UID.randomUID()}-auto-generated`;
|
|
17861
|
+
|
|
17862
|
+
/*
|
|
17863
|
+
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
17864
|
+
*
|
|
17865
|
+
* This program and the accompanying materials are made
|
|
17866
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
17867
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
17868
|
+
*
|
|
17869
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
17870
|
+
*/
|
|
17871
|
+
/**
|
|
17872
|
+
* Represents a handle that a notification component can inject to interact with the notification, for example,
|
|
17873
|
+
* to read input data or to configure the notification.
|
|
17874
|
+
*
|
|
17875
|
+
* A notification is a closable message that appears in the upper-right corner and disappears automatically after a few seconds.
|
|
17876
|
+
* It informs the user of a system event, e.g., that a task has been completed or an error has occurred.
|
|
17877
|
+
*
|
|
17878
|
+
* @deprecated since version 21.0.0-beta.1. Replaced by `WorkbenchNotification`. Marked for removal in version 22.
|
|
17879
|
+
*/
|
|
17880
|
+
class Notification {
|
|
17881
|
+
/**
|
|
17882
|
+
* Input data as passed by the notification opener, or `undefined` if not passed.
|
|
17883
|
+
*/
|
|
17884
|
+
input;
|
|
17885
|
+
}
|
|
17886
|
+
|
|
17887
|
+
/*
|
|
17888
|
+
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
17889
|
+
*
|
|
17890
|
+
* This program and the accompanying materials are made
|
|
17891
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
17892
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
17893
|
+
*
|
|
17894
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
17895
|
+
*/
|
|
17896
|
+
/**
|
|
17897
|
+
* TODO [Angular 22] Remove with Angular 22. Used for backward compatiblity.
|
|
17898
|
+
*/
|
|
17899
|
+
class RemoveLegacyInputPipe {
|
|
17900
|
+
transform(inputs) {
|
|
17901
|
+
const inputsCopy = { ...inputs ?? {} };
|
|
17902
|
+
delete inputsCopy[LEGACY_NOTIFICATION_INPUT]; // eslint-disable-line @typescript-eslint/no-dynamic-delete
|
|
17903
|
+
return inputsCopy;
|
|
17904
|
+
}
|
|
17905
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: RemoveLegacyInputPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
17906
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.1", ngImport: i0, type: RemoveLegacyInputPipe, isStandalone: true, name: "wbRemoveLegacyInput" });
|
|
17907
|
+
}
|
|
17908
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: RemoveLegacyInputPipe, decorators: [{
|
|
17909
|
+
type: Pipe,
|
|
17910
|
+
args: [{ name: 'wbRemoveLegacyInput' }]
|
|
17911
|
+
}] });
|
|
17912
|
+
|
|
17913
|
+
/*
|
|
17914
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
17915
|
+
*
|
|
17916
|
+
* This program and the accompanying materials are made
|
|
17917
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
17918
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
17919
|
+
*
|
|
17920
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
17921
|
+
*/
|
|
17922
|
+
/**
|
|
17923
|
+
* Renders the content of a workbench notification.
|
|
17924
|
+
*/
|
|
17925
|
+
class WorkbenchNotificationComponent {
|
|
17926
|
+
notification = inject(ɵWorkbenchNotification);
|
|
17927
|
+
hover = signal(false, { ...(ngDevMode ? { debugName: "hover" } : {}) });
|
|
17928
|
+
slotAnchorName = this.notification.id.replace('.', '_'); // Anchor must not contain a dot.
|
|
17929
|
+
notificationSlotBounds = viewChild('slot_bounds', { ...(ngDevMode ? { debugName: "notificationSlotBounds" } : {}), read: (ElementRef) });
|
|
17930
|
+
constructor() {
|
|
17931
|
+
this.installAutoCloseTimer();
|
|
17932
|
+
this.closeOnEscapeIfOnTop();
|
|
17933
|
+
trackFocus(inject(ElementRef).nativeElement, this.notification);
|
|
17934
|
+
}
|
|
17935
|
+
onClose() {
|
|
17936
|
+
this.notification.close();
|
|
17937
|
+
}
|
|
17938
|
+
onEscape(event) {
|
|
17939
|
+
if (this.notification.focused()) {
|
|
17940
|
+
event.stopPropagation(); // stop propagation to prevent closing the most recently displayed notification
|
|
17941
|
+
this.notification.close();
|
|
17942
|
+
}
|
|
17943
|
+
}
|
|
17944
|
+
onAuxClick(event) {
|
|
17945
|
+
if (event.button === 1) { // primary aux button
|
|
17946
|
+
event.preventDefault(); // prevent user-agent default action
|
|
17947
|
+
this.notification.close();
|
|
17948
|
+
}
|
|
17949
|
+
}
|
|
17950
|
+
onMouseDown(event) {
|
|
17951
|
+
if (event.button === 1) { // primary aux button
|
|
17952
|
+
event.preventDefault(); // prevent middle-click scrolling; necessary for aux click to work
|
|
17953
|
+
}
|
|
17954
|
+
}
|
|
17955
|
+
/**
|
|
17956
|
+
* Closes this notification when pressing escape if it is the most recently displayed notification.
|
|
17957
|
+
*/
|
|
17958
|
+
closeOnEscapeIfOnTop() {
|
|
17959
|
+
const zone = inject(NgZone);
|
|
17960
|
+
const document = inject(DOCUMENT);
|
|
17961
|
+
effect(onCleanup => {
|
|
17962
|
+
if (!this.notification.top()) {
|
|
17963
|
+
return;
|
|
17964
|
+
}
|
|
17965
|
+
const subscription = fromEvent(document, 'keydown')
|
|
17966
|
+
.pipe(subscribeIn(fn => zone.runOutsideAngular(fn)), filter((event) => event.key === 'Escape'), observeIn(fn => zone.run(fn)))
|
|
17967
|
+
.subscribe(() => this.notification.close());
|
|
17968
|
+
onCleanup(() => subscription.unsubscribe());
|
|
17969
|
+
});
|
|
17970
|
+
}
|
|
17971
|
+
/**
|
|
17972
|
+
* Installs a timer to close the notification.
|
|
17973
|
+
*/
|
|
17974
|
+
installAutoCloseTimer() {
|
|
17975
|
+
effect(onCleanup => {
|
|
17976
|
+
const duration = this.notification.duration();
|
|
17977
|
+
const focus = this.notification.focused();
|
|
17978
|
+
const blockedBy = this.notification.blockedBy();
|
|
17979
|
+
const hover = this.hover();
|
|
17980
|
+
if (hover || focus || blockedBy) {
|
|
17981
|
+
return;
|
|
17982
|
+
}
|
|
17983
|
+
untracked(() => {
|
|
17984
|
+
const subscription = fromDuration$(duration).subscribe(() => this.notification.close());
|
|
17985
|
+
onCleanup(() => subscription.unsubscribe());
|
|
17986
|
+
});
|
|
17987
|
+
});
|
|
17988
|
+
function fromDuration$(duration) {
|
|
17989
|
+
switch (duration) {
|
|
17990
|
+
case 'short':
|
|
17991
|
+
return timer(7000);
|
|
17992
|
+
case 'medium':
|
|
17993
|
+
return timer(15000);
|
|
17994
|
+
case 'long':
|
|
17995
|
+
return timer(30000);
|
|
17996
|
+
default:
|
|
17997
|
+
if (typeof duration === 'number') {
|
|
17998
|
+
return timer(duration);
|
|
17999
|
+
}
|
|
18000
|
+
return NEVER;
|
|
18001
|
+
}
|
|
18002
|
+
}
|
|
17776
18003
|
}
|
|
18004
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18005
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: WorkbenchNotificationComponent, isStandalone: true, selector: "wb-notification", host: { listeners: { "mouseenter": "hover.set(true)", "mouseleave": "hover.set(false)", "auxclick": "onAuxClick($event)", "mousedown": "onMouseDown($event)", "keydown.escape": "onEscape($event)" }, properties: { "attr.data-notificationid": "notification.id", "attr.data-severity": "notification.severity()", "style.min-height": "notification.size.minHeight()", "style.height": "notification.size.height()", "style.max-height": "notification.size.maxHeight()", "style.--\u0275slot-anchor": "`--${slotAnchorName}`", "attr.tabindex": "-1", "class": "notification.cssClass()" } }, providers: [
|
|
18006
|
+
configureNotificationGlassPane(),
|
|
18007
|
+
], viewQueries: [{ propertyName: "notificationSlotBounds", first: true, predicate: ["slot_bounds"], descendants: true, read: ElementRef, isSignal: true }], hostDirectives: [{ directive: GlassPaneDirective }], ngImport: i0, template: "<!-- Title -->\n@if (notification.title(); as title) {\n <header class=\"e2e-title\">{{(title | wbText)()}}</header>\n}\n\n<!-- Message -->\n<div class=\"slot e2e-slot\" [class.text]=\"!!notification.slot.text?.length\">\n @if (notification.slot.text?.length) {\n {{(notification.slot.text | wbText)()}}\n } @else if (notification.slot.component) {\n <sci-viewport class=\"e2e-notification-slot\">\n <ng-container *ngComponentOutlet=\"notification.slot.component; inputs: notification.inputs | wbRemoveLegacyInput;\"/>\n </sci-viewport>\n\n <!-- Extra DIV to capture bounds available to slotted content, excluding viewport content padding. May differ from the actual content size if content overflows or does not fill the slot. -->\n <div class=\"slot-bounds e2e-notification-slot-bounds\" #slot_bounds></div>\n }\n</div>\n\n<button (click)=\"onClose()\"\n [title]=\"('%workbench.close.tooltip' | wbText)()\"\n class=\"close e2e-close\">\n <wb-icon icon=\"workbench.close\"/>\n</button>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;gap:.75em;background-color:var(--sci-color-background-elevation);color:var(--sci-color-text);font-size:.9em;border:1px solid var(--sci-color-border);border-radius:var(--sci-corner);box-shadow:var(--sci-elevation) var(--sci-static-color-black);padding:1em 0;overflow:hidden;outline:none;position:relative}:host:before{content:\"\";position:absolute;top:0;left:0;bottom:0;width:var(--sci-workbench-notification-severity-indicator-size)}:host[data-severity=info]:before{background-color:var(--sci-color-accent)}:host[data-severity=warn]:before{background-color:var(--sci-color-notice)}:host[data-severity=error]:before{background-color:var(--sci-color-negative)}:host>header{flex:none;font-weight:700;padding:0 var(--sci-workbench-notification-padding);word-break:break-word;white-space:pre-line}:host>div.slot{flex:auto;overflow:hidden;display:grid}:host>div.slot.text{word-break:break-word;white-space:pre-line;padding:0 var(--sci-workbench-notification-padding)}:host>div.slot>sci-viewport{anchor-name:var(--\\275slot-anchor)}:host>div.slot>sci-viewport::part(content){padding-inline:var(--sci-workbench-notification-padding)}:host>div.slot>div.slot-bounds{position:absolute;position-anchor:var(--\\275slot-anchor);inset:anchor(top) anchor(right) anchor(bottom) anchor(left);margin-inline:var(--sci-workbench-notification-padding);visibility:hidden}:host>button.close:is(button,#sci-reset){all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-corner);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-workbench-button-cursor)}:host>button.close:is(button,#sci-reset):hover:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-hover)}:host>button.close:is(button,#sci-reset):active:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-active)}:host>button.close:is(button,#sci-reset):focus:not(:focus-visible){outline:none}:host>button.close:is(button,#sci-reset):focus-visible{outline:var(--sci-workbench-button-outline-width-focus) solid var(--sci-color-accent)}:host>button.close:is(button,#sci-reset):disabled{color:var(--sci-color-gray-500)}:host>button.close:is(button,#sci-reset){position:absolute;top:.275em;right:.275em;padding:.125em;border-radius:var(--sci-corner-small);font-size:1rem}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "wb-icon", inputs: ["icon"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: SciViewportComponent, selector: "sci-viewport", inputs: ["scrollbarStyle"], outputs: ["scroll"] }, { kind: "pipe", type: TextPipe, name: "wbText" }, { kind: "pipe", type: RemoveLegacyInputPipe, name: "wbRemoveLegacyInput" }] });
|
|
17777
18008
|
}
|
|
18009
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationComponent, decorators: [{
|
|
18010
|
+
type: Component,
|
|
18011
|
+
args: [{ selector: 'wb-notification', imports: [
|
|
18012
|
+
TextPipe,
|
|
18013
|
+
IconComponent,
|
|
18014
|
+
NgComponentOutlet,
|
|
18015
|
+
RemoveLegacyInputPipe,
|
|
18016
|
+
SciViewportComponent,
|
|
18017
|
+
], hostDirectives: [
|
|
18018
|
+
GlassPaneDirective,
|
|
18019
|
+
], providers: [
|
|
18020
|
+
configureNotificationGlassPane(),
|
|
18021
|
+
], host: {
|
|
18022
|
+
'[attr.data-notificationid]': 'notification.id',
|
|
18023
|
+
'[attr.data-severity]': 'notification.severity()',
|
|
18024
|
+
'[style.min-height]': 'notification.size.minHeight()',
|
|
18025
|
+
'[style.height]': 'notification.size.height()',
|
|
18026
|
+
'[style.max-height]': 'notification.size.maxHeight()',
|
|
18027
|
+
'[style.--ɵslot-anchor]': '`--${slotAnchorName}`',
|
|
18028
|
+
'[attr.tabindex]': '-1',
|
|
18029
|
+
'[class]': 'notification.cssClass()',
|
|
18030
|
+
'(mouseenter)': 'hover.set(true)',
|
|
18031
|
+
'(mouseleave)': 'hover.set(false)',
|
|
18032
|
+
'(auxclick)': 'onAuxClick($event)',
|
|
18033
|
+
'(mousedown)': 'onMouseDown($event)',
|
|
18034
|
+
'(keydown.escape)': 'onEscape($event)',
|
|
18035
|
+
}, template: "<!-- Title -->\n@if (notification.title(); as title) {\n <header class=\"e2e-title\">{{(title | wbText)()}}</header>\n}\n\n<!-- Message -->\n<div class=\"slot e2e-slot\" [class.text]=\"!!notification.slot.text?.length\">\n @if (notification.slot.text?.length) {\n {{(notification.slot.text | wbText)()}}\n } @else if (notification.slot.component) {\n <sci-viewport class=\"e2e-notification-slot\">\n <ng-container *ngComponentOutlet=\"notification.slot.component; inputs: notification.inputs | wbRemoveLegacyInput;\"/>\n </sci-viewport>\n\n <!-- Extra DIV to capture bounds available to slotted content, excluding viewport content padding. May differ from the actual content size if content overflows or does not fill the slot. -->\n <div class=\"slot-bounds e2e-notification-slot-bounds\" #slot_bounds></div>\n }\n</div>\n\n<button (click)=\"onClose()\"\n [title]=\"('%workbench.close.tooltip' | wbText)()\"\n class=\"close e2e-close\">\n <wb-icon icon=\"workbench.close\"/>\n</button>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;gap:.75em;background-color:var(--sci-color-background-elevation);color:var(--sci-color-text);font-size:.9em;border:1px solid var(--sci-color-border);border-radius:var(--sci-corner);box-shadow:var(--sci-elevation) var(--sci-static-color-black);padding:1em 0;overflow:hidden;outline:none;position:relative}:host:before{content:\"\";position:absolute;top:0;left:0;bottom:0;width:var(--sci-workbench-notification-severity-indicator-size)}:host[data-severity=info]:before{background-color:var(--sci-color-accent)}:host[data-severity=warn]:before{background-color:var(--sci-color-notice)}:host[data-severity=error]:before{background-color:var(--sci-color-negative)}:host>header{flex:none;font-weight:700;padding:0 var(--sci-workbench-notification-padding);word-break:break-word;white-space:pre-line}:host>div.slot{flex:auto;overflow:hidden;display:grid}:host>div.slot.text{word-break:break-word;white-space:pre-line;padding:0 var(--sci-workbench-notification-padding)}:host>div.slot>sci-viewport{anchor-name:var(--\\275slot-anchor)}:host>div.slot>sci-viewport::part(content){padding-inline:var(--sci-workbench-notification-padding)}:host>div.slot>div.slot-bounds{position:absolute;position-anchor:var(--\\275slot-anchor);inset:anchor(top) anchor(right) anchor(bottom) anchor(left);margin-inline:var(--sci-workbench-notification-padding);visibility:hidden}:host>button.close:is(button,#sci-reset){all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-corner);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-workbench-button-cursor)}:host>button.close:is(button,#sci-reset):hover:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-hover)}:host>button.close:is(button,#sci-reset):active:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-active)}:host>button.close:is(button,#sci-reset):focus:not(:focus-visible){outline:none}:host>button.close:is(button,#sci-reset):focus-visible{outline:var(--sci-workbench-button-outline-width-focus) solid var(--sci-color-accent)}:host>button.close:is(button,#sci-reset):disabled{color:var(--sci-color-gray-500)}:host>button.close:is(button,#sci-reset){position:absolute;top:.275em;right:.275em;padding:.125em;border-radius:var(--sci-corner-small);font-size:1rem}\n"] }]
|
|
18036
|
+
}], ctorParameters: () => [], propDecorators: { notificationSlotBounds: [{ type: i0.ViewChild, args: ['slot_bounds', { ...{ read: (ElementRef) }, isSignal: true }] }] } });
|
|
17778
18037
|
/**
|
|
17779
|
-
*
|
|
18038
|
+
* Blocks this notification when dialog(s) overlay it.
|
|
17780
18039
|
*/
|
|
17781
|
-
|
|
18040
|
+
function configureNotificationGlassPane() {
|
|
18041
|
+
return [
|
|
18042
|
+
{
|
|
18043
|
+
provide: GLASS_PANE_BLOCKABLE,
|
|
18044
|
+
useFactory: () => inject(ɵWorkbenchNotification),
|
|
18045
|
+
},
|
|
18046
|
+
{
|
|
18047
|
+
provide: GLASS_PANE_OPTIONS,
|
|
18048
|
+
useFactory: () => ({ attributes: { 'data-notificationid': inject(ɵWorkbenchNotification).id } }),
|
|
18049
|
+
},
|
|
18050
|
+
];
|
|
18051
|
+
}
|
|
17782
18052
|
|
|
17783
18053
|
/*
|
|
17784
|
-
* Copyright (c) 2018-
|
|
18054
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
17785
18055
|
*
|
|
17786
18056
|
* This program and the accompanying materials are made
|
|
17787
18057
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -17790,52 +18060,23 @@ const LEGACY_NOTIFICATION_INPUT = `${UID.randomUID()}-auto-generated`;
|
|
|
17790
18060
|
* SPDX-License-Identifier: EPL-2.0
|
|
17791
18061
|
*/
|
|
17792
18062
|
/**
|
|
17793
|
-
*
|
|
17794
|
-
* to read input data or to configure the notification.
|
|
17795
|
-
*
|
|
17796
|
-
* A notification is a closable message that appears in the upper-right corner and disappears automatically after a few seconds.
|
|
17797
|
-
* It informs the user of a system event, e.g., that a task has been completed or an error has occurred.
|
|
17798
|
-
*
|
|
17799
|
-
* @deprecated since version 21.0.0-beta.1. Replaced by `WorkbenchNotification`. Marked for removal in version 22.
|
|
17800
|
-
*/
|
|
17801
|
-
class Notification {
|
|
17802
|
-
/**
|
|
17803
|
-
* Input data as passed by the notification opener, or `undefined` if not passed.
|
|
17804
|
-
*/
|
|
17805
|
-
input;
|
|
17806
|
-
}
|
|
17807
|
-
|
|
17808
|
-
/*
|
|
17809
|
-
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
17810
|
-
*
|
|
17811
|
-
* This program and the accompanying materials are made
|
|
17812
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
17813
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
17814
|
-
*
|
|
17815
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
18063
|
+
* DI token to register providers available for DI if in the context of a workbench notification.
|
|
17816
18064
|
*/
|
|
18065
|
+
const WORKBENCH_NOTIFICATION_CONTEXT = new InjectionToken('WORKBENCH_NOTIFICATION_CONTEXT');
|
|
17817
18066
|
/**
|
|
17818
|
-
*
|
|
18067
|
+
* Provides providers available for DI if in the context of a workbench notification.
|
|
17819
18068
|
*/
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
this.top = computed(() => this.elements().at(-1), { ...(ngDevMode ? { debugName: "top" } : {}) });
|
|
17831
|
-
}
|
|
17832
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
17833
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationRegistry, providedIn: 'root' });
|
|
18069
|
+
function provideWorkbenchNotificationContext() {
|
|
18070
|
+
return {
|
|
18071
|
+
provide: WORKBENCH_NOTIFICATION_CONTEXT,
|
|
18072
|
+
useFactory: () => [
|
|
18073
|
+
provideWorkbenchDialogService(),
|
|
18074
|
+
provideWorkbenchMessageBoxService(),
|
|
18075
|
+
provideWorkbenchPopupService(),
|
|
18076
|
+
],
|
|
18077
|
+
multi: true,
|
|
18078
|
+
};
|
|
17834
18079
|
}
|
|
17835
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationRegistry, decorators: [{
|
|
17836
|
-
type: Injectable,
|
|
17837
|
-
args: [{ providedIn: 'root' }]
|
|
17838
|
-
}], ctorParameters: () => [] });
|
|
17839
18080
|
|
|
17840
18081
|
/** @inheritDoc */
|
|
17841
18082
|
class ɵWorkbenchNotification {
|
|
@@ -17850,17 +18091,20 @@ class ɵWorkbenchNotification {
|
|
|
17850
18091
|
_severity;
|
|
17851
18092
|
_duration;
|
|
17852
18093
|
_cssClass;
|
|
18094
|
+
portal;
|
|
17853
18095
|
size = new ɵWorkbenchNotificationSize();
|
|
17854
18096
|
focused = computed(() => this._focusMonitor.activeElement()?.id === this.id, { ...(ngDevMode ? { debugName: "focused" } : {}) });
|
|
17855
18097
|
/** Checks if this notification is the most recently displayed notification. */
|
|
17856
18098
|
top = computed(() => this._notificationRegistry.top() === this, { ...(ngDevMode ? { debugName: "top" } : {}) });
|
|
17857
18099
|
destroyed = signal(false, { ...(ngDevMode ? { debugName: "destroyed" } : {}) });
|
|
18100
|
+
bounds;
|
|
18101
|
+
blockedBy;
|
|
17858
18102
|
group;
|
|
17859
18103
|
constructor(id, content, _options) {
|
|
17860
18104
|
this.id = id;
|
|
17861
18105
|
this._options = _options;
|
|
18106
|
+
this.portal = this.createPortal();
|
|
17862
18107
|
this.slot = {
|
|
17863
|
-
injector: this.createInjector(),
|
|
17864
18108
|
component: typeof content === 'function' ? content : undefined,
|
|
17865
18109
|
text: typeof content === 'string' ? content : undefined,
|
|
17866
18110
|
};
|
|
@@ -17869,24 +18113,25 @@ class ɵWorkbenchNotification {
|
|
|
17869
18113
|
this._duration = signal(this._options.duration ?? 'medium', { ...(ngDevMode ? { debugName: "_duration" } : {}) });
|
|
17870
18114
|
this._cssClass = signal(Arrays.coerce(this._options.cssClass), { ...(ngDevMode ? { debugName: "_cssClass" } : {}) });
|
|
17871
18115
|
this.group = this._options.group;
|
|
18116
|
+
this.blockedBy = inject(WorkbenchDialogRegistry).top(this.id);
|
|
18117
|
+
this.bounds = boundingClientRect(computed(() => this.portal.componentRef()?.instance.notificationSlotBounds()));
|
|
17872
18118
|
inject(DestroyRef).onDestroy(() => this.destroyed.set(true));
|
|
17873
18119
|
}
|
|
17874
18120
|
/**
|
|
17875
|
-
* Creates
|
|
18121
|
+
* Creates a portal to render {@link WorkbenchNotificationComponent} in the notification's injection context.
|
|
17876
18122
|
*/
|
|
17877
|
-
|
|
17878
|
-
|
|
17879
|
-
|
|
18123
|
+
createPortal() {
|
|
18124
|
+
return new WbComponentPortal(WorkbenchNotificationComponent, {
|
|
18125
|
+
injector: this._options.injector,
|
|
17880
18126
|
providers: [
|
|
17881
18127
|
{ provide: ɵWorkbenchNotification, useValue: this },
|
|
17882
18128
|
{ provide: WorkbenchNotification, useExisting: ɵWorkbenchNotification },
|
|
17883
18129
|
{ provide: Notification, useClass: ɵNotification },
|
|
17884
18130
|
{ provide: WORKBENCH_ELEMENT, useExisting: ɵWorkbenchNotification },
|
|
18131
|
+
inject(WORKBENCH_NOTIFICATION_CONTEXT, { optional: true }) ?? [],
|
|
17885
18132
|
...this._options.providers ?? [],
|
|
17886
18133
|
],
|
|
17887
18134
|
});
|
|
17888
|
-
inject(DestroyRef).onDestroy(() => injector.destroy());
|
|
17889
|
-
return injector;
|
|
17890
18135
|
}
|
|
17891
18136
|
/** @inheritDoc */
|
|
17892
18137
|
get title() {
|
|
@@ -17922,6 +18167,9 @@ class ɵWorkbenchNotification {
|
|
|
17922
18167
|
}
|
|
17923
18168
|
/** @inheritDoc */
|
|
17924
18169
|
close() {
|
|
18170
|
+
if (this.blockedBy()) {
|
|
18171
|
+
return;
|
|
18172
|
+
}
|
|
17925
18173
|
this.destroy();
|
|
17926
18174
|
}
|
|
17927
18175
|
/**
|
|
@@ -18434,6 +18682,7 @@ function provideMicrofrontendNotification() {
|
|
|
18434
18682
|
MicrofrontendNotificationCapabilityValidator,
|
|
18435
18683
|
MicrofrontendTextNotificationCapabilityProvider,
|
|
18436
18684
|
MicrofrontendNotificationIntentHandler,
|
|
18685
|
+
provideWorkbenchNotificationContext(),
|
|
18437
18686
|
provideMicrofrontendTextNotificationRoute(),
|
|
18438
18687
|
provideMicrofrontendPlatformInitializer(onPreStartup, { phase: MicrofrontendPlatformStartupPhase.PreStartup }),
|
|
18439
18688
|
]);
|
|
@@ -18445,6 +18694,20 @@ function provideMicrofrontendNotification() {
|
|
|
18445
18694
|
// Register notification intent handler.
|
|
18446
18695
|
Beans.register(IntentInterceptor, { useValue: inject(MicrofrontendNotificationIntentHandler), multi: true });
|
|
18447
18696
|
}
|
|
18697
|
+
/**
|
|
18698
|
+
* Provides beans of @scion/workbench-client available for DI if in the context of a workbench notification.
|
|
18699
|
+
*/
|
|
18700
|
+
function provideWorkbenchNotificationContext() {
|
|
18701
|
+
return {
|
|
18702
|
+
provide: WORKBENCH_NOTIFICATION_CONTEXT,
|
|
18703
|
+
useFactory: () => [
|
|
18704
|
+
{ provide: WorkbenchDialogService$1, useFactory: () => new _WorkbenchDialogService(inject(WorkbenchNotification).id) },
|
|
18705
|
+
{ provide: WorkbenchMessageBoxService$1, useFactory: () => new _WorkbenchMessageBoxService(inject(WorkbenchNotification).id) },
|
|
18706
|
+
{ provide: WorkbenchPopupService$1, useFactory: () => new _WorkbenchPopupService(inject(WorkbenchNotification).id) },
|
|
18707
|
+
],
|
|
18708
|
+
multi: true,
|
|
18709
|
+
};
|
|
18710
|
+
}
|
|
18448
18711
|
}
|
|
18449
18712
|
|
|
18450
18713
|
/*
|
|
@@ -20291,6 +20554,7 @@ function provideWorkbench(config) {
|
|
|
20291
20554
|
provideWorkbenchViewContext(),
|
|
20292
20555
|
provideWorkbenchDialogContext(),
|
|
20293
20556
|
provideWorkbenchPopupContext(),
|
|
20557
|
+
provideWorkbenchNotificationContext(),
|
|
20294
20558
|
provideWorkbenchMicrofrontendSupport(config),
|
|
20295
20559
|
]);
|
|
20296
20560
|
}
|
|
@@ -20384,32 +20648,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
20384
20648
|
args: [{ selector: 'wb-splash', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SciThrobberComponent], template: "<sci-throbber type=\"ellipsis\"/>\n", styles: [":host{display:grid;justify-content:center;margin-top:3em}:host>sci-throbber{--sci-throbber-size: 80px}\n"] }]
|
|
20385
20649
|
}] });
|
|
20386
20650
|
|
|
20387
|
-
/*
|
|
20388
|
-
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
20389
|
-
*
|
|
20390
|
-
* This program and the accompanying materials are made
|
|
20391
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
20392
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
20393
|
-
*
|
|
20394
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
20395
|
-
*/
|
|
20396
|
-
/**
|
|
20397
|
-
* TODO [Angular 22] Remove with Angular 22. Used for backward compatiblity.
|
|
20398
|
-
*/
|
|
20399
|
-
class RemoveLegacyInputPipe {
|
|
20400
|
-
transform(inputs) {
|
|
20401
|
-
const inputsCopy = { ...inputs ?? {} };
|
|
20402
|
-
delete inputsCopy[LEGACY_NOTIFICATION_INPUT]; // eslint-disable-line @typescript-eslint/no-dynamic-delete
|
|
20403
|
-
return inputsCopy;
|
|
20404
|
-
}
|
|
20405
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: RemoveLegacyInputPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
20406
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.1", ngImport: i0, type: RemoveLegacyInputPipe, isStandalone: true, name: "wbRemoveLegacyInput" });
|
|
20407
|
-
}
|
|
20408
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: RemoveLegacyInputPipe, decorators: [{
|
|
20409
|
-
type: Pipe,
|
|
20410
|
-
args: [{ name: 'wbRemoveLegacyInput' }]
|
|
20411
|
-
}] });
|
|
20412
|
-
|
|
20413
20651
|
/*
|
|
20414
20652
|
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
20415
20653
|
*
|
|
@@ -20419,140 +20657,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
20419
20657
|
*
|
|
20420
20658
|
* SPDX-License-Identifier: EPL-2.0
|
|
20421
20659
|
*/
|
|
20422
|
-
/**
|
|
20423
|
-
* Renders the content of a workbench notification.
|
|
20424
|
-
*/
|
|
20425
|
-
class WorkbenchNotificationComponent {
|
|
20426
|
-
notification = input.required({ ...(ngDevMode ? { debugName: "notification" } : {}) });
|
|
20427
|
-
hover = signal(false, { ...(ngDevMode ? { debugName: "hover" } : {}) });
|
|
20428
|
-
constructor() {
|
|
20429
|
-
this.installAutoCloseTimer();
|
|
20430
|
-
this.installFocusTracker();
|
|
20431
|
-
this.closeOnEscapeIfOnTop();
|
|
20432
|
-
}
|
|
20433
|
-
onClose() {
|
|
20434
|
-
this.notification().close();
|
|
20435
|
-
}
|
|
20436
|
-
onEscape(event) {
|
|
20437
|
-
if (this.notification().focused()) {
|
|
20438
|
-
event.stopPropagation(); // stop propagation to prevent closing the most recently displayed notification
|
|
20439
|
-
this.notification().close();
|
|
20440
|
-
}
|
|
20441
|
-
}
|
|
20442
|
-
onAuxClick(event) {
|
|
20443
|
-
if (event.button === 1) { // primary aux button
|
|
20444
|
-
event.preventDefault(); // prevent user-agent default action
|
|
20445
|
-
this.notification().close();
|
|
20446
|
-
}
|
|
20447
|
-
}
|
|
20448
|
-
/**
|
|
20449
|
-
* Closes this notification when pressing escape if it is the most recently displayed notification.
|
|
20450
|
-
*/
|
|
20451
|
-
closeOnEscapeIfOnTop() {
|
|
20452
|
-
const zone = inject(NgZone);
|
|
20453
|
-
const document = inject(DOCUMENT);
|
|
20454
|
-
effect(onCleanup => {
|
|
20455
|
-
if (!this.notification().top()) {
|
|
20456
|
-
return;
|
|
20457
|
-
}
|
|
20458
|
-
const subscription = fromEvent(document, 'keydown')
|
|
20459
|
-
.pipe(subscribeIn(fn => zone.runOutsideAngular(fn)), filter((event) => event.key === 'Escape'), observeIn(fn => zone.run(fn)))
|
|
20460
|
-
.subscribe(() => this.notification().close());
|
|
20461
|
-
onCleanup(() => subscription.unsubscribe());
|
|
20462
|
-
});
|
|
20463
|
-
}
|
|
20464
|
-
/**
|
|
20465
|
-
* Installs a timer to close the notification.
|
|
20466
|
-
*/
|
|
20467
|
-
installAutoCloseTimer() {
|
|
20468
|
-
effect(onCleanup => {
|
|
20469
|
-
const notification = this.notification();
|
|
20470
|
-
const duration = notification.duration();
|
|
20471
|
-
const focus = notification.focused();
|
|
20472
|
-
const hover = this.hover();
|
|
20473
|
-
if (hover || focus) {
|
|
20474
|
-
return;
|
|
20475
|
-
}
|
|
20476
|
-
untracked(() => {
|
|
20477
|
-
const subscription = fromDuration$(duration).subscribe(() => this.notification().close());
|
|
20478
|
-
onCleanup(() => subscription.unsubscribe());
|
|
20479
|
-
});
|
|
20480
|
-
});
|
|
20481
|
-
function fromDuration$(duration) {
|
|
20482
|
-
switch (duration) {
|
|
20483
|
-
case 'short':
|
|
20484
|
-
return timer(7000);
|
|
20485
|
-
case 'medium':
|
|
20486
|
-
return timer(15000);
|
|
20487
|
-
case 'long':
|
|
20488
|
-
return timer(30000);
|
|
20489
|
-
default:
|
|
20490
|
-
if (typeof duration === 'number') {
|
|
20491
|
-
return timer(duration);
|
|
20492
|
-
}
|
|
20493
|
-
return NEVER;
|
|
20494
|
-
}
|
|
20495
|
-
}
|
|
20496
|
-
}
|
|
20497
|
-
installFocusTracker() {
|
|
20498
|
-
const host = inject(ElementRef).nativeElement;
|
|
20499
|
-
const injector = inject(Injector);
|
|
20500
|
-
effect(onCleanup => {
|
|
20501
|
-
const notification = this.notification();
|
|
20502
|
-
untracked(() => {
|
|
20503
|
-
const tracker = runInInjectionContext(injector, () => trackFocus(host, notification));
|
|
20504
|
-
onCleanup(() => tracker.destroy());
|
|
20505
|
-
});
|
|
20506
|
-
});
|
|
20507
|
-
}
|
|
20508
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20509
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: WorkbenchNotificationComponent, isStandalone: true, selector: "wb-notification", inputs: { notification: { classPropertyName: "notification", publicName: "notification", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "mouseenter": "hover.set(true)", "mouseleave": "hover.set(false)", "auxclick": "onAuxClick($event)", "keydown.escape": "onEscape($event)" }, properties: { "attr.data-notificationid": "notification().id", "attr.data-severity": "notification().severity()", "style.min-height": "notification().size.minHeight()", "style.height": "notification().size.height()", "style.max-height": "notification().size.maxHeight()", "attr.tabindex": "-1", "class": "notification().cssClass()" } }, ngImport: i0, template: "<!-- Title -->\n@if (notification().title(); as title) {\n <header class=\"e2e-title\">{{(title | wbText)()}}</header>\n}\n\n<!-- Message -->\n<div class=\"message e2e-message\" [class.text]=\"!!notification().slot.text?.length\">\n @if (notification().slot.text?.length) {\n {{(notification().slot.text | wbText)()}}\n } @else if (notification().slot.component) {\n <sci-viewport class=\"e2e-message-viewport\">\n <ng-container *ngComponentOutlet=\"notification().slot.component!; inputs: notification().inputs | wbRemoveLegacyInput; injector: notification().slot.injector\"/>\n </sci-viewport>\n }\n</div>\n\n<button (click)=\"onClose()\"\n [title]=\"('%workbench.close.tooltip' | wbText)()\"\n class=\"close e2e-close\">\n <wb-icon icon=\"workbench.close\"/>\n</button>\n", styles: [":host{display:flex;flex-direction:column;gap:.75em;background-color:var(--sci-color-background-elevation);color:var(--sci-color-text);font-size:.9em;border:1px solid var(--sci-color-border);border-radius:var(--sci-corner);box-shadow:var(--sci-elevation) var(--sci-static-color-black);padding:1em 0;overflow:hidden;outline:none;position:relative}:host:before{content:\"\";position:absolute;top:0;left:0;bottom:0;width:var(--sci-workbench-notification-severity-indicator-size)}:host[data-severity=info]:before{background-color:var(--sci-color-accent)}:host[data-severity=warn]:before{background-color:var(--sci-color-notice)}:host[data-severity=error]:before{background-color:var(--sci-color-negative)}:host>header{flex:none;font-weight:700;padding:0 1.5em;word-break:break-word;white-space:pre-line}:host>div.message{flex:auto;overflow:hidden}:host>div.message.text{word-break:break-word;white-space:pre-line;padding:0 1.5em}:host>div.message>sci-viewport{height:100%}:host>div.message>sci-viewport::part(content){padding:0 1.5em}:host>button.close:is(button,#sci-reset){all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-corner);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-workbench-button-cursor)}:host>button.close:is(button,#sci-reset):hover:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-hover)}:host>button.close:is(button,#sci-reset):active:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-active)}:host>button.close:is(button,#sci-reset):focus:not(:focus-visible){outline:none}:host>button.close:is(button,#sci-reset):focus-visible{outline:var(--sci-workbench-button-outline-width-focus) solid var(--sci-color-accent)}:host>button.close:is(button,#sci-reset):disabled{color:var(--sci-color-gray-500)}:host>button.close:is(button,#sci-reset){position:absolute;top:.275em;right:.275em;padding:.125em;border-radius:var(--sci-corner-small);font-size:1rem}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "wb-icon", inputs: ["icon"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: SciViewportComponent, selector: "sci-viewport", inputs: ["scrollbarStyle"], outputs: ["scroll"] }, { kind: "pipe", type: TextPipe, name: "wbText" }, { kind: "pipe", type: RemoveLegacyInputPipe, name: "wbRemoveLegacyInput" }] });
|
|
20510
|
-
}
|
|
20511
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationComponent, decorators: [{
|
|
20512
|
-
type: Component,
|
|
20513
|
-
args: [{ selector: 'wb-notification', imports: [
|
|
20514
|
-
TextPipe,
|
|
20515
|
-
IconComponent,
|
|
20516
|
-
NgComponentOutlet,
|
|
20517
|
-
RemoveLegacyInputPipe,
|
|
20518
|
-
SciViewportComponent,
|
|
20519
|
-
], host: {
|
|
20520
|
-
'[attr.data-notificationid]': 'notification().id',
|
|
20521
|
-
'[attr.data-severity]': 'notification().severity()',
|
|
20522
|
-
'[style.min-height]': 'notification().size.minHeight()',
|
|
20523
|
-
'[style.height]': 'notification().size.height()',
|
|
20524
|
-
'[style.max-height]': 'notification().size.maxHeight()',
|
|
20525
|
-
'[attr.tabindex]': '-1',
|
|
20526
|
-
'[class]': 'notification().cssClass()',
|
|
20527
|
-
'(mouseenter)': 'hover.set(true)',
|
|
20528
|
-
'(mouseleave)': 'hover.set(false)',
|
|
20529
|
-
'(auxclick)': 'onAuxClick($event)',
|
|
20530
|
-
'(keydown.escape)': 'onEscape($event)',
|
|
20531
|
-
}, template: "<!-- Title -->\n@if (notification().title(); as title) {\n <header class=\"e2e-title\">{{(title | wbText)()}}</header>\n}\n\n<!-- Message -->\n<div class=\"message e2e-message\" [class.text]=\"!!notification().slot.text?.length\">\n @if (notification().slot.text?.length) {\n {{(notification().slot.text | wbText)()}}\n } @else if (notification().slot.component) {\n <sci-viewport class=\"e2e-message-viewport\">\n <ng-container *ngComponentOutlet=\"notification().slot.component!; inputs: notification().inputs | wbRemoveLegacyInput; injector: notification().slot.injector\"/>\n </sci-viewport>\n }\n</div>\n\n<button (click)=\"onClose()\"\n [title]=\"('%workbench.close.tooltip' | wbText)()\"\n class=\"close e2e-close\">\n <wb-icon icon=\"workbench.close\"/>\n</button>\n", styles: [":host{display:flex;flex-direction:column;gap:.75em;background-color:var(--sci-color-background-elevation);color:var(--sci-color-text);font-size:.9em;border:1px solid var(--sci-color-border);border-radius:var(--sci-corner);box-shadow:var(--sci-elevation) var(--sci-static-color-black);padding:1em 0;overflow:hidden;outline:none;position:relative}:host:before{content:\"\";position:absolute;top:0;left:0;bottom:0;width:var(--sci-workbench-notification-severity-indicator-size)}:host[data-severity=info]:before{background-color:var(--sci-color-accent)}:host[data-severity=warn]:before{background-color:var(--sci-color-notice)}:host[data-severity=error]:before{background-color:var(--sci-color-negative)}:host>header{flex:none;font-weight:700;padding:0 1.5em;word-break:break-word;white-space:pre-line}:host>div.message{flex:auto;overflow:hidden}:host>div.message.text{word-break:break-word;white-space:pre-line;padding:0 1.5em}:host>div.message>sci-viewport{height:100%}:host>div.message>sci-viewport::part(content){padding:0 1.5em}:host>button.close:is(button,#sci-reset){all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-corner);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-workbench-button-cursor)}:host>button.close:is(button,#sci-reset):hover:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-hover)}:host>button.close:is(button,#sci-reset):active:where(:not(:disabled)){background-color:var(--sci-workbench-button-background-color-active)}:host>button.close:is(button,#sci-reset):focus:not(:focus-visible){outline:none}:host>button.close:is(button,#sci-reset):focus-visible{outline:var(--sci-workbench-button-outline-width-focus) solid var(--sci-color-accent)}:host>button.close:is(button,#sci-reset):disabled{color:var(--sci-color-gray-500)}:host>button.close:is(button,#sci-reset){position:absolute;top:.275em;right:.275em;padding:.125em;border-radius:var(--sci-corner-small);font-size:1rem}\n"] }]
|
|
20532
|
-
}], ctorParameters: () => [], propDecorators: { notification: [{ type: i0.Input, args: [{ isSignal: true, alias: "notification", required: true }] }] } });
|
|
20533
|
-
|
|
20534
|
-
/*
|
|
20535
|
-
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
20536
|
-
*
|
|
20537
|
-
* This program and the accompanying materials are made
|
|
20538
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
20539
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
20540
|
-
*
|
|
20541
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
20542
|
-
*/
|
|
20543
20660
|
/**
|
|
20544
20661
|
* Displays notifications on the right side, stacked vertically.
|
|
20545
20662
|
*/
|
|
20546
20663
|
class NotificationListComponent {
|
|
20547
20664
|
notifications = inject(WorkbenchNotificationRegistry).elements;
|
|
20548
20665
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: NotificationListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20549
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: NotificationListComponent, isStandalone: true, selector: "wb-notification-list", ngImport: i0, template: "@for (notification of notifications(); track notification.group || notification.id) {\n <
|
|
20666
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: NotificationListComponent, isStandalone: true, selector: "wb-notification-list", ngImport: i0, template: "@for (notification of notifications(); track notification.group || notification.id) {\n <div class=\"notification\">\n <ng-container *wbPortalOutlet=\"notification.portal; destroyOnDetach: true\"/>\n </div>\n}\n", styles: [":host{display:flex;flex-flow:column wrap-reverse;gap:.5em;max-height:100%;align-items:flex-start;align-content:flex-start;pointer-events:none;margin:.5em}:host>div.notification{pointer-events:auto;width:var(--sci-workbench-notification-width);max-width:100%;position:relative;animation:slide-in .3s ease-out}@keyframes slide-in{0%{opacity:0;left:100%}to{opacity:1;left:0}}\n"], dependencies: [{ kind: "directive", type: WorkbenchPortalOutletDirective, selector: "ng-template[wbPortalOutlet]", inputs: ["wbPortalOutlet", "wbPortalOutletDestroyOnDetach"] }] });
|
|
20550
20667
|
}
|
|
20551
20668
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: NotificationListComponent, decorators: [{
|
|
20552
20669
|
type: Component,
|
|
20553
20670
|
args: [{ selector: 'wb-notification-list', imports: [
|
|
20554
|
-
|
|
20555
|
-
], template: "@for (notification of notifications(); track notification.group || notification.id) {\n <
|
|
20671
|
+
WorkbenchPortalOutletDirective,
|
|
20672
|
+
], template: "@for (notification of notifications(); track notification.group || notification.id) {\n <div class=\"notification\">\n <ng-container *wbPortalOutlet=\"notification.portal; destroyOnDetach: true\"/>\n </div>\n}\n", styles: [":host{display:flex;flex-flow:column wrap-reverse;gap:.5em;max-height:100%;align-items:flex-start;align-content:flex-start;pointer-events:none;margin:.5em}:host>div.notification{pointer-events:auto;width:var(--sci-workbench-notification-width);max-width:100%;position:relative;animation:slide-in .3s ease-out}@keyframes slide-in{0%{opacity:0;left:100%}to{opacity:1;left:0}}\n"] }]
|
|
20556
20673
|
}] });
|
|
20557
20674
|
|
|
20558
20675
|
/*
|
|
@@ -20963,7 +21080,7 @@ function configureWorkbenchGlassPane() {
|
|
|
20963
21080
|
},
|
|
20964
21081
|
{
|
|
20965
21082
|
provide: GLASS_PANE_OPTIONS,
|
|
20966
|
-
|
|
21083
|
+
useFactory: () => ({ cssClass: 'e2e-workbench' }),
|
|
20967
21084
|
},
|
|
20968
21085
|
];
|
|
20969
21086
|
}
|
|
@@ -21572,7 +21689,7 @@ function migrateGroupInputReduceFn(config) {
|
|
|
21572
21689
|
*/
|
|
21573
21690
|
|
|
21574
21691
|
/*
|
|
21575
|
-
* Copyright (c) 2018-
|
|
21692
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
21576
21693
|
*
|
|
21577
21694
|
* This program and the accompanying materials are made
|
|
21578
21695
|
* available under the terms of the Eclipse Public License 2.0
|