mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-19 17:14:45 +00:00
[ACA-1696] contextmenu (#587)
* enbale contextmenu by default * attach event only when backdrop is set * outside event for contextmenu * apply outside event directive * workaround fro contextmenu event row selection * remove Output parameter * update dockerfile * update docker compose file
This commit is contained in:
parent
5759ea1b62
commit
091e0d3e3f
@ -1,4 +1,4 @@
|
|||||||
FROM nginx:alpine
|
FROM nginx:stable-alpine
|
||||||
LABEL version="1.3"
|
LABEL version="1.3"
|
||||||
LABEL maintainer="Denys Vuika <denys.vuika@alfresco.com>"
|
LABEL maintainer="Denys Vuika <denys.vuika@alfresco.com>"
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ services:
|
|||||||
# - ./nginx.conf:/etc/nginx/conf.d/default.conf
|
# - ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
image: nginx
|
image: nginx:stable-alpine
|
||||||
depends_on:
|
depends_on:
|
||||||
- content-app
|
- content-app
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
import { Directive, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { fromEvent, Subscription } from 'rxjs';
|
||||||
|
import { delay } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[acaContextMenuOutsideEvent]'
|
||||||
|
})
|
||||||
|
|
||||||
|
export class OutsideEventDirective implements OnInit, OnDestroy {
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
@Output() clickOutside: EventEmitter<null> = new EventEmitter();
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.subscriptions = this.subscriptions.concat([
|
||||||
|
fromEvent(document, 'click')
|
||||||
|
.pipe(delay(1))
|
||||||
|
.subscribe(() => this.clickOutside.next())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||||
|
this.subscriptions = [];
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,8 @@
|
|||||||
<div mat-menu class="mat-menu-panel" @panelAnimation>
|
<div mat-menu class="mat-menu-panel"
|
||||||
|
@panelAnimation
|
||||||
|
acaContextMenuOutsideEvent
|
||||||
|
(clickOutside)="onClickOutsideEvent()">
|
||||||
|
|
||||||
<div class="mat-menu-content">
|
<div class="mat-menu-content">
|
||||||
<ng-container *ngFor="let entry of actions" [ngSwitch]="entry.type">
|
<ng-container *ngFor="let entry of actions" [ngSwitch]="entry.type">
|
||||||
<ng-container *ngSwitchCase="'default'">
|
<ng-container *ngSwitchCase="'default'">
|
||||||
|
@ -68,12 +68,24 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
@ViewChildren(ContextMenuItemDirective)
|
@ViewChildren(ContextMenuItemDirective)
|
||||||
private contextMenuItems: QueryList<ContextMenuItemDirective>;
|
private contextMenuItems: QueryList<ContextMenuItemDirective>;
|
||||||
|
|
||||||
|
@HostListener('contextmenu', ['$event'])
|
||||||
|
handleContextMenu(event: MouseEvent) {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (this.contextMenuOverlayRef) {
|
||||||
|
this.contextMenuOverlayRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('document:keydown.Escape', ['$event'])
|
@HostListener('document:keydown.Escape', ['$event'])
|
||||||
handleKeydownEscape(event: KeyboardEvent) {
|
handleKeydownEscape(event: KeyboardEvent) {
|
||||||
if (event) {
|
if (event) {
|
||||||
|
if (this.contextMenuOverlayRef) {
|
||||||
this.contextMenuOverlayRef.close();
|
this.contextMenuOverlayRef.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('document:keydown', ['$event'])
|
@HostListener('document:keydown', ['$event'])
|
||||||
handleKeydownEvent(event: KeyboardEvent) {
|
handleKeydownEvent(event: KeyboardEvent) {
|
||||||
@ -91,6 +103,12 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
onClickOutsideEvent() {
|
||||||
|
if (this.contextMenuOverlayRef) {
|
||||||
|
this.contextMenuOverlayRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runAction(actionId: string) {
|
runAction(actionId: string) {
|
||||||
const context = {
|
const context = {
|
||||||
selection: this.selection
|
selection: this.selection
|
||||||
|
@ -26,6 +26,12 @@
|
|||||||
import { Directive, HostListener, Input } from '@angular/core';
|
import { Directive, HostListener, Input } from '@angular/core';
|
||||||
import { ContextMenuOverlayRef } from './context-menu-overlay';
|
import { ContextMenuOverlayRef } from './context-menu-overlay';
|
||||||
import { ContextMenuService } from './context-menu.service';
|
import { ContextMenuService } from './context-menu.service';
|
||||||
|
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||||
|
import { SetSelectedNodesAction } from '../../store/actions';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppStore } from '../../store/states/app.state';
|
||||||
|
import { DataRow } from '@alfresco/adf-core';
|
||||||
|
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[acaContextActions]'
|
selector: '[acaContextActions]'
|
||||||
@ -34,11 +40,12 @@ export class ContextActionsDirective {
|
|||||||
private overlayRef: ContextMenuOverlayRef = null;
|
private overlayRef: ContextMenuOverlayRef = null;
|
||||||
|
|
||||||
// tslint:disable-next-line:no-input-rename
|
// tslint:disable-next-line:no-input-rename
|
||||||
@Input('acaContextEnable') enabled: boolean;
|
@Input('acaContextEnable') enabled = true;
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
onResize(event) {
|
onResize(event) {
|
||||||
if (event && this.overlayRef) {
|
if (event && this.overlayRef) {
|
||||||
|
this.clearSelection();
|
||||||
this.overlayRef.close();
|
this.overlayRef.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,19 +56,84 @@ export class ContextActionsDirective {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (this.enabled) {
|
if (this.enabled) {
|
||||||
|
this.execute(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private documentList: DocumentListComponent,
|
||||||
|
private store: Store<AppStore>,
|
||||||
|
private contextMenuService: ContextMenuService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
private execute(event: MouseEvent) {
|
||||||
|
const selected = this.getSelectedRow();
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
if (!this.isInSelection(selected)) {
|
||||||
|
this.clearSelection();
|
||||||
|
|
||||||
|
this.documentList.dataTable.selectRow(selected, true);
|
||||||
|
this.documentList.selection.push((<any>selected).node);
|
||||||
|
|
||||||
|
this.updateSelection();
|
||||||
|
}
|
||||||
|
|
||||||
this.render(event);
|
this.render(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
constructor(private contextMenuService: ContextMenuService) { }
|
|
||||||
|
|
||||||
private render(event: MouseEvent) {
|
private render(event: MouseEvent) {
|
||||||
|
if (this.overlayRef) {
|
||||||
|
this.overlayRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
this.overlayRef = this.contextMenuService.open({
|
this.overlayRef = this.contextMenuService.open({
|
||||||
source: event,
|
source: event,
|
||||||
hasBackdrop: true,
|
hasBackdrop: false,
|
||||||
backdropClass: 'cdk-overlay-transparent-backdrop',
|
backdropClass: 'cdk-overlay-transparent-backdrop',
|
||||||
panelClass: 'cdk-overlay-pane',
|
panelClass: 'cdk-overlay-pane',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateSelection() {
|
||||||
|
this.store.dispatch(
|
||||||
|
new SetSelectedNodesAction(this.documentList.selection)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isInSelection(row: DataRow): MinimalNodeEntity {
|
||||||
|
return this.documentList.selection.find((selected) =>
|
||||||
|
row.getValue('name') === selected.entry.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSelectedRow(): DataRow {
|
||||||
|
const rowElement = this.findAncestor(<HTMLElement>event.target, 'adf-datatable-row');
|
||||||
|
|
||||||
|
if (!rowElement) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowName = rowElement.querySelector('.adf-data-table-cell--text .adf-datatable-cell')
|
||||||
|
.textContent
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
return this.documentList.data.getRows()
|
||||||
|
.find((row: DataRow) => row.getValue('name') === rowName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearSelection() {
|
||||||
|
this.documentList.data.getRows().map((row: DataRow) => {
|
||||||
|
return this.documentList.dataTable.selectRow(row, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.documentList.selection = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private findAncestor (el: Element, className: string): Element {
|
||||||
|
// tslint:disable-next-line:curly
|
||||||
|
while ((el = el.parentElement) && !el.classList.contains(className));
|
||||||
|
return el;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import { ContextActionsDirective } from './context-menu.directive';
|
|||||||
import { ContextMenuService } from './context-menu.service';
|
import { ContextMenuService } from './context-menu.service';
|
||||||
import { ContextMenuComponent } from './context-menu.component';
|
import { ContextMenuComponent } from './context-menu.component';
|
||||||
import { ContextMenuItemDirective } from './context-menu-item.directive';
|
import { ContextMenuItemDirective } from './context-menu-item.directive';
|
||||||
|
import { OutsideEventDirective } from './context-menu-outside-event.directive';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -47,9 +48,11 @@ import { ContextMenuItemDirective } from './context-menu-item.directive';
|
|||||||
declarations: [
|
declarations: [
|
||||||
ContextActionsDirective,
|
ContextActionsDirective,
|
||||||
ContextMenuComponent,
|
ContextMenuComponent,
|
||||||
ContextMenuItemDirective
|
ContextMenuItemDirective,
|
||||||
|
OutsideEventDirective
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
|
OutsideEventDirective,
|
||||||
ContextActionsDirective,
|
ContextActionsDirective,
|
||||||
ContextMenuComponent
|
ContextMenuComponent
|
||||||
],
|
],
|
||||||
|
@ -22,11 +22,13 @@ export class ContextMenuService {
|
|||||||
overlay.backdropClick().subscribe(() => overlayRef.close());
|
overlay.backdropClick().subscribe(() => overlayRef.close());
|
||||||
|
|
||||||
// prevent native contextmenu on overlay element if config.hasBackdrop is true
|
// prevent native contextmenu on overlay element if config.hasBackdrop is true
|
||||||
|
if (config.hasBackdrop) {
|
||||||
(<any>overlay)._backdropElement
|
(<any>overlay)._backdropElement
|
||||||
.addEventListener('contextmenu', () => {
|
.addEventListener('contextmenu', () => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
(<any>overlay)._backdropClick.next(null);
|
(<any>overlay)._backdropClick.next(null);
|
||||||
}, true);
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
return overlayRef;
|
return overlayRef;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
<adf-document-list #documentList
|
<adf-document-list #documentList
|
||||||
acaDocumentList
|
acaDocumentList
|
||||||
acaContextActions
|
acaContextActions
|
||||||
[acaContextEnable]="selection.count"
|
|
||||||
[display]="documentDisplayMode$ | async"
|
[display]="documentDisplayMode$ | async"
|
||||||
currentFolderId="-favorites-"
|
currentFolderId="-favorites-"
|
||||||
selectionMode="multiple"
|
selectionMode="multiple"
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
<adf-document-list #documentList
|
<adf-document-list #documentList
|
||||||
acaDocumentList
|
acaDocumentList
|
||||||
acaContextActions
|
acaContextActions
|
||||||
[acaContextEnable]="selection.count"
|
|
||||||
[display]="documentDisplayMode$ | async"
|
[display]="documentDisplayMode$ | async"
|
||||||
[sorting]="[ 'modifiedAt', 'desc' ]"
|
[sorting]="[ 'modifiedAt', 'desc' ]"
|
||||||
selectionMode="multiple"
|
selectionMode="multiple"
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
<adf-document-list #documentList
|
<adf-document-list #documentList
|
||||||
acaDocumentList
|
acaDocumentList
|
||||||
acaContextActions
|
acaContextActions
|
||||||
[acaContextEnable]="selection.count"
|
|
||||||
[display]="documentDisplayMode$ | async"
|
[display]="documentDisplayMode$ | async"
|
||||||
currentFolderId="-mysites-"
|
currentFolderId="-mysites-"
|
||||||
selectionMode="single"
|
selectionMode="single"
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
<adf-document-list #documentList
|
<adf-document-list #documentList
|
||||||
acaDocumentList
|
acaDocumentList
|
||||||
acaContextActions
|
acaContextActions
|
||||||
[acaContextEnable]="selection.count"
|
|
||||||
[display]="documentDisplayMode$ | async"
|
[display]="documentDisplayMode$ | async"
|
||||||
currentFolderId="-recent-"
|
currentFolderId="-recent-"
|
||||||
selectionMode="multiple"
|
selectionMode="multiple"
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
<adf-document-list #documentList
|
<adf-document-list #documentList
|
||||||
acaDocumentList
|
acaDocumentList
|
||||||
acaContextActions
|
acaContextActions
|
||||||
[acaContextEnable]="selection.count"
|
|
||||||
[display]="documentDisplayMode$ | async"
|
[display]="documentDisplayMode$ | async"
|
||||||
currentFolderId="-sharedlinks-"
|
currentFolderId="-sharedlinks-"
|
||||||
selectionMode="multiple"
|
selectionMode="multiple"
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
<adf-document-list #documentList
|
<adf-document-list #documentList
|
||||||
acaDocumentList
|
acaDocumentList
|
||||||
acaContextActions
|
acaContextActions
|
||||||
[acaContextEnable]="selection.count"
|
|
||||||
[display]="documentDisplayMode$ | async"
|
[display]="documentDisplayMode$ | async"
|
||||||
currentFolderId="-trashcan-"
|
currentFolderId="-trashcan-"
|
||||||
selectionMode="multiple"
|
selectionMode="multiple"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user