UI: Improve edit widget toolbar.
This commit is contained in:
parent
e84447d28e
commit
9bd923a878
@ -48,15 +48,16 @@
|
|||||||
[stateController]="dashboardCtx.stateController"
|
[stateController]="dashboardCtx.stateController"
|
||||||
[dashboardTimewindow]="dashboardCtx.dashboardTimewindow"
|
[dashboardTimewindow]="dashboardCtx.dashboardTimewindow"
|
||||||
[isEdit]="isEdit"
|
[isEdit]="isEdit"
|
||||||
|
[isEditingWidget]="isEditingWidget"
|
||||||
[autofillHeight]="autoFillHeight"
|
[autofillHeight]="autoFillHeight"
|
||||||
[mobileAutofillHeight]="mobileAutoFillHeight"
|
[mobileAutofillHeight]="mobileAutoFillHeight"
|
||||||
[mobileRowHeight]="layoutCtx.gridSettings.mobileRowHeight"
|
[mobileRowHeight]="layoutCtx.gridSettings.mobileRowHeight"
|
||||||
[isMobile]="isMobile"
|
[isMobile]="isMobile"
|
||||||
[isMobileDisabled]="isMobileDisabled"
|
[isMobileDisabled]="isMobileDisabled"
|
||||||
[disableWidgetInteraction]="isEdit"
|
[disableWidgetInteraction]="isEdit"
|
||||||
[isEditActionEnabled]="isEdit"
|
[isEditActionEnabled]="isEdit && !isEditingWidget"
|
||||||
[isExportActionEnabled]="isEdit && !widgetEditMode"
|
[isExportActionEnabled]="isEdit && !widgetEditMode && !isEditingWidget"
|
||||||
[isRemoveActionEnabled]="isEdit && !widgetEditMode"
|
[isRemoveActionEnabled]="isEdit && !widgetEditMode && !isEditingWidget"
|
||||||
[callbacks]="this"
|
[callbacks]="this"
|
||||||
[ignoreLoading]="layoutCtx.ignoreLoading"
|
[ignoreLoading]="layoutCtx.ignoreLoading"
|
||||||
[parentDashboard]="parentDashboard"
|
[parentDashboard]="parentDashboard"
|
||||||
|
|||||||
@ -73,6 +73,7 @@
|
|||||||
[dashboardStyle]="dashboardStyle"
|
[dashboardStyle]="dashboardStyle"
|
||||||
[backgroundImage]="backgroundImage"
|
[backgroundImage]="backgroundImage"
|
||||||
[isEdit]="isEdit"
|
[isEdit]="isEdit"
|
||||||
|
[isEditingWidget]="isEditingWidget"
|
||||||
[isPreview]="isPreview"
|
[isPreview]="isPreview"
|
||||||
[isMobile]="isMobileSize"
|
[isMobile]="isMobileSize"
|
||||||
[isEditActionEnabled]="isEditActionEnabled"
|
[isEditActionEnabled]="isEditActionEnabled"
|
||||||
|
|||||||
@ -117,6 +117,9 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
|||||||
@Input()
|
@Input()
|
||||||
isEdit: boolean;
|
isEdit: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isEditingWidget: boolean;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
isPreview: boolean;
|
isPreview: boolean;
|
||||||
|
|
||||||
@ -248,8 +251,8 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
|||||||
defaultItemCols: 8,
|
defaultItemCols: 8,
|
||||||
defaultItemRows: 6,
|
defaultItemRows: 6,
|
||||||
displayGrid: this.displayGrid,
|
displayGrid: this.displayGrid,
|
||||||
resizable: {enabled: this.isEdit},
|
resizable: {enabled: this.isEdit && !this.isEditingWidget, delayStart: 50},
|
||||||
draggable: {enabled: this.isEdit},
|
draggable: {enabled: this.isEdit && !this.isEditingWidget},
|
||||||
itemChangeCallback: item => this.dashboardWidgets.sortWidgets(),
|
itemChangeCallback: item => this.dashboardWidgets.sortWidgets(),
|
||||||
itemInitCallback: (item, itemComponent) => {
|
itemInitCallback: (item, itemComponent) => {
|
||||||
(itemComponent.item as DashboardWidget).gridsterItemComponent = itemComponent;
|
(itemComponent.item as DashboardWidget).gridsterItemComponent = itemComponent;
|
||||||
@ -300,7 +303,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
|||||||
updateMobileOpts = true;
|
updateMobileOpts = true;
|
||||||
} else if (['outerMargin', 'margin', 'columns'].includes(propName)) {
|
} else if (['outerMargin', 'margin', 'columns'].includes(propName)) {
|
||||||
updateLayoutOpts = true;
|
updateLayoutOpts = true;
|
||||||
} else if (propName === 'isEdit') {
|
} else if (['isEdit', 'isEditingWidget'].includes(propName)) {
|
||||||
updateEditingOpts = true;
|
updateEditingOpts = true;
|
||||||
} else if (['widgets', 'widgetLayouts'].includes(propName)) {
|
} else if (['widgets', 'widgetLayouts'].includes(propName)) {
|
||||||
updateWidgets = true;
|
updateWidgets = true;
|
||||||
@ -580,8 +583,8 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateEditingOpts() {
|
private updateEditingOpts() {
|
||||||
this.gridsterOpts.resizable.enabled = this.isEdit;
|
this.gridsterOpts.resizable.enabled = this.isEdit && !this.isEditingWidget;
|
||||||
this.gridsterOpts.draggable.enabled = this.isEdit;
|
this.gridsterOpts.draggable.enabled = this.isEdit && !this.isEditingWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
public notifyGridsterOptionsChanged() {
|
public notifyGridsterOptionsChanged() {
|
||||||
|
|||||||
@ -124,7 +124,10 @@ import { EdgeDownlinkTableHeaderComponent } from '@home/components/edge/edge-dow
|
|||||||
import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-page/widget-types-panel.component';
|
import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-page/widget-types-panel.component';
|
||||||
import { AlarmDurationPredicateValueComponent } from '@home/components/profile/alarm/alarm-duration-predicate-value.component';
|
import { AlarmDurationPredicateValueComponent } from '@home/components/profile/alarm/alarm-duration-predicate-value.component';
|
||||||
import { DashboardImageDialogComponent } from '@home/components/dashboard-page/dashboard-image-dialog.component';
|
import { DashboardImageDialogComponent } from '@home/components/dashboard-page/dashboard-image-dialog.component';
|
||||||
import { WidgetContainerComponent } from '@home/components/widget/widget-container.component';
|
import {
|
||||||
|
EditWidgetActionsTooltipComponent,
|
||||||
|
WidgetContainerComponent
|
||||||
|
} from '@home/components/widget/widget-container.component';
|
||||||
import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snmp/snmp-device-profile-transport.module';
|
import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snmp/snmp-device-profile-transport.module';
|
||||||
import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module';
|
import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module';
|
||||||
import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module';
|
import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module';
|
||||||
@ -207,6 +210,7 @@ import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delet
|
|||||||
EntityAliasDialogComponent,
|
EntityAliasDialogComponent,
|
||||||
DashboardComponent,
|
DashboardComponent,
|
||||||
WidgetContainerComponent,
|
WidgetContainerComponent,
|
||||||
|
EditWidgetActionsTooltipComponent,
|
||||||
WidgetComponent,
|
WidgetComponent,
|
||||||
WidgetConfigComponent,
|
WidgetConfigComponent,
|
||||||
WidgetPreviewComponent,
|
WidgetPreviewComponent,
|
||||||
@ -345,6 +349,7 @@ import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delet
|
|||||||
EntityAliasDialogComponent,
|
EntityAliasDialogComponent,
|
||||||
DashboardComponent,
|
DashboardComponent,
|
||||||
WidgetContainerComponent,
|
WidgetContainerComponent,
|
||||||
|
EditWidgetActionsTooltipComponent,
|
||||||
WidgetComponent,
|
WidgetComponent,
|
||||||
WidgetConfigComponent,
|
WidgetConfigComponent,
|
||||||
WidgetPreviewComponent,
|
WidgetPreviewComponent,
|
||||||
|
|||||||
@ -26,12 +26,10 @@
|
|||||||
'mat-elevation-z4': widget.dropShadow,
|
'mat-elevation-z4': widget.dropShadow,
|
||||||
'tb-overflow-visible': widgetComponent.widgetContext?.overflowVisible,
|
'tb-overflow-visible': widgetComponent.widgetContext?.overflowVisible,
|
||||||
'tb-has-timewindow': widget.hasTimewindow,
|
'tb-has-timewindow': widget.hasTimewindow,
|
||||||
'tb-edit': isEdit
|
'tb-edit': isEdit || isEditingWidget,
|
||||||
|
'tb-hover': hovered
|
||||||
}"
|
}"
|
||||||
[ngStyle]="widget.style"
|
[ngStyle]="widget.style">
|
||||||
(mousedown)="onMouseDown($event)"
|
|
||||||
(click)="onClicked($event)"
|
|
||||||
(contextmenu)="onContextMenu($event)">
|
|
||||||
<div *ngIf="!!widgetComponent.widgetContext?.inited"
|
<div *ngIf="!!widgetComponent.widgetContext?.inited"
|
||||||
class="tb-widget-header">
|
class="tb-widget-header">
|
||||||
<ng-container *ngIf="!widgetComponent.widgetContext?.embedTitlePanel">
|
<ng-container *ngIf="!widgetComponent.widgetContext?.embedTitlePanel">
|
||||||
@ -57,32 +55,11 @@
|
|||||||
</button>
|
</button>
|
||||||
<button mat-icon-button
|
<button mat-icon-button
|
||||||
[fxShow]="!isEdit && widget.enableFullscreen"
|
[fxShow]="!isEdit && widget.enableFullscreen"
|
||||||
(click)="$event.stopPropagation(); widget.isFullscreen = !widget.isFullscreen"
|
(click)="$event.stopPropagation(); widget.isFullscreen = !widget.isFullscreen; updateEditWidgetActionsTooltipState()"
|
||||||
matTooltip="{{(widget.isFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
matTooltip="{{(widget.isFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
||||||
matTooltipPosition="above">
|
matTooltipPosition="above">
|
||||||
<tb-icon>{{ widget.isFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</tb-icon>
|
<tb-icon>{{ widget.isFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</tb-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button
|
|
||||||
[fxShow]="isEditActionEnabled && !widget.isFullscreen"
|
|
||||||
(click)="onEdit($event)"
|
|
||||||
matTooltip="{{ 'widget.edit' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<tb-icon>edit</tb-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button
|
|
||||||
[fxShow]="isExportActionEnabled && !widget.isFullscreen"
|
|
||||||
(click)="onExport($event)"
|
|
||||||
matTooltip="{{ 'widget.export' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<tb-icon>file_download</tb-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button
|
|
||||||
[fxShow]="isRemoveActionEnabled && !widget.isFullscreen"
|
|
||||||
(click)="onRemove($event);"
|
|
||||||
matTooltip="{{ 'widget.remove' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<tb-icon>close</tb-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-widget-content" [ngClass]="{'tb-no-interaction': disableWidgetInteraction}">
|
<div class="tb-widget-content" [ngClass]="{'tb-no-interaction': disableWidgetInteraction}">
|
||||||
|
|||||||
@ -102,6 +102,12 @@ div.tb-widget {
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
&.mat-mdc-button-base {
|
||||||
|
.mat-mdc-button-touch-target {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mat-icon {
|
.mat-icon {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
@ -141,7 +147,69 @@ div.tb-widget {
|
|||||||
opacity: .5;
|
opacity: .5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.tb-hover {
|
||||||
|
&:not(.tb-highlighted) {
|
||||||
|
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.tb-edit {
|
&.tb-edit {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gridster-item:hover {
|
||||||
|
.tb-widget-container {
|
||||||
|
div.tb-widget {
|
||||||
|
&.tb-edit {
|
||||||
|
&:not(.tb-highlighted) {
|
||||||
|
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltipster-sidetip.tb-widget-edit-actions-tooltip {
|
||||||
|
.tooltipster-box {
|
||||||
|
user-select: none;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.38);
|
||||||
|
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
|
||||||
|
.tooltipster-content {
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(0, 0, 0, 0.76);
|
||||||
|
.tb-widget-actions-panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
place-content: center flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tooltipster-arrow {
|
||||||
|
.tooltipster-arrow-uncropped {
|
||||||
|
.tooltipster-arrow-background {
|
||||||
|
border-width: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.tooltipster-top {
|
||||||
|
.tooltipster-arrow {
|
||||||
|
bottom: -1px;
|
||||||
|
.tooltipster-arrow-uncropped {
|
||||||
|
.tooltipster-arrow-border {
|
||||||
|
border-top-color: rgba(0, 0, 0, 0.38);
|
||||||
|
}
|
||||||
|
.tooltipster-arrow-background {
|
||||||
|
border-top-color: #fff;
|
||||||
|
left: -2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -22,12 +22,12 @@ import {
|
|||||||
ElementRef,
|
ElementRef,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
HostBinding,
|
HostBinding,
|
||||||
Input,
|
Input, OnChanges,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
Output,
|
Output,
|
||||||
Renderer2,
|
Renderer2, SimpleChanges,
|
||||||
ViewChild,
|
ViewChild, ViewContainerRef,
|
||||||
ViewEncapsulation
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { PageComponent } from '@shared/components/page.component';
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
@ -38,6 +38,8 @@ import { SafeStyle } from '@angular/platform-browser';
|
|||||||
import { isNotEmptyStr } from '@core/utils';
|
import { isNotEmptyStr } from '@core/utils';
|
||||||
import { GridsterItemComponent } from 'angular-gridster2';
|
import { GridsterItemComponent } from 'angular-gridster2';
|
||||||
import { UtilsService } from '@core/services/utils.service';
|
import { UtilsService } from '@core/services/utils.service';
|
||||||
|
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
|
||||||
|
import { from } from 'rxjs';
|
||||||
|
|
||||||
export enum WidgetComponentActionType {
|
export enum WidgetComponentActionType {
|
||||||
MOUSE_DOWN,
|
MOUSE_DOWN,
|
||||||
@ -61,7 +63,7 @@ export class WidgetComponentAction {
|
|||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class WidgetContainerComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy {
|
export class WidgetContainerComponent extends PageComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
@HostBinding('class')
|
@HostBinding('class')
|
||||||
widgetContainerClass = 'tb-widget-container';
|
widgetContainerClass = 'tb-widget-container';
|
||||||
@ -84,6 +86,9 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, A
|
|||||||
@Input()
|
@Input()
|
||||||
isEdit: boolean;
|
isEdit: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isEditingWidget: boolean;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
isPreview: boolean;
|
isPreview: boolean;
|
||||||
|
|
||||||
@ -111,11 +116,20 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, A
|
|||||||
@Output()
|
@Output()
|
||||||
widgetComponentAction: EventEmitter<WidgetComponentAction> = new EventEmitter<WidgetComponentAction>();
|
widgetComponentAction: EventEmitter<WidgetComponentAction> = new EventEmitter<WidgetComponentAction>();
|
||||||
|
|
||||||
|
hovered = false;
|
||||||
|
|
||||||
|
get widgetEditActionsEnabled(): boolean {
|
||||||
|
return (this.isEditActionEnabled || this.isRemoveActionEnabled || this.isExportActionEnabled) && !this.widget?.isFullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
private cssClass: string;
|
private cssClass: string;
|
||||||
|
|
||||||
|
private editWidgetActionsTooltip: ITooltipsterInstance;
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
private renderer: Renderer2,
|
private renderer: Renderer2,
|
||||||
|
private container: ViewContainerRef,
|
||||||
private utils: UtilsService) {
|
private utils: UtilsService) {
|
||||||
super(store);
|
super(store);
|
||||||
}
|
}
|
||||||
@ -127,16 +141,34 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, A
|
|||||||
this.cssClass =
|
this.cssClass =
|
||||||
this.utils.applyCssToElement(this.renderer, this.gridsterItem.el, 'tb-widget-css', cssString);
|
this.utils.applyCssToElement(this.renderer, this.gridsterItem.el, 'tb-widget-css', cssString);
|
||||||
}
|
}
|
||||||
|
$(this.gridsterItem.el).on('mousedown', (e) => this.onMouseDown(e.originalEvent));
|
||||||
|
$(this.gridsterItem.el).on('click', (e) => this.onClicked(e.originalEvent));
|
||||||
|
$(this.gridsterItem.el).on('contextmenu', (e) => this.onContextMenu(e.originalEvent));
|
||||||
|
this.initEditWidgetActionTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
this.widget.widgetContext.$widgetElement = $(this.tbWidgetElement.nativeElement);
|
this.widget.widgetContext.$widgetElement = $(this.tbWidgetElement.nativeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
for (const propName of Object.keys(changes)) {
|
||||||
|
const change = changes[propName];
|
||||||
|
if (!change.firstChange && change.currentValue !== change.previousValue) {
|
||||||
|
if (['isEditActionEnabled', 'isRemoveActionEnabled', 'isExportActionEnabled'].includes(propName)) {
|
||||||
|
this.updateEditWidgetActionsTooltipState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.cssClass) {
|
if (this.cssClass) {
|
||||||
this.utils.clearCssElement(this.renderer, this.cssClass);
|
this.utils.clearCssElement(this.renderer, this.cssClass);
|
||||||
}
|
}
|
||||||
|
if (this.editWidgetActionsTooltip) {
|
||||||
|
this.editWidgetActionsTooltip.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isHighlighted(widget: DashboardWidget) {
|
isHighlighted(widget: DashboardWidget) {
|
||||||
@ -198,4 +230,141 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, A
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateEditWidgetActionsTooltipState() {
|
||||||
|
if (this.editWidgetActionsTooltip) {
|
||||||
|
if (this.widgetEditActionsEnabled) {
|
||||||
|
this.editWidgetActionsTooltip.enable();
|
||||||
|
} else {
|
||||||
|
this.editWidgetActionsTooltip.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private initEditWidgetActionTooltip() {
|
||||||
|
from(import('tooltipster')).subscribe(() => {
|
||||||
|
$(this.gridsterItem.el).tooltipster({
|
||||||
|
delay: this.widget.selected ? [0, 10000000] : [0, 100],
|
||||||
|
distance: 2,
|
||||||
|
zIndex: 151,
|
||||||
|
arrow: false,
|
||||||
|
theme: ['tb-widget-edit-actions-tooltip'],
|
||||||
|
interactive: true,
|
||||||
|
trigger: 'custom',
|
||||||
|
triggerOpen: {
|
||||||
|
mouseenter: true
|
||||||
|
},
|
||||||
|
triggerClose: {
|
||||||
|
mouseleave: true
|
||||||
|
},
|
||||||
|
side: ['top'],
|
||||||
|
trackOrigin: true,
|
||||||
|
trackerInterval: 25,
|
||||||
|
content: '',
|
||||||
|
functionPosition: (instance, helper, position) => {
|
||||||
|
const clientRect = helper.origin.getBoundingClientRect();
|
||||||
|
position.coord.left = clientRect.right - position.size.width;
|
||||||
|
position.target = clientRect.right;
|
||||||
|
return position;
|
||||||
|
},
|
||||||
|
functionReady: (_instance, helper) => {
|
||||||
|
const tooltipEl = $(helper.tooltip);
|
||||||
|
tooltipEl.on('mouseenter', () => {
|
||||||
|
this.hovered = true;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
tooltipEl.on('mouseleave', () => {
|
||||||
|
this.hovered = false;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
functionAfter: () => {
|
||||||
|
this.hovered = false;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.editWidgetActionsTooltip = $(this.gridsterItem.el).tooltipster('instance');
|
||||||
|
const componentRef = this.container.createComponent(EditWidgetActionsTooltipComponent);
|
||||||
|
componentRef.instance.container = this;
|
||||||
|
componentRef.instance.viewInited.subscribe(() => {
|
||||||
|
if (this.editWidgetActionsTooltip.status().open) {
|
||||||
|
this.editWidgetActionsTooltip.reposition();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.editWidgetActionsTooltip.on('destroyed', () => {
|
||||||
|
componentRef.destroy();
|
||||||
|
});
|
||||||
|
const parentElement = componentRef.instance.element.nativeElement;
|
||||||
|
const content = parentElement.firstChild;
|
||||||
|
parentElement.removeChild(content);
|
||||||
|
parentElement.style.display = 'none';
|
||||||
|
this.editWidgetActionsTooltip.content(content);
|
||||||
|
this.updateEditWidgetActionsTooltipState();
|
||||||
|
this.widget.onSelected((selected) =>
|
||||||
|
this.updateEditWidgetActionsTooltipSelectedState(selected));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateEditWidgetActionsTooltipSelectedState(selected: boolean) {
|
||||||
|
if (this.editWidgetActionsTooltip) {
|
||||||
|
if (selected) {
|
||||||
|
this.editWidgetActionsTooltip.option('delay', [0, 10000000]);
|
||||||
|
this.editWidgetActionsTooltip.option('triggerClose', {
|
||||||
|
mouseleave: false
|
||||||
|
});
|
||||||
|
if (this.widgetEditActionsEnabled) {
|
||||||
|
this.editWidgetActionsTooltip.open();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.editWidgetActionsTooltip.option('delay', [0, 100]);
|
||||||
|
this.editWidgetActionsTooltip.option('triggerClose', {
|
||||||
|
mouseleave: true
|
||||||
|
});
|
||||||
|
this.editWidgetActionsTooltip.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: `<div class="tb-widget-actions-panel">
|
||||||
|
<button mat-icon-button class="tb-mat-20"
|
||||||
|
[fxShow]="container.isEditActionEnabled"
|
||||||
|
(click)="container.onEdit($event)"
|
||||||
|
matTooltip="{{ 'widget.edit' | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<tb-icon>edit</tb-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button class="tb-mat-20"
|
||||||
|
[fxShow]="container.isExportActionEnabled"
|
||||||
|
(click)="container.onExport($event)"
|
||||||
|
matTooltip="{{ 'widget.export' | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<tb-icon>file_download</tb-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button class="tb-mat-20"
|
||||||
|
[fxShow]="container.isRemoveActionEnabled"
|
||||||
|
(click)="container.onRemove($event);"
|
||||||
|
matTooltip="{{ 'widget.remove' | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<tb-icon>close</tb-icon>
|
||||||
|
</button>
|
||||||
|
</div>`,
|
||||||
|
styles: [],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class EditWidgetActionsTooltipComponent implements AfterViewInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
container: WidgetContainerComponent;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
viewInited = new EventEmitter();
|
||||||
|
|
||||||
|
constructor(public element: ElementRef<HTMLElement>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.viewInited.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -240,11 +240,20 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
|
|||||||
highlightWidget(widgetId: string): DashboardWidget {
|
highlightWidget(widgetId: string): DashboardWidget {
|
||||||
const widget = this.findWidgetById(widgetId);
|
const widget = this.findWidgetById(widgetId);
|
||||||
if (widget && (!this.highlightedMode || !widget.highlighted || this.highlightedMode && widget.highlighted)) {
|
if (widget && (!this.highlightedMode || !widget.highlighted || this.highlightedMode && widget.highlighted)) {
|
||||||
this.highlightedMode = true;
|
let detectChanges = false;
|
||||||
|
if (!this.highlightedMode) {
|
||||||
|
this.highlightedMode = true;
|
||||||
|
detectChanges = true;
|
||||||
|
}
|
||||||
widget.highlighted = true;
|
widget.highlighted = true;
|
||||||
|
widget.selected = false;
|
||||||
this.dashboardWidgets.forEach((dashboardWidget) => {
|
this.dashboardWidgets.forEach((dashboardWidget) => {
|
||||||
if (dashboardWidget !== widget) {
|
if (dashboardWidget !== widget) {
|
||||||
dashboardWidget.highlighted = false;
|
dashboardWidget.highlighted = false;
|
||||||
|
dashboardWidget.selected = false;
|
||||||
|
if (detectChanges) {
|
||||||
|
dashboardWidget.widgetContext?.detectContainerChanges();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return widget;
|
return widget;
|
||||||
@ -330,6 +339,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
|||||||
|
|
||||||
private highlightedValue = false;
|
private highlightedValue = false;
|
||||||
private selectedValue = false;
|
private selectedValue = false;
|
||||||
|
private selectedCallback: (selected: boolean) => void = () => {};
|
||||||
|
|
||||||
isFullscreen = false;
|
isFullscreen = false;
|
||||||
|
|
||||||
@ -399,6 +409,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSelected(selectedCallback: (selected: boolean) => void) {
|
||||||
|
this.selectedCallback = selectedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
get selected() {
|
get selected() {
|
||||||
return this.selectedValue;
|
return this.selectedValue;
|
||||||
}
|
}
|
||||||
@ -406,6 +420,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
|
|||||||
set selected(selected: boolean) {
|
set selected(selected: boolean) {
|
||||||
if (this.selectedValue !== selected) {
|
if (this.selectedValue !== selected) {
|
||||||
this.selectedValue = selected;
|
this.selectedValue = selected;
|
||||||
|
this.selectedCallback(selected);
|
||||||
this.widgetContext.detectContainerChanges();
|
this.widgetContext.detectContainerChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user