[ACA] Context menu - support nested sub menus (#715)

* remove ContextMenuItemDirective

* remove custom menu animation

* remove custom menu styling

* menu item component

* material menu trigger

* clean up menu theme

* update context menu module

* remoe context menu from libraries document list

* clean up

* clean up

* tests
This commit is contained in:
Cilibiu Bogdan
2018-10-14 13:27:47 +03:00
committed by Denys Vuika
parent 9dcdacce40
commit 4802656d79
16 changed files with 390 additions and 267 deletions

View File

@@ -1,68 +0,0 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import {
state,
style,
animate,
transition,
query,
group,
sequence
} from '@angular/animations';
export const contextMenuAnimation = [
state(
'void',
style({
opacity: 0,
transform: 'scale(0.01, 0.01)'
})
),
transition(
'void => *',
sequence([
query('.mat-menu-content', style({ opacity: 0 })),
animate(
'100ms linear',
style({ opacity: 1, transform: 'scale(1, 0.5)' })
),
group([
query(
'.mat-menu-content',
animate(
'400ms cubic-bezier(0.55, 0, 0.55, 0.2)',
style({ opacity: 1 })
)
),
animate(
'300ms cubic-bezier(0.25, 0.8, 0.25, 1)',
style({ transform: 'scale(1, 1)' })
)
])
])
),
transition('* => void', animate('150ms 50ms linear', style({ opacity: 0 })))
];

View File

@@ -0,0 +1,39 @@
<div class="aca-context-menu">
<ng-container [ngSwitch]="actionRef.type">
<ng-container *ngSwitchCase="'menu'">
<button
mat-menu-item
[id]="actionRef.id"
[matMenuTriggerFor]="childMenu">
<mat-icon color="primary">{{ actionRef.icon }}</mat-icon>
<span>{{ actionRef.title | translate }}</span>
</button>
<mat-menu #childMenu="matMenu">
<ng-container *ngFor="let child of actionRef.children; trackBy: trackById">
<app-context-menu-item [actionRef]="child"></app-context-menu-item>
</ng-container>
</mat-menu>
</ng-container>
<ng-container *ngSwitchCase="'separator'">
<mat-divider></mat-divider>
</ng-container>
<ng-container *ngSwitchCase="'custom'">
<adf-dynamic-component [id]="actionRef.component"></adf-dynamic-component>
</ng-container>
<ng-container *ngSwitchDefault>
<button mat-menu-item
color="primary"
[id]="actionRef.id"
(click)="runAction()">
<mat-icon color="primary">{{ actionRef.icon }}</mat-icon>
<span>{{ actionRef.title | translate }}</span>
</button>
</ng-container>
</ng-container>
</div>

View File

@@ -0,0 +1,107 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { AppTestingModule } from '../../testing/app-testing.module';
import { AppExtensionService } from '../../extensions/extension.service';
import { ContextMenuItemComponent } from './context-menu-item.component';
import { ContextMenuModule } from './context-menu.module';
import {
TranslateModule,
TranslateLoader,
TranslateFakeLoader
} from '@ngx-translate/core';
describe('ContextMenuComponent', () => {
let fixture: ComponentFixture<ContextMenuItemComponent>;
let component: ContextMenuItemComponent;
let extensionsService;
let contextItem;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
AppTestingModule,
ContextMenuModule,
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
})
],
providers: [AppExtensionService]
});
fixture = TestBed.createComponent(ContextMenuItemComponent);
component = fixture.componentInstance;
extensionsService = TestBed.get(AppExtensionService);
contextItem = <any>{
type: 'button',
id: 'action-button',
title: 'Test Button',
actions: {
click: 'TEST_EVENT'
}
};
});
afterEach(() => {
fixture.destroy();
});
it('should render defined menu actions items', () => {
component.actionRef = contextItem;
fixture.detectChanges();
const buttonElement = fixture.nativeElement.querySelector('button');
expect(buttonElement.innerText.trim()).toBe(contextItem.title);
});
it('should not run action when entry has no click attribute defined', () => {
spyOn(extensionsService, 'runActionById');
contextItem.actions = {};
component.actionRef = contextItem;
fixture.detectChanges();
fixture.nativeElement
.querySelector('#action-button')
.dispatchEvent(new MouseEvent('click'));
expect(extensionsService.runActionById).not.toHaveBeenCalled();
});
it('should run action with provided action id', () => {
spyOn(extensionsService, 'runActionById');
component.actionRef = contextItem;
fixture.detectChanges();
fixture.nativeElement
.querySelector('#action-button')
.dispatchEvent(new MouseEvent('click'));
expect(extensionsService.runActionById).toHaveBeenCalledWith(
contextItem.actions.click
);
});
});

View File

@@ -23,29 +23,36 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { Directive, ElementRef, OnDestroy } from '@angular/core'; import { Component, Input, ViewEncapsulation } from '@angular/core';
import { FocusableOption, FocusMonitor, FocusOrigin } from '@angular/cdk/a11y'; import { ContentActionRef } from '@alfresco/adf-extensions';
import { AppExtensionService } from '../../extensions/extension.service';
@Directive({ @Component({
selector: '[acaContextMenuItem]' selector: 'app-context-menu-item',
templateUrl: 'context-menu-item.component.html',
encapsulation: ViewEncapsulation.None,
host: { class: 'app-context-menu-item' }
}) })
export class ContextMenuItemDirective implements OnDestroy, FocusableOption { export class ContextMenuItemComponent {
constructor( @Input()
private elementRef: ElementRef, actionRef: ContentActionRef;
private focusMonitor: FocusMonitor
) { constructor(private extensions: AppExtensionService) {}
focusMonitor.monitor(this.getHostElement(), false);
runAction() {
if (this.hasClickAction(this.actionRef)) {
this.extensions.runActionById(this.actionRef.actions.click);
}
} }
ngOnDestroy() { private hasClickAction(actionRef: ContentActionRef): boolean {
this.focusMonitor.stopMonitoring(this.getHostElement()); if (actionRef && actionRef.actions && actionRef.actions.click) {
return true;
}
return false;
} }
focus(origin: FocusOrigin = 'keyboard'): void { trackById(index: number, obj: { id: string }) {
this.focusMonitor.focusVia(this.getHostElement(), origin); return obj.id;
}
private getHostElement(): HTMLElement {
return this.elementRef.nativeElement;
} }
} }

View File

@@ -1,32 +0,0 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { ContextMenuItemDirective } from './context-menu-item.directive';
describe('ContextMenuItemDirective', () => {
it('should be defined', () => {
expect(ContextMenuItemDirective).toBeDefined();
});
});

View File

@@ -1,48 +1,41 @@
<div mat-menu class="mat-menu-panel" <button style="visibility: hidden" [matMenuTriggerFor]="rootMenu" #rootTriggerEl></button>
@panelAnimation
<mat-menu #rootMenu="matMenu"
class="aca-context-menu"
hasBackdrop="false"
acaContextMenuOutsideEvent acaContextMenuOutsideEvent
(clickOutside)="onClickOutsideEvent()"> (clickOutside)="onClickOutsideEvent()">
<ng-container *ngFor="let entry of actions" [ngSwitch]="entry.type">
<div class="mat-menu-content"> <ng-container *ngSwitchDefault>
<ng-container *ngFor="let entry of actions" [ngSwitch]="entry.type"> <button mat-menu-item
<ng-container *ngSwitchCase="'default'"> [id]="entry.id"
<button mat-menu-item (click)="runAction(entry.actions.click)">
[id]="entry.id" <mat-icon color="primary">{{ entry.icon }}</mat-icon>
acaContextMenuItem <span>{{ entry.title | translate }}</span>
(click)="runAction(entry.actions.click)"> </button>
<mat-icon color="primary">{{ entry.icon }}</mat-icon>
<span>{{ entry.title | translate }}</span>
</button>
</ng-container>
<ng-container *ngSwitchCase="'button'">
<button mat-menu-item
[id]="entry.id"
acaContextMenuItem
(click)="runAction(entry.actions.click)">
<mat-icon color="primary">{{ entry.icon }}</mat-icon>
<span>{{ entry.title | translate }}</span>
</button>
</ng-container>
<span *ngSwitchCase="'separator'"
class="aca-context-menu__separator"
[id]="entry.id">
</span>
<ng-container *ngSwitchCase="'menu'">
<button mat-menu-item
acaContextMenuItem
[id]="entry.id"
class="aca-context-menu__more-actions">
<mat-icon color="primary">{{ entry.icon }}</mat-icon>
<span>{{ entry.title | translate }}</span>
</button>
</ng-container>
<ng-container *ngSwitchCase="'custom'">
<adf-dynamic-component [id]="entry.component"></adf-dynamic-component>
</ng-container>
</ng-container> </ng-container>
</div>
</div> <ng-container *ngSwitchCase="'separator'">
<mat-divider></mat-divider>
</ng-container>
<ng-container *ngSwitchCase="'menu'">
<button mat-menu-item
[id]="entry.id"
[matMenuTriggerFor]="childMenu">
<mat-icon color="primary">{{ entry.icon }}</mat-icon>
<span>{{ entry.title | translate }}</span>
</button>
<mat-menu #childMenu="matMenu">
<ng-container *ngFor="let child of entry.children; trackBy: trackById">
<app-context-menu-item [actionRef]="child"></app-context-menu-item>
</ng-container>
</mat-menu>
</ng-container>
<ng-container *ngSwitchCase="'custom'">
<adf-dynamic-component [id]="entry.component"></adf-dynamic-component>
</ng-container>
</ng-container>
</mat-menu>

View File

@@ -1,19 +0,0 @@
.aca-context-menu {
&__more-actions::after {
margin-left: 34px;
width: 0;
height: 0;
border-style: solid;
border-width: 5px 0 5px 5px;
content: '';
display: inline-block;
}
&__separator {
display: block;
margin: 0;
padding: 0;
border-top-width: 1px;
border-top-style: solid;
}
}

View File

@@ -23,10 +23,104 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
import {
TestBed,
ComponentFixture,
fakeAsync,
tick
} from '@angular/core/testing';
import { AppTestingModule } from '../../testing/app-testing.module';
import { AppExtensionService } from '../../extensions/extension.service';
import { ContextMenuComponent } from './context-menu.component'; import { ContextMenuComponent } from './context-menu.component';
import { ContextMenuModule } from './context-menu.module';
import { ContextMenuOverlayRef } from './context-menu-overlay';
import {
TranslateModule,
TranslateLoader,
TranslateFakeLoader
} from '@ngx-translate/core';
import { of } from 'rxjs';
import { Store } from '@ngrx/store';
describe('ContextMenuComponent', () => { describe('ContextMenuComponent', () => {
it('should be defined', () => { let fixture: ComponentFixture<ContextMenuComponent>;
expect(ContextMenuComponent).toBeDefined(); let component: ContextMenuComponent;
let contextMenuOverlayRef;
let extensionsService;
const contextItem = {
type: 'button',
id: 'action-button',
title: 'Test Button',
actions: {
click: 'TEST_EVENT'
}
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
AppTestingModule,
ContextMenuModule,
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
})
],
providers: [
AppExtensionService,
{
provide: ContextMenuOverlayRef,
useValue: {
close: jasmine.createSpy('close')
}
},
{
provide: Store,
useValue: {
dispatch: () => {},
select: () => of({ count: 1 })
}
}
]
});
fixture = TestBed.createComponent(ContextMenuComponent);
component = fixture.componentInstance;
contextMenuOverlayRef = TestBed.get(ContextMenuOverlayRef);
extensionsService = TestBed.get(AppExtensionService);
spyOn(extensionsService, 'getAllowedContextMenuActions').and.returnValue([
contextItem
]);
fixture.detectChanges();
}); });
it('should close context menu on Escape event', () => {
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
expect(contextMenuOverlayRef.close).toHaveBeenCalled();
});
it('should render defined context menu actions items', fakeAsync(() => {
component.ngAfterViewInit();
tick(500);
const contextMenuElements = document.body
.querySelector('.aca-context-menu')
.querySelectorAll('button');
expect(contextMenuElements.length).toBe(1);
expect(contextMenuElements[0].innerText).toBe(contextItem.title);
}));
it('should run action with provided action id', fakeAsync(() => {
spyOn(extensionsService, 'runActionById');
component.runAction(contextItem.actions.click);
expect(extensionsService.runActionById).toHaveBeenCalledWith(
contextItem.actions.click
);
}));
}); });

View File

@@ -4,14 +4,5 @@
.aca-context-menu { .aca-context-menu {
@include angular-material-theme($theme); @include angular-material-theme($theme);
&__separator {
border-top-color: mat-color($foreground, divider);
}
&__more-actions::after {
border-color: transparent;
border-left-color: mat-color($primary);
}
} }
} }

View File

@@ -29,13 +29,10 @@ import {
OnInit, OnInit,
OnDestroy, OnDestroy,
HostListener, HostListener,
ViewChildren, ViewChild,
QueryList,
AfterViewInit AfterViewInit
} from '@angular/core'; } from '@angular/core';
import { trigger } from '@angular/animations'; import { MatMenuTrigger } from '@angular/material';
import { FocusKeyManager } from '@angular/cdk/a11y';
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
import { AppExtensionService } from '../../extensions/extension.service'; import { AppExtensionService } from '../../extensions/extension.service';
import { AppStore } from '../../store/states'; import { AppStore } from '../../store/states';
@@ -44,42 +41,23 @@ import { Store } from '@ngrx/store';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { ContentActionRef } from '@alfresco/adf-extensions'; import { ContentActionRef } from '@alfresco/adf-extensions';
import { ContextMenuOverlayRef } from './context-menu-overlay'; import { ContextMenuOverlayRef } from './context-menu-overlay';
import { contextMenuAnimation } from './animations';
import { ContextMenuItemDirective } from './context-menu-item.directive';
@Component({ @Component({
selector: 'aca-context-menu', selector: 'aca-context-menu',
templateUrl: './context-menu.component.html', templateUrl: './context-menu.component.html',
styleUrls: [ styleUrls: ['./context-menu.component.theme.scss'],
'./context-menu.component.scss',
'./context-menu.component.theme.scss'
],
host: { host: {
role: 'menu', class: 'aca-context-menu-holder'
class: 'aca-context-menu'
}, },
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None
animations: [trigger('panelAnimation', contextMenuAnimation)]
}) })
export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit { export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
private onDestroy$: Subject<boolean> = new Subject<boolean>(); private onDestroy$: Subject<boolean> = new Subject<boolean>();
private _keyManager: FocusKeyManager<ContextMenuItemDirective>;
actions: Array<ContentActionRef> = []; actions: Array<ContentActionRef> = [];
@ViewChildren(ContextMenuItemDirective) @ViewChild(MatMenuTrigger)
private contextMenuItems: QueryList<ContextMenuItemDirective>; trigger: MatMenuTrigger;
@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) {
@@ -90,16 +68,6 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
} }
} }
@HostListener('document:keydown', ['$event'])
handleKeydownEvent(event: KeyboardEvent) {
if (event) {
const keyCode = event.keyCode;
if (keyCode === UP_ARROW || keyCode === DOWN_ARROW) {
this._keyManager.onKeydown(event);
}
}
}
constructor( constructor(
private contextMenuOverlayRef: ContextMenuOverlayRef, private contextMenuOverlayRef: ContextMenuOverlayRef,
private extensions: AppExtensionService, private extensions: AppExtensionService,
@@ -114,7 +82,6 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
runAction(actionId: string) { runAction(actionId: string) {
this.extensions.runActionById(actionId); this.extensions.runActionById(actionId);
this.contextMenuOverlayRef.close();
} }
ngOnDestroy() { ngOnDestroy() {
@@ -134,9 +101,6 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
} }
ngAfterViewInit() { ngAfterViewInit() {
this._keyManager = new FocusKeyManager<ContextMenuItemDirective>( setTimeout(() => this.trigger.openMenu(), 0);
this.contextMenuItems
);
this._keyManager.setFirstItemActive();
} }
} }

View File

@@ -43,14 +43,6 @@ export class ContextActionsDirective {
@Input('acaContextEnable') @Input('acaContextEnable')
enabled = true; enabled = true;
@HostListener('window:resize', ['$event'])
onResize(event) {
if (event && this.overlayRef) {
this.clearSelection();
this.overlayRef.close();
}
}
@HostListener('contextmenu', ['$event']) @HostListener('contextmenu', ['$event'])
onContextMenuEvent(event: MouseEvent) { onContextMenuEvent(event: MouseEvent) {
if (event) { if (event) {
@@ -69,6 +61,7 @@ export class ContextActionsDirective {
) {} ) {}
private execute(event: MouseEvent) { private execute(event: MouseEvent) {
// todo: review this in ADF
const selected = this.getSelectedRow(event); const selected = this.getSelectedRow(event);
if (selected) { if (selected) {

View File

@@ -26,7 +26,37 @@
import { ContextActionsDirective } from './context-menu.directive'; import { ContextActionsDirective } from './context-menu.directive';
describe('ContextActionsDirective', () => { describe('ContextActionsDirective', () => {
it('should be defined', () => { let directive;
expect(ContextActionsDirective).toBeDefined(); const contextMenuServiceMock = <any>{
open: jasmine.createSpy('open')
};
const storeMock = <any>{};
const documentListMock = <any>{};
beforeEach(() => {
directive = new ContextActionsDirective(
documentListMock,
storeMock,
contextMenuServiceMock
);
});
it('should not render context menu when disable 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);
directive.onContextMenuEvent(new MouseEvent('contextmenu'));
expect(contextMenuServiceMock.open).toHaveBeenCalled();
}); });
}); });

View File

@@ -35,9 +35,9 @@ import { CoreExtensionsModule } from '../../extensions/core.extensions.module';
import { ContextActionsDirective } from './context-menu.directive'; import { ContextActionsDirective } from './context-menu.directive';
import { ContextMenuComponent } from './context-menu.component'; import { ContextMenuComponent } from './context-menu.component';
import { ContextMenuItemDirective } from './context-menu-item.directive';
import { ExtensionsModule } from '@alfresco/adf-extensions'; import { ExtensionsModule } from '@alfresco/adf-extensions';
import { OutsideEventDirective } from './context-menu-outside-event.directive'; import { OutsideEventDirective } from './context-menu-outside-event.directive';
import { ContextMenuItemComponent } from './context-menu-item.component';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -52,13 +52,14 @@ import { OutsideEventDirective } from './context-menu-outside-event.directive';
declarations: [ declarations: [
ContextActionsDirective, ContextActionsDirective,
ContextMenuComponent, ContextMenuComponent,
ContextMenuItemDirective, ContextMenuItemComponent,
OutsideEventDirective OutsideEventDirective
], ],
exports: [ exports: [
OutsideEventDirective, OutsideEventDirective,
ContextActionsDirective, ContextActionsDirective,
ContextMenuComponent ContextMenuComponent,
ContextMenuItemComponent
], ],
entryComponents: [ContextMenuComponent] entryComponents: [ContextMenuComponent]
}) })

View File

@@ -23,10 +23,48 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { TestBed } from '@angular/core/testing';
import { Overlay } from '@angular/cdk/overlay';
import { Injector } from '@angular/core';
import { Store } from '@ngrx/store';
import { of } from 'rxjs';
import { AppConfigService } from '@alfresco/adf-core';
import { ContextMenuService } from './context-menu.service'; import { ContextMenuService } from './context-menu.service';
import { ContextMenuModule } from './context-menu.module';
describe('ContextMenuService', () => { describe('ContextMenuService', () => {
it('should be defined', () => { let contextMenuService;
expect(ContextMenuService).toBeDefined(); const overlayConfig = {
hasBackdrop: false,
backdropClass: '',
panelClass: 'test-panel'
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ContextMenuModule],
providers: [
Overlay,
{ provide: Store, useValue: { select: () => of() } },
{ provide: AppConfigService, useValue: {} }
]
});
const injector = TestBed.get(Injector);
const overlay = TestBed.get(Overlay);
contextMenuService = new ContextMenuService(injector, overlay);
});
it('should create a custom overlay', () => {
contextMenuService.open(overlayConfig);
expect(document.querySelector('.test-panel')).not.toBe(null);
});
it('should render component', () => {
contextMenuService.open(overlayConfig);
expect(document.querySelector('aca-context-menu')).not.toBe(null);
}); });
}); });

View File

@@ -18,20 +18,6 @@ export class ContextMenuService {
this.attachDialogContainer(overlay, config, overlayRef); this.attachDialogContainer(overlay, config, overlayRef);
overlay.backdropClick().subscribe(() => overlayRef.close());
// prevent native contextmenu on overlay element if config.hasBackdrop is true
if (config.hasBackdrop) {
(<any>overlay)._backdropElement.addEventListener(
'contextmenu',
() => {
event.preventDefault();
(<any>overlay)._backdropClick.next(null);
},
true
);
}
return overlayRef; return overlayRef;
} }

View File

@@ -18,7 +18,6 @@
<div class="inner-layout__panel"> <div class="inner-layout__panel">
<adf-document-list #documentList <adf-document-list #documentList
acaDocumentList acaDocumentList
acaContextActions
[display]="documentDisplayMode$ | async" [display]="documentDisplayMode$ | async"
currentFolderId="-mysites-" currentFolderId="-mysites-"
selectionMode="single" selectionMode="single"