mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-3456] DocumentList - context menu (#3694)
* refactor context menu * prune log * remove fdescribe * remove undescore from private * fix e2e action buttons * fix trailing space * remove fdescribe
This commit is contained in:
committed by
Eugenio Romano
parent
62f0804205
commit
4404b724fa
46
lib/core/context-menu/animations.ts
Normal file
46
lib/core/context-menu/animations.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
state,
|
||||
style,
|
||||
animate,
|
||||
transition,
|
||||
query,
|
||||
group,
|
||||
sequence,
|
||||
AnimationStateMetadata,
|
||||
AnimationTransitionMetadata
|
||||
} from '@angular/animations';
|
||||
|
||||
export const contextMenuAnimation: ( AnimationStateMetadata | AnimationTransitionMetadata)[] = [
|
||||
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 })))
|
||||
];
|
101
lib/core/context-menu/context-menu-list.component.ts
Normal file
101
lib/core/context-menu/context-menu-list.component.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component, ViewEncapsulation, HostListener, AfterViewInit,
|
||||
Optional, Inject, QueryList, ViewChildren
|
||||
} from '@angular/core';
|
||||
import { trigger } from '@angular/animations';
|
||||
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
|
||||
import { FocusKeyManager } from '@angular/cdk/a11y';
|
||||
import { MatMenuItem } from '@angular/material';
|
||||
import { ContextMenuOverlayRef } from './context-menu-overlay';
|
||||
import { contextMenuAnimation } from './animations';
|
||||
import { CONTEXT_MENU_DATA } from './context-menu.tokens';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-context-menu',
|
||||
template: `
|
||||
<div mat-menu class="mat-menu-panel" @panelAnimation>
|
||||
<div id="adf-context-menu-content" class="mat-menu-content">
|
||||
<ng-container *ngFor="let link of links">
|
||||
<button *ngIf="link.model?.visible"
|
||||
[attr.data-automation-id]="'context-'+((link.title || link.model?.title) | translate)"
|
||||
mat-menu-item
|
||||
[disabled]="link.model?.disabled"
|
||||
(click)="onMenuItemClick($event, link)">
|
||||
<mat-icon *ngIf="link.model?.icon">{{ link.model.icon }}</mat-icon>
|
||||
<span>{{ (link.title || link.model?.title) | translate }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
host: {
|
||||
role: 'menu',
|
||||
class: 'adf-context-menu'
|
||||
},
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations: [
|
||||
trigger('panelAnimation', contextMenuAnimation)
|
||||
]
|
||||
})
|
||||
export class ContextMenuListComponent implements AfterViewInit {
|
||||
private keyManager: FocusKeyManager<MatMenuItem>;
|
||||
@ViewChildren(MatMenuItem) items: QueryList<MatMenuItem>;
|
||||
links: any[];
|
||||
|
||||
@HostListener('document:keydown.Escape', ['$event'])
|
||||
handleKeydownEscape(event: KeyboardEvent) {
|
||||
if (event) {
|
||||
this.contextMenuOverlayRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
@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(
|
||||
@Inject(ContextMenuOverlayRef) private contextMenuOverlayRef: ContextMenuOverlayRef,
|
||||
@Optional() @Inject(CONTEXT_MENU_DATA) private data: any
|
||||
) {
|
||||
this.links = this.data;
|
||||
}
|
||||
|
||||
onMenuItemClick(event: Event, menuItem: any) {
|
||||
if (menuItem && menuItem.model && menuItem.model.disabled) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
menuItem.subject.next(menuItem);
|
||||
this.contextMenuOverlayRef.close();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.keyManager = new FocusKeyManager<MatMenuItem>(this.items);
|
||||
this.keyManager.setFirstItemActive();
|
||||
}
|
||||
}
|
129
lib/core/context-menu/context-menu-overlay.service.ts
Normal file
129
lib/core/context-menu/context-menu-overlay.service.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Injectable, Injector, ElementRef, ComponentRef } from '@angular/core';
|
||||
import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
|
||||
import { PortalInjector, ComponentPortal } from '@angular/cdk/portal';
|
||||
import { ContextMenuOverlayRef } from './context-menu-overlay';
|
||||
import { ContextMenuOverlayConfig } from './interfaces';
|
||||
import { CONTEXT_MENU_DATA } from './context-menu.tokens';
|
||||
import { ContextMenuListComponent } from './context-menu-list.component';
|
||||
|
||||
const DEFAULT_CONFIG: ContextMenuOverlayConfig = {
|
||||
panelClass: 'cdk-overlay-pane',
|
||||
backdropClass: 'cdk-overlay-transparent-backdrop',
|
||||
hasBackdrop: true
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class ContextMenuOverlayService {
|
||||
|
||||
constructor( private injector: Injector, private overlay: Overlay) { }
|
||||
|
||||
open(config: ContextMenuOverlayConfig): ContextMenuOverlayRef {
|
||||
const overlayConfig = { ...DEFAULT_CONFIG, ...config };
|
||||
|
||||
const overlay = this.createOverlay(overlayConfig);
|
||||
|
||||
const overlayRef = new ContextMenuOverlayRef(overlay);
|
||||
|
||||
this.attachDialogContainer(overlay, config, overlayRef);
|
||||
|
||||
overlay.backdropClick().subscribe(() => overlayRef.close());
|
||||
|
||||
// prevent native contextmenu on overlay element if config.hasBackdrop is true
|
||||
if (overlayConfig.hasBackdrop) {
|
||||
(<any> overlay)._backdropElement
|
||||
.addEventListener('contextmenu', (event) => {
|
||||
event.preventDefault();
|
||||
(<any> overlay)._backdropClick.next(null);
|
||||
}, true);
|
||||
}
|
||||
|
||||
return overlayRef;
|
||||
}
|
||||
|
||||
private createOverlay(config: ContextMenuOverlayConfig): OverlayRef {
|
||||
const overlayConfig = this.getOverlayConfig(config);
|
||||
return this.overlay.create(overlayConfig);
|
||||
}
|
||||
|
||||
private attachDialogContainer(overlay: OverlayRef, config: ContextMenuOverlayConfig, contextMenuOverlayRef: ContextMenuOverlayRef) {
|
||||
const injector = this.createInjector(config, contextMenuOverlayRef);
|
||||
|
||||
const containerPortal = new ComponentPortal(ContextMenuListComponent, null, injector);
|
||||
const containerRef: ComponentRef<ContextMenuListComponent> = overlay.attach(containerPortal);
|
||||
|
||||
return containerRef.instance;
|
||||
}
|
||||
|
||||
private createInjector(config: ContextMenuOverlayConfig, contextMenuOverlayRef: ContextMenuOverlayRef): PortalInjector {
|
||||
const injectionTokens = new WeakMap();
|
||||
|
||||
injectionTokens.set(ContextMenuOverlayRef, contextMenuOverlayRef);
|
||||
injectionTokens.set(CONTEXT_MENU_DATA, config.data);
|
||||
|
||||
return new PortalInjector(this.injector, injectionTokens);
|
||||
}
|
||||
|
||||
private getOverlayConfig(config: ContextMenuOverlayConfig): OverlayConfig {
|
||||
const { clientY, clientX } = config.source;
|
||||
|
||||
const fakeElement: any = {
|
||||
getBoundingClientRect: (): ClientRect => ({
|
||||
bottom: clientY,
|
||||
height: 0,
|
||||
left: clientX,
|
||||
right: clientX,
|
||||
top: clientY,
|
||||
width: 0
|
||||
})
|
||||
};
|
||||
|
||||
const positionStrategy = this.overlay.position()
|
||||
.connectedTo(
|
||||
new ElementRef(fakeElement),
|
||||
{ originX: 'start', originY: 'bottom' },
|
||||
{ overlayX: 'start', overlayY: 'top' })
|
||||
.withFallbackPosition(
|
||||
{ originX: 'start', originY: 'top' },
|
||||
{ overlayX: 'start', overlayY: 'bottom' })
|
||||
.withFallbackPosition(
|
||||
{ originX: 'end', originY: 'top' },
|
||||
{ overlayX: 'start', overlayY: 'top' })
|
||||
.withFallbackPosition(
|
||||
{ originX: 'start', originY: 'top' },
|
||||
{ overlayX: 'end', overlayY: 'top' })
|
||||
.withFallbackPosition(
|
||||
{ originX: 'end', originY: 'center' },
|
||||
{ overlayX: 'start', overlayY: 'center' })
|
||||
.withFallbackPosition(
|
||||
{ originX: 'start', originY: 'center' },
|
||||
{ overlayX: 'end', overlayY: 'center' }
|
||||
);
|
||||
|
||||
const overlayConfig = new OverlayConfig({
|
||||
hasBackdrop: config.hasBackdrop,
|
||||
backdropClass: config.backdropClass,
|
||||
panelClass: config.panelClass,
|
||||
scrollStrategy: this.overlay.scrollStrategies.close(),
|
||||
positionStrategy
|
||||
});
|
||||
|
||||
return overlayConfig;
|
||||
}
|
||||
}
|
27
lib/core/context-menu/context-menu-overlay.ts
Normal file
27
lib/core/context-menu/context-menu-overlay.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { OverlayRef } from '@angular/cdk/overlay';
|
||||
|
||||
export class ContextMenuOverlayRef {
|
||||
|
||||
constructor(private overlayRef: OverlayRef) { }
|
||||
|
||||
close(): void {
|
||||
this.overlayRef.dispose();
|
||||
}
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContextMenuDirective } from './context-menu.directive';
|
||||
import { ContextMenuService } from './context-menu.service';
|
||||
|
||||
describe('ContextMenuDirective', () => {
|
||||
|
||||
let contextMenuService;
|
||||
let directive;
|
||||
|
||||
beforeEach(() => {
|
||||
contextMenuService = new ContextMenuService();
|
||||
directive = new ContextMenuDirective(contextMenuService);
|
||||
directive.enabled = true;
|
||||
});
|
||||
|
||||
it('should show menu via service', (done) => {
|
||||
contextMenuService.show.subscribe(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
directive.links = [{}];
|
||||
directive.onShowContextMenu(null);
|
||||
});
|
||||
|
||||
it('should prevent default behavior', () => {
|
||||
let event = new MouseEvent('click');
|
||||
spyOn(event, 'preventDefault').and.callThrough();
|
||||
|
||||
directive.onShowContextMenu(event);
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward event to service', () => {
|
||||
let event = new MouseEvent('click');
|
||||
|
||||
contextMenuService.show.subscribe(e => {
|
||||
expect(e.event).toBeDefined();
|
||||
expect(e.event).toBe(event);
|
||||
});
|
||||
|
||||
directive.onShowContextMenu(event);
|
||||
});
|
||||
|
||||
it('should forward menu items to service', () => {
|
||||
let links = [{}, {}];
|
||||
directive.links = links;
|
||||
|
||||
contextMenuService.show.subscribe(e => {
|
||||
expect(e.obj).toBeDefined();
|
||||
expect(e.obj).toBe(links);
|
||||
});
|
||||
|
||||
directive.onShowContextMenu(null);
|
||||
});
|
||||
|
||||
});
|
@@ -18,7 +18,7 @@
|
||||
/* tslint:disable:no-input-rename */
|
||||
|
||||
import { Directive, HostListener, Input } from '@angular/core';
|
||||
import { ContextMenuService } from './context-menu.service';
|
||||
import { ContextMenuOverlayService } from './context-menu-overlay.service';
|
||||
|
||||
// @deprecated 2.3.0 context-menu tag removed
|
||||
@Directive({
|
||||
@@ -33,8 +33,7 @@ export class ContextMenuDirective {
|
||||
@Input('context-menu-enabled')
|
||||
enabled: boolean = false;
|
||||
|
||||
constructor(private _contextMenuService: ContextMenuService) {
|
||||
}
|
||||
constructor(private contextMenuService: ContextMenuOverlayService) {}
|
||||
|
||||
@HostListener('contextmenu', ['$event'])
|
||||
onShowContextMenu(event?: MouseEvent) {
|
||||
@@ -44,9 +43,10 @@ export class ContextMenuDirective {
|
||||
}
|
||||
|
||||
if (this.links && this.links.length > 0) {
|
||||
if (this._contextMenuService) {
|
||||
this._contextMenuService.show.next({event: event, obj: this.links});
|
||||
}
|
||||
this.contextMenuService.open({
|
||||
source: event,
|
||||
data: this.links
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { ContextMenuHolderComponent } from './context-menu-holder.component';
|
||||
import { ContextMenuDirective } from './context-menu.directive';
|
||||
import { ContextMenuListComponent } from './context-menu-list.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -31,11 +32,15 @@ import { ContextMenuDirective } from './context-menu.directive';
|
||||
],
|
||||
declarations: [
|
||||
ContextMenuHolderComponent,
|
||||
ContextMenuDirective
|
||||
ContextMenuDirective,
|
||||
ContextMenuListComponent
|
||||
],
|
||||
exports: [
|
||||
ContextMenuHolderComponent,
|
||||
ContextMenuDirective
|
||||
],
|
||||
entryComponents: [
|
||||
ContextMenuListComponent
|
||||
]
|
||||
})
|
||||
export class ContextMenuModule {}
|
||||
|
174
lib/core/context-menu/context-menu.spec.ts
Normal file
174
lib/core/context-menu/context-menu.spec.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { ContextMenuModule } from './context-menu.module';
|
||||
import { CoreModule } from '../core.module';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-test-component',
|
||||
template: `
|
||||
<div id="target" [context-menu]="actions" [context-menu-enabled]="true"></div>
|
||||
`
|
||||
})
|
||||
class TestComponent {
|
||||
actions;
|
||||
}
|
||||
|
||||
describe('ContextMenuDirective', () => {
|
||||
let fixture: ComponentFixture<TestComponent>;
|
||||
const actions = [
|
||||
{
|
||||
model: {
|
||||
visible: false,
|
||||
title: 'Action 1'
|
||||
},
|
||||
subject: {
|
||||
next: jasmine.createSpy('next')
|
||||
}
|
||||
},
|
||||
{
|
||||
model: {
|
||||
visible: true,
|
||||
disabled: true,
|
||||
title: 'Action 2',
|
||||
icon: null
|
||||
},
|
||||
subject: {
|
||||
next: jasmine.createSpy('next')
|
||||
}
|
||||
},
|
||||
{
|
||||
model: {
|
||||
visible: true,
|
||||
disabled: false,
|
||||
title: 'Action 3',
|
||||
icon: 'action-icon-3'
|
||||
},
|
||||
subject: {
|
||||
next: jasmine.createSpy('next')
|
||||
}
|
||||
},
|
||||
{
|
||||
model: {
|
||||
visible: true,
|
||||
disabled: false,
|
||||
title: 'Action 4',
|
||||
icon: 'action-icon-4'
|
||||
},
|
||||
subject: {
|
||||
next: jasmine.createSpy('next')
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot(),
|
||||
ContextMenuModule,
|
||||
NoopAnimationsModule
|
||||
],
|
||||
declarations: [
|
||||
TestComponent
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(TestComponent);
|
||||
fixture.componentInstance.actions = actions;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should not render contextmenu when action was not performed', () => {
|
||||
const containerElement = fixture.debugElement.nativeElement.parentElement;
|
||||
expect(containerElement.querySelector('.adf-context-menu button')).toBe(null);
|
||||
});
|
||||
|
||||
describe('Events', () => {
|
||||
let targetElement: HTMLElement;
|
||||
let contextMenu: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
targetElement = fixture.debugElement.nativeElement.querySelector('#target');
|
||||
targetElement.dispatchEvent(new CustomEvent('contextmenu'));
|
||||
fixture.detectChanges();
|
||||
contextMenu = document.querySelector('.adf-context-menu');
|
||||
});
|
||||
|
||||
it('should show menu on mouse contextmenu event', () => {
|
||||
expect(contextMenu).not.toBe(null);
|
||||
});
|
||||
|
||||
it('should set DOM element reference on menu open event', () => {
|
||||
expect(contextMenu.className).toContain('adf-context-menu');
|
||||
});
|
||||
|
||||
it('should reset DOM element reference on Escape event', () => {
|
||||
const event = new KeyboardEvent('keydown', {
|
||||
bubbles : true, cancelable : true, key : 'Escape'
|
||||
});
|
||||
|
||||
document.querySelector('.cdk-overlay-backdrop').dispatchEvent(event);
|
||||
fixture.detectChanges();
|
||||
expect(document.querySelector('.adf-context-menu')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Contextmenu list', () => {
|
||||
let targetElement: HTMLElement;
|
||||
let contextMenu: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
targetElement = fixture.debugElement.nativeElement.querySelector('#target');
|
||||
targetElement.dispatchEvent(new CustomEvent('contextmenu'));
|
||||
fixture.detectChanges();
|
||||
contextMenu = document.querySelector('.adf-context-menu');
|
||||
});
|
||||
|
||||
it('should not render item with visibility property set to false', () => {
|
||||
expect(contextMenu.querySelectorAll('button').length).toBe(3);
|
||||
});
|
||||
|
||||
it('should render item as disabled when `disabled` property is set to true', () => {
|
||||
expect(contextMenu.querySelectorAll('button')[0].disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should set first not disabled item as active', () => {
|
||||
expect(document.activeElement.querySelector('mat-icon').innerHTML).toContain('action-icon-3');
|
||||
});
|
||||
|
||||
it('should not allow action event when item is disabled', () => {
|
||||
contextMenu.querySelectorAll('button')[0].click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.actions[1].subject.next).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should perform action when item is not disabled', () => {
|
||||
contextMenu.querySelectorAll('button')[1].click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.actions[2].subject.next).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not render item icon if not set', () => {
|
||||
expect(contextMenu.querySelectorAll('button')[0].querySelector('mat-icon')).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
20
lib/core/context-menu/context-menu.tokens.ts
Normal file
20
lib/core/context-menu/context-menu.tokens.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
export const CONTEXT_MENU_DATA = new InjectionToken<any>('CONTEXT_MENU_DATA');
|
24
lib/core/context-menu/interfaces.ts
Normal file
24
lib/core/context-menu/interfaces.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface ContextMenuOverlayConfig {
|
||||
panelClass?: string;
|
||||
hasBackdrop?: boolean;
|
||||
backdropClass?: string;
|
||||
source?: MouseEvent;
|
||||
data?: any;
|
||||
}
|
Reference in New Issue
Block a user