Context menu - library files fix (#815)

This commit is contained in:
Cilibiu Bogdan 2018-11-21 18:01:59 +02:00 committed by Denys Vuika
parent 94f2762940
commit 43b55102be
3 changed files with 79 additions and 81 deletions

View File

@ -6,7 +6,7 @@ import {
OnDestroy OnDestroy
} from '@angular/core'; } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs'; import { fromEvent, Subscription } from 'rxjs';
import { delay } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
@Directive({ @Directive({
selector: '[acaContextMenuOutsideEvent]' selector: '[acaContextMenuOutsideEvent]'
@ -22,7 +22,7 @@ export class OutsideEventDirective implements OnInit, OnDestroy {
ngOnInit() { ngOnInit() {
this.subscriptions = this.subscriptions.concat([ this.subscriptions = this.subscriptions.concat([
fromEvent(document.body, 'click') fromEvent(document.body, 'click')
.pipe(delay(1)) .pipe(filter(event => !this.findAncestor(event.target as Element)))
.subscribe(() => this.clickOutside.next()) .subscribe(() => this.clickOutside.next())
]); ]);
} }
@ -31,4 +31,15 @@ export class OutsideEventDirective implements OnInit, OnDestroy {
this.subscriptions.forEach(subscription => subscription.unsubscribe()); this.subscriptions.forEach(subscription => subscription.unsubscribe());
this.subscriptions = []; this.subscriptions = [];
} }
private findAncestor(el: Element): boolean {
const className = 'aca-context-menu';
if (el.classList.contains(className)) {
return true;
}
// tslint:disable-next-line:curly
while ((el = el.parentElement) && !el.classList.contains(className));
return !!el;
}
} }

View File

@ -23,20 +23,24 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { Directive, HostListener, Input } from '@angular/core'; import {
Directive,
HostListener,
Input,
OnInit,
OnDestroy
} 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 { debounceTime } from 'rxjs/operators';
import { SetSelectedNodesAction } from '../../store/actions'; import { Subject, fromEvent, Subscription } from 'rxjs';
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]'
}) })
export class ContextActionsDirective { export class ContextActionsDirective implements OnInit, OnDestroy {
private execute$: Subject<any> = new Subject();
private subscriptions: Subscription[] = [];
private overlayRef: ContextMenuOverlayRef = null; private overlayRef: ContextMenuOverlayRef = null;
// tslint:disable-next-line:no-input-rename // tslint:disable-next-line:no-input-rename
@ -49,40 +53,44 @@ export class ContextActionsDirective {
event.preventDefault(); event.preventDefault();
if (this.enabled) { if (this.enabled) {
this.execute(event); const target = this.getTarget(event);
if (target) {
this.execute(event, target);
}
} }
} }
} }
constructor( constructor(private contextMenuService: ContextMenuService) {}
private documentList: DocumentListComponent,
private store: Store<AppStore>,
private contextMenuService: ContextMenuService
) {}
private execute(event: MouseEvent) { ngOnInit() {
// todo: review this in ADF this.subscriptions.push(
const selected = this.getSelectedRow(event); fromEvent(document.body, 'contextmenu').subscribe(() => {
if (this.overlayRef) {
this.overlayRef.close();
}
}),
if (selected) { this.execute$.pipe(debounceTime(300)).subscribe((event: MouseEvent) => {
if (!this.isInSelection(selected)) { this.render(event);
this.clearSelection(); })
);
}
this.documentList.dataTable.selectRow(selected, true); ngOnDestroy() {
this.documentList.selection.push((<any>selected).node); this.subscriptions.forEach(subscription => subscription.unsubscribe());
this.subscriptions = [];
this.execute$ = null;
}
this.updateSelection(); execute(event: MouseEvent, target: Element) {
} if (!this.isSelected(target)) {
target.dispatchEvent(new MouseEvent('click'));
this.render(event);
} }
this.execute$.next(event);
} }
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: false, hasBackdrop: false,
@ -91,46 +99,24 @@ export class ContextActionsDirective {
}); });
} }
private updateSelection() { private getTarget(event: MouseEvent): Element {
this.store.dispatch( return this.findAncestor(<Element>event.target, 'adf-datatable-table-cell');
new SetSelectedNodesAction(this.documentList.selection)
);
} }
private isInSelection(row: DataRow): MinimalNodeEntity { private isSelected(target): boolean {
return this.documentList.selection.find( if (!target) {
selected => row.getValue('name') === selected.entry.name return false;
);
}
private getSelectedRow(event): DataRow {
const rowElement = this.findAncestor(
<HTMLElement>event.target,
'adf-datatable-row'
);
if (!rowElement) {
return null;
} }
const rowName = rowElement return this.findAncestor(target, 'adf-datatable-row').classList.contains(
.querySelector('.adf-data-table-cell--text .adf-datatable-cell') 'is-selected'
.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 { private findAncestor(el: Element, className: string): Element {
if (el.classList.contains(className)) {
return el;
}
// tslint:disable-next-line:curly // tslint:disable-next-line:curly
while ((el = el.parentElement) && !el.classList.contains(className)); while ((el = el.parentElement) && !el.classList.contains(className));
return el; return el;

View File

@ -24,39 +24,40 @@
*/ */
import { ContextActionsDirective } from './context-menu.directive'; import { ContextActionsDirective } from './context-menu.directive';
import { fakeAsync, tick } from '@angular/core/testing';
describe('ContextActionsDirective', () => { describe('ContextActionsDirective', () => {
let directive; let directive;
const contextMenuServiceMock = <any>{ const contextMenuServiceMock = <any>{
open: jasmine.createSpy('open') open: jasmine.createSpy('open')
}; };
const storeMock = <any>{};
const documentListMock = <any>{};
beforeEach(() => { beforeEach(() => {
directive = new ContextActionsDirective( directive = new ContextActionsDirective(contextMenuServiceMock);
documentListMock,
storeMock,
contextMenuServiceMock
);
}); });
it('should not render context menu when disable property is false', () => { it('should not render context menu when `enabled` property is false', () => {
directive.enabled = false; directive.enabled = false;
spyOn(directive, 'getSelectedRow').and.returnValue({});
directive.onContextMenuEvent(new MouseEvent('contextmenu')); directive.onContextMenuEvent(new MouseEvent('contextmenu'));
expect(contextMenuServiceMock.open).not.toHaveBeenCalled(); expect(contextMenuServiceMock.open).not.toHaveBeenCalled();
}); });
it('should render context menu when disable property is true', () => { it('should call service to render context menu', fakeAsync(() => {
directive.enabled = true; const el = document.createElement('div');
spyOn(directive, 'getSelectedRow').and.returnValue({}); el.className =
spyOn(directive, 'isInSelection').and.returnValue(true); 'adf-data-table-cell adf-datatable-table-cell adf-datatable-row';
directive.onContextMenuEvent(new MouseEvent('contextmenu')); const fragment = document.createDocumentFragment();
fragment.appendChild(el);
const target = fragment.querySelector('div');
directive.ngOnInit();
directive.onContextMenuEvent(<any>{ preventDefault: () => {}, target });
tick(500);
expect(contextMenuServiceMock.open).toHaveBeenCalled(); expect(contextMenuServiceMock.open).toHaveBeenCalled();
}); }));
}); });