@scion/workbench 21.0.0-beta.5 → 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.
- package/fesm2022/scion-workbench.mjs +927 -885
- package/fesm2022/scion-workbench.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -9917,7 +9917,7 @@ function configureDialogGlassPane() {
|
|
|
9917
9917
|
}
|
|
9918
9918
|
|
|
9919
9919
|
/*
|
|
9920
|
-
* Copyright (c) 2018-
|
|
9920
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
9921
9921
|
*
|
|
9922
9922
|
* This program and the accompanying materials are made
|
|
9923
9923
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -9926,96 +9926,17 @@ function configureDialogGlassPane() {
|
|
|
9926
9926
|
* SPDX-License-Identifier: EPL-2.0
|
|
9927
9927
|
*/
|
|
9928
9928
|
/**
|
|
9929
|
-
*
|
|
9930
|
-
*
|
|
9931
|
-
* A dialog is a visual element for focused interaction with the user, such as prompting the user for input or confirming actions.
|
|
9932
|
-
* The user can move and resize a dialog.
|
|
9933
|
-
*
|
|
9934
|
-
* Displayed on top of other content, a modal dialog blocks interaction with other parts of the application.
|
|
9935
|
-
*
|
|
9936
|
-
* ## Modality
|
|
9937
|
-
* A dialog can be context-modal or application-modal. Context-modal blocks a specific part of the application, as specified by the context;
|
|
9938
|
-
* application-modal blocks the workbench or browser viewport, based on {@link WorkbenchConfig.dialog.modalityScope}.
|
|
9939
|
-
*
|
|
9940
|
-
* ## Context
|
|
9941
|
-
* A dialog can be bound to a context (e.g., part or view), defaulting to the calling context.
|
|
9942
|
-
* The dialog is displayed only if the context is visible and closes when the context is disposed.
|
|
9943
|
-
*
|
|
9944
|
-
* ## Positioning
|
|
9945
|
-
* A dialog is opened in the center of its context, if any, unless opened from the peripheral area.
|
|
9946
|
-
*
|
|
9947
|
-
* ## Stacking
|
|
9948
|
-
* Dialogs are stacked per modality, with only the topmost dialog in each stack being interactive.
|
|
9949
|
-
*
|
|
9950
|
-
* ## Dialog Component
|
|
9951
|
-
* The dialog component can inject the {@link WorkbenchDialog} handle to interact with the dialog, such as setting the title or closing the dialog.
|
|
9952
|
-
* Inputs passed to the dialog are available as input properties in the dialog component.
|
|
9953
|
-
*
|
|
9954
|
-
* ## Dialog Header
|
|
9955
|
-
* By default, the dialog displays the title and a close button in the header. Alternatively, the dialog supports the use of a custom header.
|
|
9956
|
-
* To provide a custom header, add an Angular template to the HTML of the dialog component and decorate it with the `wbDialogHeader` directive.
|
|
9957
|
-
*
|
|
9958
|
-
* ```html
|
|
9959
|
-
* <ng-template wbDialogHeader>
|
|
9960
|
-
* <app-dialog-header/>
|
|
9961
|
-
* </ng-template>
|
|
9962
|
-
* ```
|
|
9963
|
-
*
|
|
9964
|
-
* ## Dialog Footer
|
|
9965
|
-
* 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
|
|
9966
|
-
* the `wbDialogAction` directive. Multiple actions are supported, rendered in modeling order, and can be left- or right-aligned.
|
|
9967
|
-
*
|
|
9968
|
-
* ```html
|
|
9969
|
-
* <!-- Checkbox -->
|
|
9970
|
-
* <ng-template wbDialogAction align="start">
|
|
9971
|
-
* <label>
|
|
9972
|
-
* <input type="checkbox"/>
|
|
9973
|
-
* Do not ask me again
|
|
9974
|
-
* </label>
|
|
9975
|
-
* </ng-template>
|
|
9976
|
-
*
|
|
9977
|
-
* <!-- OK Button -->
|
|
9978
|
-
* <ng-template wbDialogAction align="end">
|
|
9979
|
-
* <button (click)="...">OK</button>
|
|
9980
|
-
* </ng-template>
|
|
9981
|
-
*
|
|
9982
|
-
* <!-- Cancel Button -->
|
|
9983
|
-
* <ng-template wbDialogAction align="end">
|
|
9984
|
-
* <button (click)="...">Cancel</button>
|
|
9985
|
-
* </ng-template>
|
|
9986
|
-
* ```
|
|
9987
|
-
*
|
|
9988
|
-
* 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
|
|
9989
|
-
* decorate it with the `wbDialogFooter` directive.
|
|
9990
|
-
*
|
|
9991
|
-
* ```html
|
|
9992
|
-
* <ng-template wbDialogFooter>
|
|
9993
|
-
* <app-dialog-footer/>
|
|
9994
|
-
* </ng-template>
|
|
9995
|
-
* ```
|
|
9996
|
-
*
|
|
9997
|
-
* ## Styling
|
|
9998
|
-
* The following CSS variables can be set to customize the default look of a dialog.
|
|
9999
|
-
*
|
|
10000
|
-
* - `--sci-workbench-dialog-padding`
|
|
10001
|
-
* - `--sci-workbench-dialog-header-height`
|
|
10002
|
-
* - `--sci-workbench-dialog-header-background-color`
|
|
10003
|
-
* - `--sci-workbench-dialog-title-font-family`
|
|
10004
|
-
* - `--sci-workbench-dialog-title-font-weight`
|
|
10005
|
-
* - `--sci-workbench-dialog-title-font-size`
|
|
10006
|
-
* - `--sci-workbench-dialog-title-align`
|
|
9929
|
+
* Provides {@link WorkbenchDialogService} for dependency injection.
|
|
10007
9930
|
*/
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
9931
|
+
function provideWorkbenchDialogService() {
|
|
9932
|
+
return [
|
|
9933
|
+
ɵWorkbenchDialogService,
|
|
9934
|
+
{ provide: WorkbenchDialogService, useExisting: ɵWorkbenchDialogService },
|
|
9935
|
+
];
|
|
10011
9936
|
}
|
|
10012
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogService, decorators: [{
|
|
10013
|
-
type: Injectable,
|
|
10014
|
-
args: [{ providedIn: 'root', useExisting: ɵWorkbenchDialogService }]
|
|
10015
|
-
}] });
|
|
10016
9937
|
|
|
10017
9938
|
/*
|
|
10018
|
-
* Copyright (c) 2018-
|
|
9939
|
+
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
10019
9940
|
*
|
|
10020
9941
|
* This program and the accompanying materials are made
|
|
10021
9942
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -10023,51 +9944,87 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
10023
9944
|
*
|
|
10024
9945
|
* SPDX-License-Identifier: EPL-2.0
|
|
10025
9946
|
*/
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
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);
|
|
10032
9954
|
constructor() {
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
insertionSortOrderFn = () => 0;
|
|
10036
|
-
onAction(key) {
|
|
10037
|
-
this.action.emit(key);
|
|
10038
|
-
}
|
|
10039
|
-
onArrowKey(index, direction) {
|
|
10040
|
-
const actionButtonCount = this._actionButtons().length;
|
|
10041
|
-
const newIndex = (direction === 'left' ? index - 1 : index + 1);
|
|
10042
|
-
this._actionButtons()[(newIndex + actionButtonCount) % actionButtonCount].nativeElement.focus();
|
|
9955
|
+
trackFocus(this._host, this.popup);
|
|
9956
|
+
this.focusInitialElement();
|
|
10043
9957
|
}
|
|
10044
|
-
|
|
10045
|
-
const
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
//
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
}
|
|
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" } : {}) });
|
|
10055
9968
|
}
|
|
10056
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
10057
|
-
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"] }] });
|
|
10058
9973
|
}
|
|
10059
|
-
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: [{
|
|
10060
9975
|
type: Component,
|
|
10061
|
-
args: [{ selector: 'wb-
|
|
10062
|
-
|
|
10063
|
-
|
|
9976
|
+
args: [{ selector: 'wb-popup', imports: [
|
|
9977
|
+
CdkTrapFocus,
|
|
9978
|
+
SciViewportComponent,
|
|
9979
|
+
NgComponentOutlet,
|
|
9980
|
+
], hostDirectives: [
|
|
9981
|
+
GlassPaneDirective,
|
|
9982
|
+
], providers: [
|
|
9983
|
+
configurePopupGlassPane(),
|
|
10064
9984
|
], host: {
|
|
10065
|
-
'[attr.data-
|
|
10066
|
-
|
|
10067
|
-
|
|
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
|
+
}
|
|
10010
|
+
|
|
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.
|
|
10014
|
+
*
|
|
10015
|
+
* The popup component can inject this handle to interact with the popup.
|
|
10016
|
+
*
|
|
10017
|
+
* Popup inputs are available as input properties in the popup component.
|
|
10018
|
+
*
|
|
10019
|
+
* @see WorkbenchPopupService
|
|
10020
|
+
*
|
|
10021
|
+
* @deprecated since version 21.0.0-beta.1. Replaced by `WorkbenchPopup`. Marked for removal in version 22.
|
|
10022
|
+
*/
|
|
10023
|
+
class Popup extends WorkbenchPopup {
|
|
10024
|
+
}
|
|
10068
10025
|
|
|
10069
10026
|
/*
|
|
10070
|
-
* Copyright (c) 2018-
|
|
10027
|
+
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10071
10028
|
*
|
|
10072
10029
|
* This program and the accompanying materials are made
|
|
10073
10030
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -10076,421 +10033,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
10076
10033
|
* SPDX-License-Identifier: EPL-2.0
|
|
10077
10034
|
*/
|
|
10078
10035
|
/**
|
|
10079
|
-
*
|
|
10080
|
-
*
|
|
10081
|
-
* The host element of this modeling directive must be a <ng-template>. The footer shares the lifecycle of the host element.
|
|
10082
|
-
*
|
|
10083
|
-
* **Example:**
|
|
10084
|
-
* ```html
|
|
10085
|
-
* <ng-template wbDialogFooter>
|
|
10086
|
-
* <app-dialog-footer/>
|
|
10087
|
-
* </ng-template>
|
|
10088
|
-
* ```
|
|
10036
|
+
* DI token to register providers available for DI if in the context of a workbench popup.
|
|
10089
10037
|
*/
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
}
|
|
10105
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
10106
|
-
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 });
|
|
10038
|
+
const WORKBENCH_POPUP_CONTEXT = new InjectionToken('WORKBENCH_POPUP_CONTEXT');
|
|
10039
|
+
/**
|
|
10040
|
+
* Provides providers available for DI if in the context of a workbench popup.
|
|
10041
|
+
*/
|
|
10042
|
+
function provideWorkbenchPopupContext() {
|
|
10043
|
+
return {
|
|
10044
|
+
provide: WORKBENCH_POPUP_CONTEXT,
|
|
10045
|
+
useFactory: () => [
|
|
10046
|
+
provideWorkbenchDialogService(),
|
|
10047
|
+
provideWorkbenchMessageBoxService(),
|
|
10048
|
+
provideWorkbenchPopupService(),
|
|
10049
|
+
],
|
|
10050
|
+
multi: true,
|
|
10051
|
+
};
|
|
10107
10052
|
}
|
|
10108
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogFooterDirective, decorators: [{
|
|
10109
|
-
type: Directive,
|
|
10110
|
-
args: [{ selector: 'ng-template[wbDialogFooter]' }]
|
|
10111
|
-
}], ctorParameters: () => [], propDecorators: { divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }] } });
|
|
10112
10053
|
|
|
10113
10054
|
/*
|
|
10114
|
-
* Copyright (c) 2018-
|
|
10115
|
-
*
|
|
10116
|
-
* This program and the accompanying materials are made
|
|
10117
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10118
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10119
|
-
*
|
|
10120
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10121
|
-
*/
|
|
10122
|
-
/**
|
|
10123
|
-
* Use this directive to replace the default dialog header that displays the title and a close button.
|
|
10124
|
-
*
|
|
10125
|
-
* The host element of this modeling directive must be a <ng-template>. The header shares the lifecycle of the host element.
|
|
10126
|
-
*
|
|
10127
|
-
* **Example:**
|
|
10128
|
-
* ```html
|
|
10129
|
-
* <ng-template wbDialogHeader>
|
|
10130
|
-
* <app-dialog-header/>
|
|
10131
|
-
* </ng-template>
|
|
10132
|
-
* ```
|
|
10133
|
-
*/
|
|
10134
|
-
class WorkbenchDialogHeaderDirective {
|
|
10135
|
-
/**
|
|
10136
|
-
* Specifies if to display a visual separator between this header and the dialog content.
|
|
10137
|
-
* Defaults to `true`.
|
|
10138
|
-
*/
|
|
10139
|
-
divider = input(undefined, { ...(ngDevMode ? { debugName: "divider" } : {}), transform: booleanAttribute });
|
|
10140
|
-
template = inject(TemplateRef);
|
|
10141
|
-
_header;
|
|
10142
|
-
constructor() {
|
|
10143
|
-
const dialog = inject(ɵWorkbenchDialog);
|
|
10144
|
-
// Defer registering header to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
10145
|
-
asapScheduler.schedule(() => this._header = dialog.registerHeader(this));
|
|
10146
|
-
// Defer disposing header to avoid `ExpressionChangedAfterItHasBeenCheckedError`.
|
|
10147
|
-
inject(DestroyRef).onDestroy(() => asapScheduler.schedule(() => this._header?.dispose()));
|
|
10148
|
-
}
|
|
10149
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
10150
|
-
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 });
|
|
10151
|
-
}
|
|
10152
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchDialogHeaderDirective, decorators: [{
|
|
10153
|
-
type: Directive,
|
|
10154
|
-
args: [{ selector: 'ng-template[wbDialogHeader]' }]
|
|
10155
|
-
}], ctorParameters: () => [], propDecorators: { divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }] } });
|
|
10156
|
-
|
|
10157
|
-
/*
|
|
10158
|
-
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
10159
|
-
*
|
|
10160
|
-
* This program and the accompanying materials are made
|
|
10161
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10162
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10163
|
-
*
|
|
10164
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10165
|
-
*/
|
|
10166
|
-
class MessageBoxHeaderComponent {
|
|
10167
|
-
title = input(undefined, { ...(ngDevMode ? { debugName: "title" } : {}) });
|
|
10168
|
-
severity = input.required({ ...(ngDevMode ? { debugName: "severity" } : {}) });
|
|
10169
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10170
|
-
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" }] });
|
|
10171
|
-
}
|
|
10172
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MessageBoxHeaderComponent, decorators: [{
|
|
10173
|
-
type: Component,
|
|
10174
|
-
args: [{ selector: 'wb-message-box-header', imports: [
|
|
10175
|
-
TextPipe,
|
|
10176
|
-
], host: {
|
|
10177
|
-
'[attr.data-severity]': 'severity()',
|
|
10178
|
-
}, 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"] }]
|
|
10179
|
-
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], severity: [{ type: i0.Input, args: [{ isSignal: true, alias: "severity", required: true }] }] } });
|
|
10180
|
-
|
|
10181
|
-
/*
|
|
10182
|
-
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
10183
|
-
*
|
|
10184
|
-
* This program and the accompanying materials are made
|
|
10185
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10186
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10187
|
-
*
|
|
10188
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10189
|
-
*/
|
|
10190
|
-
/**
|
|
10191
|
-
* Tests if the object is of the specified type.
|
|
10192
|
-
*/
|
|
10193
|
-
class TypeofPipe {
|
|
10194
|
-
transform(object, type) {
|
|
10195
|
-
return typeof object === type;
|
|
10196
|
-
}
|
|
10197
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: TypeofPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
10198
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.1", ngImport: i0, type: TypeofPipe, isStandalone: true, name: "wbTypeof" });
|
|
10199
|
-
}
|
|
10200
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: TypeofPipe, decorators: [{
|
|
10201
|
-
type: Pipe,
|
|
10202
|
-
args: [{ name: 'wbTypeof' }]
|
|
10203
|
-
}] });
|
|
10204
|
-
|
|
10205
|
-
/*
|
|
10206
|
-
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
10207
|
-
*
|
|
10208
|
-
* This program and the accompanying materials are made
|
|
10209
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10210
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10211
|
-
*
|
|
10212
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10213
|
-
*/
|
|
10214
|
-
/**
|
|
10215
|
-
* Renders the workbench message box.
|
|
10216
|
-
*
|
|
10217
|
-
* This component is designed to be opened in a workbench dialog.
|
|
10218
|
-
*/
|
|
10219
|
-
class WorkbenchMessageBoxComponent {
|
|
10220
|
-
message = input.required({ ...(ngDevMode ? { debugName: "message" } : {}), transform: nullIfEmptyMessage });
|
|
10221
|
-
options = input(undefined, { ...(ngDevMode ? { debugName: "options" } : {}) });
|
|
10222
|
-
_dialog = inject(ɵWorkbenchDialog);
|
|
10223
|
-
empty = signal(false, { ...(ngDevMode ? { debugName: "empty" } : {}) });
|
|
10224
|
-
constructor() {
|
|
10225
|
-
this._dialog.closable = false;
|
|
10226
|
-
this._dialog.resizable = false;
|
|
10227
|
-
this._dialog.padding = false;
|
|
10228
|
-
// Limit the maximum messagebox width if text message to break the message.
|
|
10229
|
-
effect(() => {
|
|
10230
|
-
if (typeof this.message() === 'string' || this.message() === null) {
|
|
10231
|
-
this._dialog.size.maxWidth = 'var(--sci-workbench-messagebox-max-width)';
|
|
10232
|
-
}
|
|
10233
|
-
});
|
|
10234
|
-
}
|
|
10235
|
-
onAction(action) {
|
|
10236
|
-
this._dialog.close(action);
|
|
10237
|
-
}
|
|
10238
|
-
onEscape() {
|
|
10239
|
-
if ('cancel' in (this.options()?.actions ?? {})) {
|
|
10240
|
-
this._dialog.close('cancel');
|
|
10241
|
-
}
|
|
10242
|
-
}
|
|
10243
|
-
onFooterPreferredSizeChange(preferredSize) {
|
|
10244
|
-
this._dialog.size.minWidth = `${preferredSize}px`;
|
|
10245
|
-
}
|
|
10246
|
-
onContentDimensionChange(dimension) {
|
|
10247
|
-
this.empty.set(!dimension.offsetHeight);
|
|
10248
|
-
}
|
|
10249
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10250
|
-
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" }] });
|
|
10251
|
-
}
|
|
10252
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxComponent, decorators: [{
|
|
10253
|
-
type: Component,
|
|
10254
|
-
args: [{ selector: 'wb-message-box', imports: [
|
|
10255
|
-
NgComponentOutlet,
|
|
10256
|
-
SciDimensionDirective,
|
|
10257
|
-
WorkbenchDialogHeaderDirective,
|
|
10258
|
-
WorkbenchDialogFooterDirective,
|
|
10259
|
-
MessageBoxHeaderComponent,
|
|
10260
|
-
MessageBoxFooterComponent,
|
|
10261
|
-
TypeofPipe,
|
|
10262
|
-
TextPipe,
|
|
10263
|
-
], host: {
|
|
10264
|
-
// Ensure host element to be focusable in order to close the message box on Escape keystroke.
|
|
10265
|
-
'[attr.tabindex]': '-1',
|
|
10266
|
-
'[class.empty]': 'empty()',
|
|
10267
|
-
'[class.content-selectable]': 'options()?.contentSelectable',
|
|
10268
|
-
'[class.has-title]': '!!this.options()?.title',
|
|
10269
|
-
'(keydown.escape)': 'onEscape()',
|
|
10270
|
-
}, 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"] }]
|
|
10271
|
-
}], ctorParameters: () => [], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }] } });
|
|
10272
|
-
function nullIfEmptyMessage(message) {
|
|
10273
|
-
return message !== '' ? message : null;
|
|
10274
|
-
}
|
|
10275
|
-
|
|
10276
|
-
/**
|
|
10277
|
-
* Provides a standardized dialog for presenting a message to the user, such as an info, warning or alert,
|
|
10278
|
-
* or for prompting the user for confirmation. The message can be plain text or a component, allowing for
|
|
10279
|
-
* structured content or input prompts.
|
|
10280
|
-
*
|
|
10281
|
-
* Displayed on top of other content, a modal message box blocks interaction with other parts of the application.
|
|
10282
|
-
*
|
|
10283
|
-
* ## Modality
|
|
10284
|
-
* A message box can be context-modal or application-modal. Context-modal blocks a specific part of the application, as specified by the context;
|
|
10285
|
-
* application-modal blocks the workbench or browser viewport, based on {@link WorkbenchConfig.dialog.modalityScope}.
|
|
10286
|
-
*
|
|
10287
|
-
* ## Context
|
|
10288
|
-
* A message box can be bound to a context (e.g., part or view), defaulting to the calling context.
|
|
10289
|
-
* The message box is displayed only if the context is visible and closes when the context is disposed.
|
|
10290
|
-
*
|
|
10291
|
-
* ## Positioning
|
|
10292
|
-
* A message box is opened in the center of its context, if any, unless opened from the peripheral area.
|
|
10293
|
-
*
|
|
10294
|
-
* ## Stacking
|
|
10295
|
-
* Message boxes are stacked per modality, with only the topmost message box in each stack being interactive.
|
|
10296
|
-
*
|
|
10297
|
-
* ## Styling
|
|
10298
|
-
* The following CSS variables can be set to customize the default look of a message box.
|
|
10299
|
-
*
|
|
10300
|
-
* - `--sci-workbench-messagebox-max-width`
|
|
10301
|
-
* - `--sci-workbench-messagebox-severity-indicator-size`
|
|
10302
|
-
* - `--sci-workbench-messagebox-padding`
|
|
10303
|
-
* - `--sci-workbench-messagebox-text-align`
|
|
10304
|
-
* - `--sci-workbench-messagebox-title-align`
|
|
10305
|
-
* - `--sci-workbench-messagebox-title-font-family`
|
|
10306
|
-
* - `--sci-workbench-messagebox-title-font-weight`
|
|
10307
|
-
* - `--sci-workbench-messagebox-title-font-size`
|
|
10308
|
-
*/
|
|
10309
|
-
class WorkbenchMessageBoxService {
|
|
10310
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10311
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, providedIn: 'root', useExisting: ɵWorkbenchMessageBoxService });
|
|
10312
|
-
}
|
|
10313
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchMessageBoxService, decorators: [{
|
|
10314
|
-
type: Injectable,
|
|
10315
|
-
args: [{ providedIn: 'root', useExisting: ɵWorkbenchMessageBoxService }]
|
|
10316
|
-
}] });
|
|
10317
|
-
|
|
10318
|
-
/*
|
|
10319
|
-
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
10320
|
-
*
|
|
10321
|
-
* This program and the accompanying materials are made
|
|
10322
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10323
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10324
|
-
*
|
|
10325
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10326
|
-
*/
|
|
10327
|
-
/** @inheritDoc */
|
|
10328
|
-
class ɵWorkbenchMessageBoxService {
|
|
10329
|
-
_workbenchDialogService = inject(WorkbenchDialogService);
|
|
10330
|
-
_zone = inject(NgZone);
|
|
10331
|
-
constructor() {
|
|
10332
|
-
this.installServiceLifecycleLogger();
|
|
10333
|
-
}
|
|
10334
|
-
/**
|
|
10335
|
-
* @inheritDoc
|
|
10336
|
-
*/
|
|
10337
|
-
async open(message, options) {
|
|
10338
|
-
assertNotInReactiveContext(this.open, 'Call WorkbenchMessageBoxService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
10339
|
-
// 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.
|
|
10340
|
-
if (!NgZone.isInAngularZone()) {
|
|
10341
|
-
return this._zone.run(() => this.open(message, options));
|
|
10342
|
-
}
|
|
10343
|
-
return (await this._workbenchDialogService.open(WorkbenchMessageBoxComponent, {
|
|
10344
|
-
inputs: { message, options },
|
|
10345
|
-
modality: options?.modality,
|
|
10346
|
-
injector: options?.injector,
|
|
10347
|
-
providers: options?.providers,
|
|
10348
|
-
cssClass: options?.cssClass,
|
|
10349
|
-
context: options?.context,
|
|
10350
|
-
animate: true,
|
|
10351
|
-
}));
|
|
10352
|
-
}
|
|
10353
|
-
installServiceLifecycleLogger() {
|
|
10354
|
-
const logger = inject(Logger);
|
|
10355
|
-
const workbenchElement = inject(WORKBENCH_ELEMENT, { optional: true });
|
|
10356
|
-
logger.debug(() => `Constructing WorkbenchMessageBoxService [context=${workbenchElement?.id}]`, LoggerNames.LIFECYCLE);
|
|
10357
|
-
inject(DestroyRef).onDestroy(() => logger.debug(() => `Destroying WorkbenchMessageBoxService [context=${workbenchElement?.id}]'`, LoggerNames.LIFECYCLE));
|
|
10358
|
-
}
|
|
10359
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10360
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, providedIn: 'root' });
|
|
10361
|
-
}
|
|
10362
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchMessageBoxService, decorators: [{
|
|
10363
|
-
type: Injectable,
|
|
10364
|
-
args: [{ providedIn: 'root' }]
|
|
10365
|
-
}], ctorParameters: () => [] });
|
|
10366
|
-
/**
|
|
10367
|
-
* Provides {@link WorkbenchDialogService} for dependency injection.
|
|
10368
|
-
*/
|
|
10369
|
-
function provideWorkbenchMessageBoxService() {
|
|
10370
|
-
return [
|
|
10371
|
-
ɵWorkbenchMessageBoxService,
|
|
10372
|
-
{ provide: WorkbenchMessageBoxService, useExisting: ɵWorkbenchMessageBoxService },
|
|
10373
|
-
];
|
|
10374
|
-
}
|
|
10375
|
-
|
|
10376
|
-
/*
|
|
10377
|
-
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
10378
|
-
*
|
|
10379
|
-
* This program and the accompanying materials are made
|
|
10380
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10381
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10382
|
-
*
|
|
10383
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10384
|
-
*/
|
|
10385
|
-
/**
|
|
10386
|
-
* Renders the content of a workbench popup.
|
|
10387
|
-
*/
|
|
10388
|
-
class WorkbenchPopupComponent {
|
|
10389
|
-
_host = inject(ElementRef).nativeElement;
|
|
10390
|
-
_cdkTrapFocus = viewChild.required('focus_trap', { read: CdkTrapFocus });
|
|
10391
|
-
popup = inject(ɵWorkbenchPopup);
|
|
10392
|
-
constructor() {
|
|
10393
|
-
trackFocus(this._host, this.popup);
|
|
10394
|
-
this.focusInitialElement();
|
|
10395
|
-
}
|
|
10396
|
-
focusInitialElement() {
|
|
10397
|
-
const effectRef = effect(() => {
|
|
10398
|
-
// [Angular 14] The initial focus must not be requested via `cdkTrapFocusAutoCapture` as this would restore
|
|
10399
|
-
// focus to the previously focused element when the `FocusTrap` is destroyed. This behavior is unwanted if the
|
|
10400
|
-
// popup is closed by losing focus. Otherwise, the newly focused element that caused the loss of focus and thus
|
|
10401
|
-
// the closing of the popup would immediately become unfocused again. This behavior could only be observed when
|
|
10402
|
-
// the popup loses focus by clicking on an element in a microfrontend.
|
|
10403
|
-
void this._cdkTrapFocus().focusTrap.focusInitialElementWhenReady();
|
|
10404
|
-
effectRef.destroy();
|
|
10405
|
-
}, { ...(ngDevMode ? { debugName: "effectRef" } : {}) });
|
|
10406
|
-
}
|
|
10407
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10408
|
-
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: [
|
|
10409
|
-
configurePopupGlassPane(),
|
|
10410
|
-
], 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"] }] });
|
|
10411
|
-
}
|
|
10412
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchPopupComponent, decorators: [{
|
|
10413
|
-
type: Component,
|
|
10414
|
-
args: [{ selector: 'wb-popup', imports: [
|
|
10415
|
-
CdkTrapFocus,
|
|
10416
|
-
SciViewportComponent,
|
|
10417
|
-
NgComponentOutlet,
|
|
10418
|
-
], hostDirectives: [
|
|
10419
|
-
GlassPaneDirective,
|
|
10420
|
-
], providers: [
|
|
10421
|
-
configurePopupGlassPane(),
|
|
10422
|
-
], host: {
|
|
10423
|
-
'[attr.data-popupid]': 'popup.id',
|
|
10424
|
-
'[style.width]': 'popup.size.width()',
|
|
10425
|
-
'[style.min-width]': 'popup.size.minWidth()',
|
|
10426
|
-
'[style.max-width]': 'popup.size.maxWidth()',
|
|
10427
|
-
'[style.height]': 'popup.size.height()',
|
|
10428
|
-
'[style.min-height]': 'popup.size.minHeight()',
|
|
10429
|
-
'[style.max-height]': 'popup.size.maxHeight()',
|
|
10430
|
-
'[class]': 'popup.cssClass()',
|
|
10431
|
-
}, 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"] }]
|
|
10432
|
-
}], ctorParameters: () => [], propDecorators: { _cdkTrapFocus: [{ type: i0.ViewChild, args: ['focus_trap', { ...{ read: CdkTrapFocus }, isSignal: true }] }] } });
|
|
10433
|
-
/**
|
|
10434
|
-
* Blocks this popup when dialog(s) overlay it.
|
|
10435
|
-
*/
|
|
10436
|
-
function configurePopupGlassPane() {
|
|
10437
|
-
return [
|
|
10438
|
-
{
|
|
10439
|
-
provide: GLASS_PANE_BLOCKABLE,
|
|
10440
|
-
useFactory: () => inject(ɵWorkbenchPopup),
|
|
10441
|
-
},
|
|
10442
|
-
{
|
|
10443
|
-
provide: GLASS_PANE_OPTIONS,
|
|
10444
|
-
useFactory: () => ({ attributes: { 'data-popupid': inject(ɵWorkbenchPopup).id } }),
|
|
10445
|
-
},
|
|
10446
|
-
];
|
|
10447
|
-
}
|
|
10448
|
-
|
|
10449
|
-
/**
|
|
10450
|
-
* A popup is a visual workbench element for displaying content above other content. The popup is positioned relative
|
|
10451
|
-
* to an anchor based on its preferred alignment. The anchor can be an element or a coordinate.
|
|
10452
|
-
*
|
|
10453
|
-
* The popup component can inject this handle to interact with the popup.
|
|
10454
|
-
*
|
|
10455
|
-
* Popup inputs are available as input properties in the popup component.
|
|
10456
|
-
*
|
|
10457
|
-
* @see WorkbenchPopupService
|
|
10458
|
-
*
|
|
10459
|
-
* @deprecated since version 21.0.0-beta.1. Replaced by `WorkbenchPopup`. Marked for removal in version 22.
|
|
10460
|
-
*/
|
|
10461
|
-
class Popup extends WorkbenchPopup {
|
|
10462
|
-
}
|
|
10463
|
-
|
|
10464
|
-
/*
|
|
10465
|
-
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10466
|
-
*
|
|
10467
|
-
* This program and the accompanying materials are made
|
|
10468
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
10469
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10470
|
-
*
|
|
10471
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
10472
|
-
*/
|
|
10473
|
-
/**
|
|
10474
|
-
* DI token to register providers available for DI if in the context of a workbench popup.
|
|
10475
|
-
*/
|
|
10476
|
-
const WORKBENCH_POPUP_CONTEXT = new InjectionToken('WORKBENCH_POPUP_CONTEXT');
|
|
10477
|
-
/**
|
|
10478
|
-
* Provides providers available for DI if in the context of a workbench popup.
|
|
10479
|
-
*/
|
|
10480
|
-
function provideWorkbenchPopupContext() {
|
|
10481
|
-
return {
|
|
10482
|
-
provide: WORKBENCH_POPUP_CONTEXT,
|
|
10483
|
-
useFactory: () => [
|
|
10484
|
-
provideWorkbenchDialogService(),
|
|
10485
|
-
provideWorkbenchMessageBoxService(),
|
|
10486
|
-
provideWorkbenchPopupService(),
|
|
10487
|
-
],
|
|
10488
|
-
multi: true,
|
|
10489
|
-
};
|
|
10490
|
-
}
|
|
10491
|
-
|
|
10492
|
-
/*
|
|
10493
|
-
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10055
|
+
* Copyright (c) 2018-2025 Swiss Federal Railways
|
|
10494
10056
|
*
|
|
10495
10057
|
* This program and the accompanying materials are made
|
|
10496
10058
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -11024,6 +10586,65 @@ function createInvocationContext(elementId, options) {
|
|
|
11024
10586
|
return null;
|
|
11025
10587
|
}
|
|
11026
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 });
|
|
10646
|
+
}
|
|
10647
|
+
|
|
11027
10648
|
/*
|
|
11028
10649
|
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
11029
10650
|
*
|
|
@@ -11080,103 +10701,54 @@ class ɵPopupService {
|
|
|
11080
10701
|
{ provide: LEGACY_POPUP_INPUT, useValue: config.input },
|
|
11081
10702
|
],
|
|
11082
10703
|
});
|
|
11083
|
-
}
|
|
11084
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11085
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵPopupService, providedIn: 'root' });
|
|
11086
|
-
}
|
|
11087
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵPopupService, decorators: [{
|
|
11088
|
-
type: Injectable,
|
|
11089
|
-
args: [{ providedIn: 'root' }]
|
|
11090
|
-
}] });
|
|
11091
|
-
|
|
11092
|
-
/*
|
|
11093
|
-
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
11094
|
-
*
|
|
11095
|
-
* This program and the accompanying materials are made
|
|
11096
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
11097
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11098
|
-
*
|
|
11099
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
11100
|
-
*/
|
|
11101
|
-
/**
|
|
11102
|
-
* Enables the display of a component in a popup.
|
|
11103
|
-
*
|
|
11104
|
-
* A popup is a visual workbench element for displaying content above other content. It is positioned relative to an anchor,
|
|
11105
|
-
* which can be an element or a coordinate. The popup moves with the anchor. By default, the popup closes on focus loss or
|
|
11106
|
-
* when pressing the escape key.
|
|
11107
|
-
*
|
|
11108
|
-
* A popup can be bound to a context (e.g., part or view), displaying the popup only if the context is visible and closing
|
|
11109
|
-
* it when the context is disposed. Defaults to the calling context.
|
|
11110
|
-
*
|
|
11111
|
-
* @deprecated since version 21.0.0-beta.1. Use `WorkbenchPopupService` to open popups. Marked for removal in version 22.
|
|
11112
|
-
*/
|
|
11113
|
-
class PopupService {
|
|
11114
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11115
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PopupService, providedIn: 'root', useExisting: ɵPopupService });
|
|
11116
|
-
}
|
|
11117
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PopupService, decorators: [{
|
|
11118
|
-
type: Injectable,
|
|
11119
|
-
args: [{ providedIn: 'root', useExisting: ɵPopupService }]
|
|
11120
|
-
}] });
|
|
11121
|
-
|
|
11122
|
-
/*
|
|
11123
|
-
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
11124
|
-
*
|
|
11125
|
-
* This program and the accompanying materials are made
|
|
11126
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
11127
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11128
|
-
*
|
|
11129
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
11130
|
-
*/
|
|
11131
|
-
/** @inheritDoc */
|
|
11132
|
-
class ɵWorkbenchPopupService {
|
|
11133
|
-
_injector = inject(Injector);
|
|
11134
|
-
_rootInjector = inject(ApplicationRef).injector;
|
|
11135
|
-
_popupRegistry = inject(WorkbenchPopupRegistry);
|
|
11136
|
-
_zone = inject(NgZone);
|
|
11137
|
-
/** @inheritDoc */
|
|
11138
|
-
async open(component, options) {
|
|
11139
|
-
assertNotInReactiveContext(this.open, 'Call WorkbenchPopupService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
11140
|
-
// Ensure to run in Angular zone to display the popup even when called from outside the Angular zone.
|
|
11141
|
-
if (!NgZone.isInAngularZone()) {
|
|
11142
|
-
return this._zone.run(() => this.open(component, options));
|
|
11143
|
-
}
|
|
11144
|
-
const popup = this.createPopup(component, options);
|
|
11145
|
-
this._popupRegistry.register(popup.id, popup);
|
|
11146
|
-
try {
|
|
11147
|
-
return await popup.waitForClose();
|
|
11148
|
-
}
|
|
11149
|
-
finally {
|
|
11150
|
-
this._popupRegistry.unregister(popup.id);
|
|
11151
|
-
}
|
|
11152
|
-
}
|
|
11153
|
-
/**
|
|
11154
|
-
* Creates the popup handle.
|
|
11155
|
-
*/
|
|
11156
|
-
createPopup(component, options) {
|
|
11157
|
-
// Construct the handle in an injection context that shares the popup's lifecycle, allowing for automatic cleanup of effects and RxJS interop functions.
|
|
11158
|
-
const popupId = options.id ?? computePopupId();
|
|
11159
|
-
const popupInjector = Injector.create({
|
|
11160
|
-
parent: this._rootInjector, // use root injector to be independent of service construction context
|
|
11161
|
-
providers: [],
|
|
11162
|
-
name: `Workbench Popup ${popupId}`,
|
|
11163
|
-
});
|
|
11164
|
-
const invocationContext = createPopupInvocationContext(options, this._injector);
|
|
11165
|
-
return runInInjectionContext(popupInjector, () => new ɵWorkbenchPopup(popupId, component, invocationContext, options));
|
|
11166
|
-
}
|
|
11167
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11168
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵWorkbenchPopupService, providedIn: 'root' });
|
|
10704
|
+
}
|
|
10705
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10706
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵPopupService, providedIn: 'root' });
|
|
11169
10707
|
}
|
|
11170
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
10708
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ɵPopupService, decorators: [{
|
|
11171
10709
|
type: Injectable,
|
|
11172
10710
|
args: [{ providedIn: 'root' }]
|
|
11173
10711
|
}] });
|
|
10712
|
+
|
|
10713
|
+
/*
|
|
10714
|
+
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
10715
|
+
*
|
|
10716
|
+
* This program and the accompanying materials are made
|
|
10717
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
10718
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10719
|
+
*
|
|
10720
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
10721
|
+
*/
|
|
11174
10722
|
/**
|
|
11175
|
-
*
|
|
10723
|
+
* Enables the display of a component in a popup.
|
|
10724
|
+
*
|
|
10725
|
+
* A popup is a visual workbench element for displaying content above other content. It is positioned relative to an anchor,
|
|
10726
|
+
* which can be an element or a coordinate. The popup moves with the anchor. By default, the popup closes on focus loss or
|
|
10727
|
+
* when pressing the escape key.
|
|
10728
|
+
*
|
|
10729
|
+
* A popup can be bound to a context (e.g., part or view), displaying the popup only if the context is visible and closing
|
|
10730
|
+
* it when the context is disposed. Defaults to the calling context.
|
|
10731
|
+
*
|
|
10732
|
+
* @deprecated since version 21.0.0-beta.1. Use `WorkbenchPopupService` to open popups. Marked for removal in version 22.
|
|
11176
10733
|
*/
|
|
11177
|
-
|
|
11178
|
-
|
|
10734
|
+
class PopupService {
|
|
10735
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10736
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PopupService, providedIn: 'root', useExisting: ɵPopupService });
|
|
11179
10737
|
}
|
|
10738
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: PopupService, decorators: [{
|
|
10739
|
+
type: Injectable,
|
|
10740
|
+
args: [{ providedIn: 'root', useExisting: ɵPopupService }]
|
|
10741
|
+
}] });
|
|
10742
|
+
|
|
10743
|
+
/*
|
|
10744
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
10745
|
+
*
|
|
10746
|
+
* This program and the accompanying materials are made
|
|
10747
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
10748
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
10749
|
+
*
|
|
10750
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
10751
|
+
*/
|
|
11180
10752
|
/**
|
|
11181
10753
|
* Provides {@link WorkbenchPopupService} for dependency injection.
|
|
11182
10754
|
*/
|
|
@@ -11388,230 +10960,680 @@ class ɵWorkbenchDialog {
|
|
|
11388
10960
|
return this._padding;
|
|
11389
10961
|
}
|
|
11390
10962
|
/** @inheritDoc */
|
|
11391
|
-
set padding(padding) {
|
|
11392
|
-
untracked(() => this._padding.set(padding));
|
|
10963
|
+
set padding(padding) {
|
|
10964
|
+
untracked(() => this._padding.set(padding));
|
|
10965
|
+
}
|
|
10966
|
+
/** @inheritDoc */
|
|
10967
|
+
get cssClass() {
|
|
10968
|
+
return this._cssClass;
|
|
10969
|
+
}
|
|
10970
|
+
/** @inheritDoc */
|
|
10971
|
+
set cssClass(cssClass) {
|
|
10972
|
+
untracked(() => this._cssClass.set(new Array().concat(this._options.cssClass ?? []).concat(cssClass)));
|
|
10973
|
+
}
|
|
10974
|
+
/**
|
|
10975
|
+
* Returns the position of the dialog in the dialog stack.
|
|
10976
|
+
*/
|
|
10977
|
+
getPositionInDialogStack() {
|
|
10978
|
+
return this._workbenchDialogRegistry.indexOf(this);
|
|
10979
|
+
}
|
|
10980
|
+
/** @inheritDoc */
|
|
10981
|
+
blink() {
|
|
10982
|
+
this._blink$.next();
|
|
10983
|
+
}
|
|
10984
|
+
/**
|
|
10985
|
+
* Creates a portal to render {@link WorkbenchDialogComponent} in the dialog's injection context.
|
|
10986
|
+
*/
|
|
10987
|
+
createPortal() {
|
|
10988
|
+
const injector = Injector.create({
|
|
10989
|
+
parent: this._options.injector ?? inject(Injector),
|
|
10990
|
+
providers: [
|
|
10991
|
+
{ provide: ɵWorkbenchDialog, useValue: this },
|
|
10992
|
+
{ provide: WorkbenchDialog, useExisting: ɵWorkbenchDialog },
|
|
10993
|
+
{ provide: WORKBENCH_ELEMENT, useExisting: ɵWorkbenchDialog },
|
|
10994
|
+
inject(WORKBENCH_DIALOG_CONTEXT, { optional: true }) ?? [],
|
|
10995
|
+
this._options.providers ?? [],
|
|
10996
|
+
],
|
|
10997
|
+
});
|
|
10998
|
+
inject(DestroyRef).onDestroy(() => injector.destroy());
|
|
10999
|
+
return new ComponentPortal(WorkbenchDialogComponent, null, injector);
|
|
11000
|
+
}
|
|
11001
|
+
/**
|
|
11002
|
+
* Creates a dedicated overlay per dialog to place it on top of previously created overlays, such as dialogs, popups, dropdowns, etc.
|
|
11003
|
+
*/
|
|
11004
|
+
createOverlay() {
|
|
11005
|
+
const overlay = inject(Overlay);
|
|
11006
|
+
return overlay.create({
|
|
11007
|
+
disposeOnNavigation: true, // dispose dialog on browser back/forward navigation
|
|
11008
|
+
panelClass: ['wb-dialog-modality-context'],
|
|
11009
|
+
positionStrategy: overlay.position().global(),
|
|
11010
|
+
scrollStrategy: overlay.scrollStrategies.noop(),
|
|
11011
|
+
});
|
|
11012
|
+
}
|
|
11013
|
+
/**
|
|
11014
|
+
* Restores focus when re-attaching this dialog.
|
|
11015
|
+
*/
|
|
11016
|
+
restoreFocusOnAttach() {
|
|
11017
|
+
effect(() => {
|
|
11018
|
+
const attached = this.attached();
|
|
11019
|
+
untracked(() => attached && this.focus());
|
|
11020
|
+
});
|
|
11021
|
+
}
|
|
11022
|
+
/**
|
|
11023
|
+
* Restores focus when unblocking this dialog.
|
|
11024
|
+
*/
|
|
11025
|
+
restoreFocusOnUnblock() {
|
|
11026
|
+
effect(() => {
|
|
11027
|
+
const blocked = this.blockedBy();
|
|
11028
|
+
untracked(() => !blocked && this.focus());
|
|
11029
|
+
});
|
|
11030
|
+
}
|
|
11031
|
+
/**
|
|
11032
|
+
* Monitors attachment of the host element.
|
|
11033
|
+
*/
|
|
11034
|
+
monitorHostElementAttached() {
|
|
11035
|
+
if (this.invocationContext) {
|
|
11036
|
+
return this.invocationContext.attached;
|
|
11037
|
+
}
|
|
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));
|
|
11393
11178
|
}
|
|
11394
11179
|
/** @inheritDoc */
|
|
11395
|
-
get
|
|
11396
|
-
return this.
|
|
11180
|
+
get maxWidth() {
|
|
11181
|
+
return this._maxWidth;
|
|
11397
11182
|
}
|
|
11398
11183
|
/** @inheritDoc */
|
|
11399
|
-
set
|
|
11400
|
-
untracked(() => this.
|
|
11184
|
+
set maxWidth(maxWidth) {
|
|
11185
|
+
untracked(() => this._maxWidth.set(maxWidth));
|
|
11401
11186
|
}
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
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();
|
|
11407
11207
|
}
|
|
11408
11208
|
/** @inheritDoc */
|
|
11409
|
-
|
|
11410
|
-
this.
|
|
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
|
+
}
|
|
11235
|
+
}
|
|
11411
11236
|
}
|
|
11412
11237
|
/**
|
|
11413
|
-
* Creates
|
|
11238
|
+
* Creates the dialog handle.
|
|
11414
11239
|
*/
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
inject(WORKBENCH_DIALOG_CONTEXT, { optional: true }) ?? [],
|
|
11423
|
-
this._options.providers ?? [],
|
|
11424
|
-
],
|
|
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}`,
|
|
11425
11247
|
});
|
|
11426
|
-
|
|
11427
|
-
return new ComponentPortal(WorkbenchDialogComponent, null, injector);
|
|
11248
|
+
return runInInjectionContext(dialogInjector, () => new ɵWorkbenchDialog(dialogId, component, invocationContext, options));
|
|
11428
11249
|
}
|
|
11429
11250
|
/**
|
|
11430
|
-
*
|
|
11251
|
+
* Returns a Promise that resolves when all application modal-dialogs are closed. If none are opened, the Promise resolves immediately.
|
|
11431
11252
|
*/
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
|
|
11436
|
-
|
|
11437
|
-
positionStrategy: overlay.position().global(),
|
|
11438
|
-
scrollStrategy: overlay.scrollStrategies.noop(),
|
|
11439
|
-
});
|
|
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();
|
|
11440
11258
|
}
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
const attached = this.attached();
|
|
11447
|
-
untracked(() => attached && this.focus());
|
|
11448
|
-
});
|
|
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));
|
|
11449
11264
|
}
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
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();
|
|
11458
11397
|
}
|
|
11459
|
-
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
monitorHostElementAttached() {
|
|
11463
|
-
if (this.invocationContext) {
|
|
11464
|
-
return this.invocationContext.attached;
|
|
11465
|
-
}
|
|
11466
|
-
if (this._workbenchConfig.dialog?.modalityScope === 'viewport') {
|
|
11467
|
-
return computed(() => true);
|
|
11468
|
-
}
|
|
11469
|
-
const workbenchComponentRef = inject(WORKBENCH_COMPONENT_REF);
|
|
11470
|
-
return computed(() => !!workbenchComponentRef());
|
|
11398
|
+
insertionSortOrderFn = () => 0;
|
|
11399
|
+
onAction(key) {
|
|
11400
|
+
this.action.emit(key);
|
|
11471
11401
|
}
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
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);
|
|
11480
11414
|
}
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
const workbenchComponentBounds = inject(WORKBENCH_COMPONENT_BOUNDS);
|
|
11484
|
-
const document = inject(DOCUMENT);
|
|
11485
|
-
effect(() => {
|
|
11486
|
-
const visible = this.attached() && !viewDragService.dragging();
|
|
11487
|
-
// Maintain position and size when hidden to prevent flickering when visible again and to support for virtual scrolling in dialog content.
|
|
11488
|
-
if (!visible) {
|
|
11489
|
-
setStyle(this._overlayRef.overlayElement, { visibility: 'hidden' }); // Hide via `visibility` instead of `display` property to retain the size.
|
|
11490
|
-
return;
|
|
11491
|
-
}
|
|
11492
|
-
// IMPORTANT: Track host bounds only if visible to prevent flickering.
|
|
11493
|
-
// Align dialog relative to contextual element if opened in non-peripheral area.
|
|
11494
|
-
const hostBounds = this.invocationContext?.peripheral() === false ? this.invocationContext.bounds() : workbenchComponentBounds();
|
|
11495
|
-
if (!hostBounds) {
|
|
11496
|
-
setStyle(this._overlayRef.overlayElement, { visibility: 'hidden' }); // Hide via `visibility` instead of `display` property to retain the size.
|
|
11497
|
-
return;
|
|
11498
|
-
}
|
|
11499
|
-
setStyle(this._overlayRef.overlayElement, { visibility: null });
|
|
11500
|
-
// Center the dialog horizontally within the host bounds.
|
|
11501
|
-
// Shift the overlay instead of fitting it to the host bounds, so the dialog can grow beyond host bounds
|
|
11502
|
-
// if not specifying dialog size via a dialog handle.
|
|
11503
|
-
const { left, top, width } = hostBounds;
|
|
11504
|
-
const viewportCenter = document.documentElement.offsetWidth / 2;
|
|
11505
|
-
const dialogCenter = left + width / 2;
|
|
11506
|
-
const xDelta = -1 * (viewportCenter - dialogCenter);
|
|
11507
|
-
setStyle(this._overlayRef.hostElement, {
|
|
11508
|
-
transform: `translateX(${Math.round(xDelta)}px) translateY(${Math.round(top)}px)`, // round offset to avoid blurry dialog
|
|
11509
|
-
});
|
|
11510
|
-
});
|
|
11415
|
+
finally {
|
|
11416
|
+
host.classList.remove('calculating-min-width');
|
|
11511
11417
|
}
|
|
11512
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 {
|
|
11513
11454
|
/**
|
|
11514
|
-
*
|
|
11515
|
-
|
|
11516
|
-
computeBlocked() {
|
|
11517
|
-
const dialogRegistry = inject(WorkbenchDialogRegistry);
|
|
11518
|
-
const topInThisContext = dialogRegistry.top(this.id);
|
|
11519
|
-
const topInInvocationContext = dialogRegistry.top(this.invocationContext?.elementId);
|
|
11520
|
-
return computed(() => {
|
|
11521
|
-
// Get the top dialog in the context spawned by this dialog.
|
|
11522
|
-
if (topInThisContext()) {
|
|
11523
|
-
return topInThisContext();
|
|
11524
|
-
}
|
|
11525
|
-
// Get the top dialog in the context this dialog was opened in.
|
|
11526
|
-
if (topInInvocationContext() !== this) {
|
|
11527
|
-
return topInInvocationContext();
|
|
11528
|
-
}
|
|
11529
|
-
return null;
|
|
11530
|
-
});
|
|
11531
|
-
}
|
|
11532
|
-
blinkOnRequest() {
|
|
11533
|
-
this._blink$
|
|
11534
|
-
.pipe(switchMap(() => of(true).pipe(concatWith(of(false).pipe(delay(300))))), distinctUntilChanged(), takeUntilDestroyed())
|
|
11535
|
-
.subscribe(this.blinking$);
|
|
11536
|
-
}
|
|
11537
|
-
/**
|
|
11538
|
-
* Closes the dialog when the context element is destroyed.
|
|
11455
|
+
* Specifies if to display a visual separator between the dialog content and this footer.
|
|
11456
|
+
* Defaults to `true`.
|
|
11539
11457
|
*/
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
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()));
|
|
11548
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 {
|
|
11549
11498
|
/**
|
|
11550
|
-
*
|
|
11499
|
+
* Specifies if to display a visual separator between this header and the dialog content.
|
|
11500
|
+
* Defaults to `true`.
|
|
11551
11501
|
*/
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
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()));
|
|
11557
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 });
|
|
11558
11514
|
}
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
}
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
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;
|
|
11594
11559
|
}
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
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
|
+
});
|
|
11598
11597
|
}
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
return this._minWidth;
|
|
11598
|
+
onAction(action) {
|
|
11599
|
+
this._dialog.close(action);
|
|
11602
11600
|
}
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11601
|
+
onEscape() {
|
|
11602
|
+
if ('cancel' in (this.options()?.actions ?? {})) {
|
|
11603
|
+
this._dialog.close('cancel');
|
|
11604
|
+
}
|
|
11606
11605
|
}
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
return this._maxWidth;
|
|
11606
|
+
onFooterPreferredSizeChange(preferredSize) {
|
|
11607
|
+
this._dialog.size.minWidth = `${preferredSize}px`;
|
|
11610
11608
|
}
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
untracked(() => this._maxWidth.set(maxWidth));
|
|
11609
|
+
onContentDimensionChange(dimension) {
|
|
11610
|
+
this.empty.set(!dimension.offsetHeight);
|
|
11614
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;
|
|
11615
11637
|
}
|
|
11616
11638
|
|
|
11617
11639
|
/*
|
|
@@ -11624,95 +11646,103 @@ class ɵWorkbenchDialogSize {
|
|
|
11624
11646
|
* SPDX-License-Identifier: EPL-2.0
|
|
11625
11647
|
*/
|
|
11626
11648
|
/** @inheritDoc */
|
|
11627
|
-
class
|
|
11628
|
-
|
|
11629
|
-
_rootInjector = inject(ApplicationRef).injector;
|
|
11630
|
-
_dialogRegistry = inject(WorkbenchDialogRegistry);
|
|
11631
|
-
_document = inject(DOCUMENT);
|
|
11649
|
+
class ɵWorkbenchMessageBoxService {
|
|
11650
|
+
_workbenchDialogService = inject(WorkbenchDialogService);
|
|
11632
11651
|
_zone = inject(NgZone);
|
|
11633
11652
|
constructor() {
|
|
11634
11653
|
this.installServiceLifecycleLogger();
|
|
11635
11654
|
}
|
|
11636
|
-
/** @inheritDoc */
|
|
11637
|
-
async open(component, options) {
|
|
11638
|
-
assertNotInReactiveContext(this.open, 'Call WorkbenchDialogService.open() in a non-reactive (non-tracking) context, such as within the untracked() function.');
|
|
11639
|
-
// Ensure to run in Angular zone to display the dialog even when called from outside the Angular zone.
|
|
11640
|
-
if (!NgZone.isInAngularZone()) {
|
|
11641
|
-
return this._zone.run(() => this.open(component, options));
|
|
11642
|
-
}
|
|
11643
|
-
// Delay the opening of a context-modal dialog until all application-modal dialogs are closed.
|
|
11644
|
-
// Otherwise, the context-modal dialog would overlap already opened application-modal dialogs.
|
|
11645
|
-
const invocationContext = createDialogInvocationContext(options ?? {}, this._injector);
|
|
11646
|
-
if (invocationContext) {
|
|
11647
|
-
await this.waitUntilApplicationModalDialogsClosed();
|
|
11648
|
-
}
|
|
11649
|
-
// Create the dialog.
|
|
11650
|
-
const dialog = this.createDialog(component, invocationContext, options ?? {});
|
|
11651
|
-
this._dialogRegistry.register(dialog.id, dialog);
|
|
11652
|
-
// Capture focused element to restore focus when closing the dialog.
|
|
11653
|
-
const previouslyFocusedElement = this._document.activeElement instanceof HTMLElement ? this._document.activeElement : undefined;
|
|
11654
|
-
try {
|
|
11655
|
-
return await dialog.waitForClose();
|
|
11656
|
-
}
|
|
11657
|
-
finally {
|
|
11658
|
-
this._dialogRegistry.unregister(dialog.id);
|
|
11659
|
-
// Restore focus to previously focused element when closing the last dialog in the current context.
|
|
11660
|
-
if (previouslyFocusedElement && !this._dialogRegistry.top(invocationContext?.elementId)()) {
|
|
11661
|
-
previouslyFocusedElement.focus();
|
|
11662
|
-
}
|
|
11663
|
-
}
|
|
11664
|
-
}
|
|
11665
|
-
/**
|
|
11666
|
-
* Creates the dialog handle.
|
|
11667
|
-
*/
|
|
11668
|
-
createDialog(component, invocationContext, options) {
|
|
11669
|
-
// Construct the handle in an injection context that shares the dialog's lifecycle, allowing for automatic cleanup of effects and RxJS interop functions.
|
|
11670
|
-
const dialogId = computeDialogId();
|
|
11671
|
-
const dialogInjector = Injector.create({
|
|
11672
|
-
parent: this._rootInjector, // use root injector to be independent of service construction context
|
|
11673
|
-
providers: [],
|
|
11674
|
-
name: `Workbench Dialog ${dialogId}`,
|
|
11675
|
-
});
|
|
11676
|
-
return runInInjectionContext(dialogInjector, () => new ɵWorkbenchDialog(dialogId, component, invocationContext, options));
|
|
11677
|
-
}
|
|
11678
11655
|
/**
|
|
11679
|
-
*
|
|
11656
|
+
* @inheritDoc
|
|
11680
11657
|
*/
|
|
11681
|
-
async
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
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
|
+
}));
|
|
11686
11673
|
}
|
|
11687
11674
|
installServiceLifecycleLogger() {
|
|
11688
11675
|
const logger = inject(Logger);
|
|
11689
11676
|
const workbenchElement = inject(WORKBENCH_ELEMENT, { optional: true });
|
|
11690
|
-
logger.debug(() => `Constructing
|
|
11691
|
-
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));
|
|
11692
11679
|
}
|
|
11693
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type:
|
|
11694
|
-
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' });
|
|
11695
11682
|
}
|
|
11696
|
-
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: [{
|
|
11697
11684
|
type: Injectable,
|
|
11698
11685
|
args: [{ providedIn: 'root' }]
|
|
11699
11686
|
}], ctorParameters: () => [] });
|
|
11687
|
+
|
|
11700
11688
|
/**
|
|
11701
|
-
*
|
|
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`
|
|
11702
11720
|
*/
|
|
11703
|
-
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
}
|
|
11707
|
-
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 });
|
|
11708
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
|
+
*/
|
|
11709
11739
|
/**
|
|
11710
|
-
* Provides {@link
|
|
11740
|
+
* Provides {@link WorkbenchMessageBoxService} for dependency injection.
|
|
11711
11741
|
*/
|
|
11712
|
-
function
|
|
11742
|
+
function provideWorkbenchMessageBoxService() {
|
|
11713
11743
|
return [
|
|
11714
|
-
|
|
11715
|
-
{ provide:
|
|
11744
|
+
ɵWorkbenchMessageBoxService,
|
|
11745
|
+
{ provide: WorkbenchMessageBoxService, useExisting: ɵWorkbenchMessageBoxService },
|
|
11716
11746
|
];
|
|
11717
11747
|
}
|
|
11718
11748
|
|
|
@@ -12694,6 +12724,11 @@ class ViewTabComponent {
|
|
|
12694
12724
|
event.stopPropagation();
|
|
12695
12725
|
event.preventDefault();
|
|
12696
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
|
+
}
|
|
12697
12732
|
onDragStart(event) {
|
|
12698
12733
|
if (!event.dataTransfer) {
|
|
12699
12734
|
return;
|
|
@@ -12758,7 +12793,7 @@ class ViewTabComponent {
|
|
|
12758
12793
|
});
|
|
12759
12794
|
}
|
|
12760
12795
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ViewTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12761
|
-
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" }] });
|
|
12762
12797
|
}
|
|
12763
12798
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ViewTabComponent, decorators: [{
|
|
12764
12799
|
type: Component,
|
|
@@ -12779,6 +12814,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
12779
12814
|
'(click)': 'onClick()',
|
|
12780
12815
|
'(auxclick)': 'onAuxClick($event)',
|
|
12781
12816
|
'(contextmenu)': 'onContextmenu($event)',
|
|
12817
|
+
'(mousedown)': 'onMouseDown($event)',
|
|
12782
12818
|
'(dragstart)': 'onDragStart($event)',
|
|
12783
12819
|
'(dragend)': 'onDragEnd()',
|
|
12784
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"] }]
|
|
@@ -17911,6 +17947,11 @@ class WorkbenchNotificationComponent {
|
|
|
17911
17947
|
this.notification.close();
|
|
17912
17948
|
}
|
|
17913
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
|
+
}
|
|
17914
17955
|
/**
|
|
17915
17956
|
* Closes this notification when pressing escape if it is the most recently displayed notification.
|
|
17916
17957
|
*/
|
|
@@ -17961,7 +18002,7 @@ class WorkbenchNotificationComponent {
|
|
|
17961
18002
|
}
|
|
17962
18003
|
}
|
|
17963
18004
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: WorkbenchNotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17964
|
-
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)", "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: [
|
|
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: [
|
|
17965
18006
|
configureNotificationGlassPane(),
|
|
17966
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" }] });
|
|
17967
18008
|
}
|
|
@@ -17989,6 +18030,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
|
|
|
17989
18030
|
'(mouseenter)': 'hover.set(true)',
|
|
17990
18031
|
'(mouseleave)': 'hover.set(false)',
|
|
17991
18032
|
'(auxclick)': 'onAuxClick($event)',
|
|
18033
|
+
'(mousedown)': 'onMouseDown($event)',
|
|
17992
18034
|
'(keydown.escape)': 'onEscape($event)',
|
|
17993
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"] }]
|
|
17994
18036
|
}], ctorParameters: () => [], propDecorators: { notificationSlotBounds: [{ type: i0.ViewChild, args: ['slot_bounds', { ...{ read: (ElementRef) }, isSignal: true }] }] } });
|