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
} from '@angular/core';
import { fromEvent, Subscription } from 'rxjs';
import { delay } from 'rxjs/operators';
import { filter } from 'rxjs/operators';
@Directive({
selector: '[acaContextMenuOutsideEvent]'
@ -22,7 +22,7 @@ export class OutsideEventDirective implements OnInit, OnDestroy {
ngOnInit() {
this.subscriptions = this.subscriptions.concat([
fromEvent(document.body, 'click')
.pipe(delay(1))
.pipe(filter(event => !this.findAncestor(event.target as Element)))
.subscribe(() => this.clickOutside.next())
]);
}
@ -31,4 +31,15 @@ export class OutsideEventDirective implements OnInit, OnDestroy {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
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/>.
*/
import { Directive, HostListener, Input } from '@angular/core';
import {
Directive,
HostListener,
Input,
OnInit,
OnDestroy
} from '@angular/core';
import { ContextMenuOverlayRef } from './context-menu-overlay';
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';
import { debounceTime } from 'rxjs/operators';
import { Subject, fromEvent, Subscription } from 'rxjs';
@Directive({
selector: '[acaContextActions]'
})
export class ContextActionsDirective {
export class ContextActionsDirective implements OnInit, OnDestroy {
private execute$: Subject<any> = new Subject();
private subscriptions: Subscription[] = [];
private overlayRef: ContextMenuOverlayRef = null;
// tslint:disable-next-line:no-input-rename
@ -49,40 +53,44 @@ export class ContextActionsDirective {
event.preventDefault();
if (this.enabled) {
this.execute(event);
const target = this.getTarget(event);
if (target) {
this.execute(event, target);
}
}
}
}
constructor(
private documentList: DocumentListComponent,
private store: Store<AppStore>,
private contextMenuService: ContextMenuService
) {}
constructor(private contextMenuService: ContextMenuService) {}
private execute(event: MouseEvent) {
// todo: review this in ADF
const selected = this.getSelectedRow(event);
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);
}
}
private render(event: MouseEvent) {
ngOnInit() {
this.subscriptions.push(
fromEvent(document.body, 'contextmenu').subscribe(() => {
if (this.overlayRef) {
this.overlayRef.close();
}
}),
this.execute$.pipe(debounceTime(300)).subscribe((event: MouseEvent) => {
this.render(event);
})
);
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
this.subscriptions = [];
this.execute$ = null;
}
execute(event: MouseEvent, target: Element) {
if (!this.isSelected(target)) {
target.dispatchEvent(new MouseEvent('click'));
}
this.execute$.next(event);
}
private render(event: MouseEvent) {
this.overlayRef = this.contextMenuService.open({
source: event,
hasBackdrop: false,
@ -91,46 +99,24 @@ export class ContextActionsDirective {
});
}
private updateSelection() {
this.store.dispatch(
new SetSelectedNodesAction(this.documentList.selection)
private getTarget(event: MouseEvent): Element {
return this.findAncestor(<Element>event.target, 'adf-datatable-table-cell');
}
private isSelected(target): boolean {
if (!target) {
return false;
}
return this.findAncestor(target, 'adf-datatable-row').classList.contains(
'is-selected'
);
}
private isInSelection(row: DataRow): MinimalNodeEntity {
return this.documentList.selection.find(
selected => row.getValue('name') === selected.entry.name
);
}
private getSelectedRow(event): 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 {
if (el.classList.contains(className)) {
return el;
}
// tslint:disable-next-line:curly
while ((el = el.parentElement) && !el.classList.contains(className));
return el;

View File

@ -24,39 +24,40 @@
*/
import { ContextActionsDirective } from './context-menu.directive';
import { fakeAsync, tick } from '@angular/core/testing';
describe('ContextActionsDirective', () => {
let directive;
const contextMenuServiceMock = <any>{
open: jasmine.createSpy('open')
};
const storeMock = <any>{};
const documentListMock = <any>{};
beforeEach(() => {
directive = new ContextActionsDirective(
documentListMock,
storeMock,
contextMenuServiceMock
);
directive = new ContextActionsDirective(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;
spyOn(directive, 'getSelectedRow').and.returnValue({});
directive.onContextMenuEvent(new MouseEvent('contextmenu'));
expect(contextMenuServiceMock.open).not.toHaveBeenCalled();
});
it('should render context menu when disable property is true', () => {
directive.enabled = true;
spyOn(directive, 'getSelectedRow').and.returnValue({});
spyOn(directive, 'isInSelection').and.returnValue(true);
it('should call service to render context menu', fakeAsync(() => {
const el = document.createElement('div');
el.className =
'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();
});
}));
});