diff --git a/docs/extending/application-actions.md b/docs/extending/application-actions.md
index 9764c91f5..0d6108763 100644
--- a/docs/extending/application-actions.md
+++ b/docs/extending/application-actions.md
@@ -124,5 +124,6 @@ Below is the list of public actions types you can use in the plugin definitions
| 1.8.0 | VIEW_NODE | NodeId<`string`> , [ViewNodeExtras](../features/file-viewer.md#details)<`any`> | Lightweight preview of a node by id. Can be invoked from extensions. For details also see [File Viewer](../features/file-viewer.md#details) |
| 1.8.0 | CLOSE_PREVIEW | n/a | Closes the viewer ( preview of the item ) |
| 1.9.0 | RESET_SELECTION | n/a | Resets active document list selection |
-| 1.10.0 | FILE_FROM_TEMPLATE | n/a | Invoke dialogs flow for creating a file from selected template|
-| 1.10.0 | CREATE_FILE_FROM_TEMPLATE | Node | Copy selected tetmplate into current folder |
+| 1.10.0 | FILE_FROM_TEMPLATE | n/a | Invoke dialogs flow for creating a file from selected template|
+| 1.10.0 | CREATE_FILE_FROM_TEMPLATE | Node | Copy selected template into current folder |
+| 1.10.0 | CONTEXT_MENU | MouseEvent | Invoke context menu for [DocumentListComponent](https://www.alfresco.com/abn/adf/docs/content-services/components/document-list.component) |
diff --git a/src/app/components/context-menu/context-menu.directives.spec.ts b/projects/aca-shared/src/lib/directives/contextmenu/contextmenu.directive.spec.ts
similarity index 77%
rename from src/app/components/context-menu/context-menu.directives.spec.ts
rename to projects/aca-shared/src/lib/directives/contextmenu/contextmenu.directive.spec.ts
index e32fe86fd..36f75c365 100644
--- a/src/app/components/context-menu/context-menu.directives.spec.ts
+++ b/projects/aca-shared/src/lib/directives/contextmenu/contextmenu.directive.spec.ts
@@ -23,24 +23,25 @@
* along with Alfresco. If not, see .
*/
-import { ContextActionsDirective } from './context-menu.directive';
+import { ContextActionsDirective } from './contextmenu.directive';
+import { ContextMenu } from '@alfresco/aca-shared/store';
import { fakeAsync, tick } from '@angular/core/testing';
describe('ContextActionsDirective', () => {
let directive;
- const contextMenuServiceMock = {
- open: jasmine.createSpy('open')
+ const storeMock = {
+ dispatch: jasmine.createSpy('dispatch')
};
beforeEach(() => {
- directive = new ContextActionsDirective(contextMenuServiceMock);
+ directive = new ContextActionsDirective(storeMock);
});
it('should not render context menu when `enabled` property is false', () => {
directive.enabled = false;
directive.onContextMenuEvent(new MouseEvent('contextmenu'));
- expect(contextMenuServiceMock.open).not.toHaveBeenCalled();
+ expect(storeMock.dispatch).not.toHaveBeenCalled();
});
it('should call service to render context menu', fakeAsync(() => {
@@ -51,13 +52,16 @@ describe('ContextActionsDirective', () => {
const fragment = document.createDocumentFragment();
fragment.appendChild(el);
const target = fragment.querySelector('div');
+ const mouseEventMock = { preventDefault: () => {}, target };
directive.ngOnInit();
- directive.onContextMenuEvent({ preventDefault: () => {}, target });
+ directive.onContextMenuEvent(mouseEventMock);
tick(500);
- expect(contextMenuServiceMock.open).toHaveBeenCalled();
+ expect(storeMock.dispatch).toHaveBeenCalledWith(
+ new ContextMenu(mouseEventMock)
+ );
}));
});
diff --git a/src/app/components/context-menu/context-menu.directive.ts b/projects/aca-shared/src/lib/directives/contextmenu/contextmenu.directive.ts
similarity index 69%
rename from src/app/components/context-menu/context-menu.directive.ts
rename to projects/aca-shared/src/lib/directives/contextmenu/contextmenu.directive.ts
index 140f3b5df..448b4b085 100644
--- a/src/app/components/context-menu/context-menu.directive.ts
+++ b/projects/aca-shared/src/lib/directives/contextmenu/contextmenu.directive.ts
@@ -30,18 +30,18 @@ import {
OnInit,
OnDestroy
} from '@angular/core';
-import { ContextMenuOverlayRef } from './context-menu-overlay';
-import { ContextMenuService } from './context-menu.service';
-import { debounceTime } from 'rxjs/operators';
-import { Subject, fromEvent, Subscription } from 'rxjs';
+import { debounceTime, takeUntil } from 'rxjs/operators';
+import { Subject } from 'rxjs';
+import { Store } from '@ngrx/store';
+import { AppStore, ContextMenu } from '@alfresco/aca-shared/store';
@Directive({
- selector: '[acaContextActions]'
+ selector: '[acaContextActions]',
+ exportAs: 'acaContextActions'
})
export class ContextActionsDirective implements OnInit, OnDestroy {
private execute$: Subject = new Subject();
- private subscriptions: Subscription[] = [];
- private overlayRef: ContextMenuOverlayRef = null;
+ onDestroy$: Subject = new Subject();
// tslint:disable-next-line:no-input-rename
@Input('acaContextEnable')
@@ -61,42 +61,30 @@ export class ContextActionsDirective implements OnInit, OnDestroy {
}
}
- constructor(private contextMenuService: ContextMenuService) {}
+ constructor(private store: Store) {}
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);
- })
- );
+ this.execute$
+ .pipe(
+ debounceTime(300),
+ takeUntil(this.onDestroy$)
+ )
+ .subscribe((event: MouseEvent) => {
+ this.store.dispatch(new ContextMenu(event));
+ });
}
ngOnDestroy() {
- this.subscriptions.forEach(subscription => subscription.unsubscribe());
- this.subscriptions = [];
- this.execute$ = null;
+ this.onDestroy$.next(true);
+ this.onDestroy$.complete();
}
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,
- backdropClass: 'cdk-overlay-transparent-backdrop',
- panelClass: 'cdk-overlay-pane'
- });
+ this.execute$.next(event);
}
private getTarget(event: MouseEvent): Element {
diff --git a/projects/aca-shared/src/lib/directives/contextmenu/contextmenu.module.ts b/projects/aca-shared/src/lib/directives/contextmenu/contextmenu.module.ts
new file mode 100644
index 000000000..30ecdc60d
--- /dev/null
+++ b/projects/aca-shared/src/lib/directives/contextmenu/contextmenu.module.ts
@@ -0,0 +1,33 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 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 .
+ */
+
+import { NgModule } from '@angular/core';
+import { ContextActionsDirective } from './contextmenu.directive';
+
+@NgModule({
+ declarations: [ContextActionsDirective],
+ exports: [ContextActionsDirective]
+})
+export class ContextActionsModule {}
diff --git a/projects/aca-shared/src/lib/shared.module.ts b/projects/aca-shared/src/lib/shared.module.ts
index 18a1e5424..54b96cb65 100644
--- a/projects/aca-shared/src/lib/shared.module.ts
+++ b/projects/aca-shared/src/lib/shared.module.ts
@@ -27,8 +27,11 @@ import { NgModule, ModuleWithProviders } from '@angular/core';
import { ContentApiService } from './services/content-api.service';
import { NodePermissionService } from './services/node-permission.service';
import { AppService } from './services/app.service';
-
-@NgModule({})
+import { ContextActionsModule } from './directives/contextmenu/contextmenu.module';
+@NgModule({
+ imports: [ContextActionsModule],
+ exports: [ContextActionsModule]
+})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
diff --git a/projects/aca-shared/src/public-api.ts b/projects/aca-shared/src/public-api.ts
index eeabe06e3..de7d4d9aa 100644
--- a/projects/aca-shared/src/public-api.ts
+++ b/projects/aca-shared/src/public-api.ts
@@ -39,4 +39,7 @@ export * from './lib/services/node-permission.service';
export * from './lib/components/generic-error/generic-error.component';
export * from './lib/components/generic-error/generic-error.module';
+export * from './lib/directives/contextmenu/contextmenu.directive';
+export * from './lib/directives/contextmenu/contextmenu.module';
+
export * from './lib/shared.module';
diff --git a/projects/aca-shared/store/src/actions/contextmenu.actions.ts b/projects/aca-shared/store/src/actions/contextmenu.actions.ts
new file mode 100644
index 000000000..c0cac2f7f
--- /dev/null
+++ b/projects/aca-shared/store/src/actions/contextmenu.actions.ts
@@ -0,0 +1,36 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 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 .
+ */
+
+import { Action } from '@ngrx/store';
+
+export enum ContextMenuActionTypes {
+ ContextMenu = 'CONTEXT_MENU'
+}
+
+export class ContextMenu implements Action {
+ readonly type = ContextMenuActionTypes.ContextMenu;
+
+ constructor(public event: MouseEvent) {}
+}
diff --git a/projects/aca-shared/store/src/public_api.ts b/projects/aca-shared/store/src/public_api.ts
index 39bebd47b..3b6ce971a 100644
--- a/projects/aca-shared/store/src/public_api.ts
+++ b/projects/aca-shared/store/src/public_api.ts
@@ -33,6 +33,7 @@ export * from './actions/upload.actions';
export * from './actions/viewer.actions';
export * from './actions/metadata-aspect.actions';
export * from './actions/template.actions';
+export * from './actions/contextmenu.actions';
export * from './effects/dialog.effects';
export * from './effects/router.effects';
diff --git a/src/app/components/context-menu/context-menu.module.ts b/src/app/components/context-menu/context-menu.module.ts
index 76c633769..07d7e2e71 100644
--- a/src/app/components/context-menu/context-menu.module.ts
+++ b/src/app/components/context-menu/context-menu.module.ts
@@ -35,7 +35,7 @@ import { AppCommonModule } from '../common/common.module';
import { ContextMenuItemComponent } from './context-menu-item.component';
import { OutsideEventDirective } from './context-menu-outside-event.directive';
import { ContextMenuComponent } from './context-menu.component';
-import { ContextActionsDirective } from './context-menu.directive';
+import { ContextActionsModule } from '@alfresco/aca-shared';
@NgModule({
imports: [
@@ -46,19 +46,19 @@ import { ContextActionsDirective } from './context-menu.directive';
CoreExtensionsModule.forChild(),
CoreModule.forChild(),
AppCommonModule,
- ExtensionsModule
+ ExtensionsModule,
+ ContextActionsModule
],
declarations: [
- ContextActionsDirective,
ContextMenuComponent,
ContextMenuItemComponent,
OutsideEventDirective
],
exports: [
OutsideEventDirective,
- ContextActionsDirective,
ContextMenuComponent,
- ContextMenuItemComponent
+ ContextMenuItemComponent,
+ ContextActionsModule
],
entryComponents: [ContextMenuComponent]
})
diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts
index 1db3d4cb9..8286fe668 100644
--- a/src/app/store/app-store.module.ts
+++ b/src/app/store/app-store.module.ts
@@ -40,7 +40,8 @@ import {
LibraryEffects,
UploadEffects,
FavoriteEffects,
- TemplateEffects
+ TemplateEffects,
+ ContextMenuEffects
} from './effects';
import { INITIAL_STATE } from './initial-state';
@@ -58,7 +59,8 @@ import { INITIAL_STATE } from './initial-state';
LibraryEffects,
UploadEffects,
FavoriteEffects,
- TemplateEffects
+ TemplateEffects,
+ ContextMenuEffects
]),
!environment.production
? StoreDevtoolsModule.instrument({ maxAge: 25 })
diff --git a/src/app/store/effects.ts b/src/app/store/effects.ts
index 5856c9cd3..12f7862fd 100644
--- a/src/app/store/effects.ts
+++ b/src/app/store/effects.ts
@@ -33,3 +33,4 @@ export * from './effects/library.effects';
export * from './effects/upload.effects';
export * from './effects/upload.effects';
export * from './effects/template.effects';
+export * from './effects/contextmenu.effects';
diff --git a/src/app/store/effects/contextmenu.effects.spec.ts b/src/app/store/effects/contextmenu.effects.spec.ts
new file mode 100644
index 000000000..0e992efad
--- /dev/null
+++ b/src/app/store/effects/contextmenu.effects.spec.ts
@@ -0,0 +1,65 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 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 .
+ */
+
+import { TestBed } from '@angular/core/testing';
+import { AppTestingModule } from '../../testing/app-testing.module';
+import { ContextMenuEffects } from './contextmenu.effects';
+import { EffectsModule } from '@ngrx/effects';
+import { Store } from '@ngrx/store';
+import { ContextMenu } from '@alfresco/aca-shared/store';
+import { ContextMenuService } from '../../components/context-menu/context-menu.service';
+
+describe('ContextMenuEffects', () => {
+ let store: Store;
+ let contextMenuService: ContextMenuService;
+ const overlayRefMock = {
+ close: jasmine.createSpy('close')
+ };
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [AppTestingModule, EffectsModule.forRoot([ContextMenuEffects])],
+ providers: [ContextMenuService]
+ });
+
+ store = TestBed.get(Store);
+ contextMenuService = TestBed.get(ContextMenuService);
+
+ spyOn(contextMenuService, 'open').and.returnValue(overlayRefMock);
+ });
+
+ it('should open dialog', () => {
+ store.dispatch(new ContextMenu(new MouseEvent('click')));
+ expect(contextMenuService.open).toHaveBeenCalled();
+ });
+
+ it('should close dialog reference if previously was opened', () => {
+ store.dispatch(new ContextMenu(new MouseEvent('click')));
+ expect(contextMenuService.open).toHaveBeenCalled();
+
+ store.dispatch(new ContextMenu(new MouseEvent('click')));
+ expect(overlayRefMock.close).toHaveBeenCalled();
+ });
+});
diff --git a/src/app/store/effects/contextmenu.effects.ts b/src/app/store/effects/contextmenu.effects.ts
new file mode 100644
index 000000000..0934262ba
--- /dev/null
+++ b/src/app/store/effects/contextmenu.effects.ts
@@ -0,0 +1,61 @@
+/*!
+ * @license
+ * Alfresco Example Content Application
+ *
+ * Copyright (C) 2005 - 2020 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 .
+ */
+
+import {
+ ContextMenuActionTypes,
+ ContextMenu
+} from '@alfresco/aca-shared/store';
+import { Injectable } from '@angular/core';
+import { Actions, Effect, ofType } from '@ngrx/effects';
+import { map } from 'rxjs/operators';
+import { ContextMenuOverlayRef } from '../../components/context-menu/context-menu-overlay';
+import { ContextMenuService } from '../../components/context-menu/context-menu.service';
+
+@Injectable()
+export class ContextMenuEffects {
+ private overlayRef: ContextMenuOverlayRef = null;
+
+ constructor(
+ private contextMenuService: ContextMenuService,
+ private actions$: Actions
+ ) {}
+
+ @Effect({ dispatch: false })
+ contextMenu$ = this.actions$.pipe(
+ ofType(ContextMenuActionTypes.ContextMenu),
+ map(action => {
+ if (this.overlayRef) {
+ this.overlayRef.close();
+ }
+
+ this.overlayRef = this.contextMenuService.open({
+ source: action.event,
+ hasBackdrop: false,
+ backdropClass: 'cdk-overlay-transparent-backdrop',
+ panelClass: 'cdk-overlay-pane'
+ });
+ })
+ );
+}