From a8a7f0578c1f75c4ec05796c0f7c8d8dfc3c6f84 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Mon, 25 Nov 2019 12:17:34 -0500 Subject: [PATCH] LPXXX editor continued Signed-off-by: Bill Erickson --- .../src/eg2/src/app/share/common-widgets.module.ts | 14 ++- ...nt.css => context-menu-container.component.css} | 0 ....html => context-menu-container.component.html} | 0 .../context-menu-container.component.ts | 38 +++++++ .../share/context-menu/context-menu.component.ts | 111 --------------------- .../share/context-menu/context-menu.directive.ts | 90 +++++++++++++++++ .../app/share/context-menu/context-menu.module.ts | 24 +++++ .../app/share/context-menu/context-menu.service.ts | 32 ++++++ .../marc-edit/editable-content.component.html | 11 +- .../share/marc-edit/editable-content.component.ts | 2 +- .../share/marc-edit/fixed-field.component.html | 8 +- .../staff/share/marc-edit/fixed-field.component.ts | 3 - .../src/eg2/src/app/staff/staff.component.html | 3 + 13 files changed, 200 insertions(+), 136 deletions(-) rename Open-ILS/src/eg2/src/app/share/context-menu/{context-menu.component.css => context-menu-container.component.css} (100%) rename Open-ILS/src/eg2/src/app/share/context-menu/{context-menu.component.html => context-menu-container.component.html} (100%) create mode 100644 Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.ts delete mode 100644 Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.ts create mode 100644 Open-ILS/src/eg2/src/app/share/context-menu/context-menu.directive.ts create mode 100644 Open-ILS/src/eg2/src/app/share/context-menu/context-menu.module.ts create mode 100644 Open-ILS/src/eg2/src/app/share/context-menu/context-menu.service.ts diff --git a/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts b/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts index 8ba4750ee1..e1f85cdd3e 100644 --- a/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts +++ b/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts @@ -14,7 +14,7 @@ import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; import {OrgSelectComponent} from '@eg/share/org-select/org-select.component'; import {DateRangeSelectComponent} from '@eg/share/daterange-select/daterange-select.component'; import {DateTimeSelectComponent} from '@eg/share/datetime-select/datetime-select.component'; -import {ContextMenuDirective, ContextMenuComponent} from '@eg/share/context-menu/context-menu.component'; +import {ContextMenuModule} from '@eg/share/context-menu/context-menu.module'; @NgModule({ @@ -24,16 +24,15 @@ import {ContextMenuDirective, ContextMenuComponent} from '@eg/share/context-menu DateSelectComponent, OrgSelectComponent, DateRangeSelectComponent, - DateTimeSelectComponent, - ContextMenuDirective, - ContextMenuComponent + DateTimeSelectComponent ], imports: [ CommonModule, FormsModule, ReactiveFormsModule, NgbModule, - EgCoreModule + EgCoreModule, + ContextMenuModule ], exports: [ CommonModule, @@ -46,9 +45,8 @@ import {ContextMenuDirective, ContextMenuComponent} from '@eg/share/context-menu OrgSelectComponent, DateRangeSelectComponent, DateTimeSelectComponent, - ContextMenuComponent, - ContextMenuDirective - ], + ContextMenuModule + ] }) export class CommonWidgetsModule { } diff --git a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.css b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.css similarity index 100% rename from Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.css rename to Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.css diff --git a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.html b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.html similarity index 100% rename from Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.html rename to Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.html diff --git a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.ts b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.ts new file mode 100644 index 0000000000..a5dfdcefbf --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu-container.component.ts @@ -0,0 +1,38 @@ +import {Component, Input, Output, EventEmitter, OnInit, ViewChild, + AfterViewInit, TemplateRef, ViewEncapsulation} from '@angular/core'; +import {ContextMenuService, ContextMenu, ContextMenuEntry} from './context-menu.service'; + +@Component({ + selector: 'eg-context-menu-container', + templateUrl: './context-menu-container.component.html', + styleUrls: ['context-menu-container.component.css'], + /* Our CSS affects the style of the popover, which may + * be beyond our reach for standard view encapsulation */ + encapsulation: ViewEncapsulation.None +}) + +export class ContextMenuContainerComponent implements OnInit, AfterViewInit { + + menuEntries: ContextMenuEntry[] = []; + @ViewChild('menuTemplate', {static: false}) menuTemplate: TemplateRef; + + constructor(private menuService: ContextMenuService) {} + + ngOnInit() { + + this.menuService.showMenuRequest.subscribe( + (menu: ContextMenu) => { + + this.menuEntries = menu.entries + }); + } + + ngAfterViewInit() { + this.menuService.menuTemplate = this.menuTemplate; + } + + entryClicked(entry: ContextMenuEntry) { + this.menuService.menuItemSelected.emit(entry); + } +} + diff --git a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.ts b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.ts deleted file mode 100644 index df56b96e82..0000000000 --- a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.component.ts +++ /dev/null @@ -1,111 +0,0 @@ -import {Component, Input, Output, AfterViewInit, EventEmitter, Directive, ViewChild, - Renderer2, ViewEncapsulation, ComponentFactoryResolver, TemplateRef} from '@angular/core'; -import {NgbPopover} from '@ng-bootstrap/ng-bootstrap'; - -/** - * Context menu component. - * - * No state is maintained (i.e. there is no current value), events are - * simply emitted as entries are chosen. - * - * - * - * - */ - -export interface ContextMenuEntry { - value: string; - label: string; -} - -@Component({ - selector: 'eg-context-menu', - templateUrl: './context-menu.component.html', - styleUrls: ['context-menu.component.css'], - /* Our CSS affects the style of the popover, which may - * be beyond our reach for standard view encapsulation */ - encapsulation: ViewEncapsulation.None -}) - -export class ContextMenuComponent implements AfterViewInit { - - @Input() menuEntries: ContextMenuEntry[] = []; - - // Additional CSS classes (space separated) to apply to the entry links - @Input() entryClasses = ''; - - @Output() entrySelected: EventEmitter; - - @ViewChild('menuTemplate', {static: false}) - public menuTemplate: TemplateRef; - - randId = Math.floor(Math.random() * 10000000); - - constructor(private renderer: Renderer2) { - this.entrySelected = new EventEmitter(); - } - - ngAfterViewInit() { - } - - grabFocus() { - // ARG TODO - const link = this.renderer.selectRootElement(`[id='${this.randId}']`); - setTimeout(() => { - console.log('focusing ', link); - link.focus(); - }, 400); - } - - entryClicked(entry: ContextMenuEntry) { - console.log('emitting ', entry); - this.entrySelected.emit(entry); - } -} - -@Directive({ - selector: '[egContextMenu]', - exportAs: 'egContextMenu' -}) -export class ContextMenuDirective extends NgbPopover { - - menuComp: ContextMenuComponent; - - triggers = 'contextmenu'; // TODO TODO - popoverClass = 'eg-context-menu'; - - @Input() set egContextMenu(menuComp: ContextMenuComponent) { - this.menuComp = menuComp; - } - - // Only one active menu is allowed at a time. - static activeMenu: ContextMenuDirective; - - open() { - - // The popover will automatically close in most cases, but - // context menus preventDefault(), which prevents right-click on - // other context menus from firing the close operation. Or at - // least, that's my assumption. This fixes it. - if (ContextMenuDirective.activeMenu) { - ContextMenuDirective.activeMenu.close(); - } - - if (!this.menuComp.menuEntries || - this.menuComp.menuEntries.length === 0) { - return; - } - - this.ngbPopover = this.menuComp.menuTemplate; - ContextMenuDirective.activeMenu = this; - - super.open(); - - // ARG TODO - setTimeout(() => this.menuComp.grabFocus()); - } -} - - diff --git a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.directive.ts b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.directive.ts new file mode 100644 index 0000000000..591d9d01f3 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.directive.ts @@ -0,0 +1,90 @@ +import {Input, Output, EventEmitter, Directive} from '@angular/core'; +import {NgbPopover} from '@ng-bootstrap/ng-bootstrap'; +import {ContextMenuService, ContextMenu, ContextMenuEntry} from './context-menu.service'; + + +/* Import all of this stuff so we can pass it to our parent + * class via its constructor */ +import { + Inject, Injector, Renderer2, ElementRef, TemplateRef, ViewContainerRef, + ComponentFactoryResolver, NgZone, ChangeDetectorRef, ApplicationRef +} from '@angular/core'; +import {DOCUMENT} from '@angular/common'; +import {NgbPopoverConfig} from '@ng-bootstrap/ng-bootstrap'; +/* --- */ + +@Directive({ + selector: '[egContextMenu]', + exportAs: 'egContextMenu' +}) +export class ContextMenuDirective extends NgbPopover { + + triggers = 'contextmenu'; + popoverClass = 'eg-context-menu'; + + menuEntries: ContextMenuEntry[] = []; + menu: ContextMenu; + + @Input() set egContextMenu(menuEntries: ContextMenuEntry[]) { + this.menuEntries = menuEntries; + } + + @Output() menuItemSelected: EventEmitter; + + // Only one active menu is allowed at a time. + static activeDirective: ContextMenuDirective; + static menuId = 0; + + constructor( + p1: ElementRef, p2: Renderer2, p3: Injector, + p4: ComponentFactoryResolver, p5: ViewContainerRef, p6: NgbPopoverConfig, + p7: NgZone, @Inject(DOCUMENT) p8: any, p9: ChangeDetectorRef, + p10: ApplicationRef, private menuService: ContextMenuService) { + + // relay injected services to parent + super(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + + this.menuItemSelected = new EventEmitter(); + + this.menuService.menuItemSelected.subscribe( + (entry: ContextMenuEntry) => { + + // Only broadcast entry selection to my listeners if I'm + // hosting the menu where the selection occurred. + + if (this.menu && this.menu.id === this.menuService.activeMenu.id) { + this.menuItemSelected.emit(entry); + } + }); + } + + open() { + + // In certain scenarios (e.g. right-clicking on another context + // menu) an open popover will stay open. Force it closed here. + if (ContextMenuDirective.activeDirective) { + ContextMenuDirective.activeDirective.close(); + ContextMenuDirective.activeDirective = null; + this.menuService.activeMenu == null; + } + + if (!this.menuEntries || + this.menuEntries.length === 0) { + return; + } + + this.menu = new ContextMenu(); + this.menu.id = ContextMenuDirective.menuId++; + this.menu.entries = this.menuEntries; + + this.menuService.activeMenu = this.menu; + this.menuService.showMenuRequest.emit(this.menu); + this.ngbPopover = this.menuService.menuTemplate; + + ContextMenuDirective.activeDirective = this; + + super.open(); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.module.ts b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.module.ts new file mode 100644 index 0000000000..fb25e6144a --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.module.ts @@ -0,0 +1,24 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {NgbModule} from '@ng-bootstrap/ng-bootstrap'; +import {ContextMenuService} from './context-menu.service'; +import {ContextMenuDirective} from './context-menu.directive'; +import {ContextMenuContainerComponent} from './context-menu-container.component'; + +@NgModule({ + declarations: [ + ContextMenuDirective, + ContextMenuContainerComponent + ], + imports: [ + CommonModule, + NgbModule + ], + exports: [ + ContextMenuDirective, + ContextMenuContainerComponent + ] +}) + +export class ContextMenuModule { } + diff --git a/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.service.ts b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.service.ts new file mode 100644 index 0000000000..bfedf4232f --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/context-menu/context-menu.service.ts @@ -0,0 +1,32 @@ +import {Injectable, EventEmitter, TemplateRef} from '@angular/core'; +import {tap} from 'rxjs/operators'; + +/* Relay requests to/from the context menu directive and its + * template container component */ + +export interface ContextMenuEntry { + value: string; + label: string; +} + +export class ContextMenu { + id: number; + entries: ContextMenuEntry[]; +} + +@Injectable({providedIn: 'root'}) +export class ContextMenuService { + + showMenuRequest: EventEmitter; + menuItemSelected: EventEmitter; + + menuTemplate: TemplateRef; + activeMenu: ContextMenu; + + constructor() { + this.showMenuRequest = new EventEmitter(); + this.menuItemSelected = new EventEmitter(); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.html b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.html index ed6c64a9f3..f44f711162 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.html @@ -1,16 +1,12 @@ - - -
@@ -26,7 +22,8 @@ [maxlength]="maxLength || ''" [disabled]="fieldText" [attr.tabindex]="fieldText ? -1 : ''" - [egContextMenu]="contextMenu" + [egContextMenu]="contextMenuEntries()" + (menuItemSelected)="contextMenuChange($event.value)" (keydown)="inputKeyDown($event)" (focus)="$event.target.select()" [ngModel]="getContent()" diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.ts b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.ts index d3602c643a..6d1b055e7d 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.ts @@ -3,7 +3,7 @@ import {ElementRef, Component, Input, Output, OnInit, EventEmitter, import {filter} from 'rxjs/operators'; import {MarcRecord, MarcField, MarcSubfield} from './marcrecord'; import {MarcEditContext, FieldFocusRequest} from './editor-context'; -import {ContextMenuEntry} from '@eg/share/context-menu/context-menu.component'; +import {ContextMenuEntry} from '@eg/share/context-menu/context-menu.service'; import {TagTableService} from './tagtable.service'; /** diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.html b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.html index 3d822f9eaf..52c332b56b 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.html @@ -1,11 +1,6 @@ - - -
@@ -18,7 +13,8 @@ (change)="valueChange()" [(ngModel)]="fieldValue" [attr.maxlength]="fieldLength" [attr.size]="fieldLength" - [egContextMenu]="contextMenu" + [egContextMenu]="fieldValues" + (menuItemSelected)="valueChange($event.value)" />
diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.ts b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.ts index 3d71ddf891..703aaea61f 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/fixed-field.component.ts @@ -2,8 +2,6 @@ import {Component, Input, Output, OnInit, EventEmitter} from '@angular/core'; import {MarcRecord} from './marcrecord'; import {MarcEditContext} from './editor-context'; import {TagTableService, ValueLabelPair} from './tagtable.service'; -//import {NgbPopover} from '@ng-bootstrap/ng-bootstrap'; -//import {ContextMenuDirective} from './context-menu.component'; /** * MARC Fixed Field Editing Component @@ -27,7 +25,6 @@ export class FixedFieldComponent implements OnInit { fieldMeta: any; fieldLength: number = null; fieldValues: ValueLabelPair[] = null; - //popOver: NgbPopover; randId = Math.floor(Math.random() * 10000000); constructor(private tagTable: TagTableService) {} diff --git a/Open-ILS/src/eg2/src/app/staff/staff.component.html b/Open-ILS/src/eg2/src/app/staff/staff.component.html index 9002fa8e1f..e7fec07002 100644 --- a/Open-ILS/src/eg2/src/app/staff/staff.component.html +++ b/Open-ILS/src/eg2/src/app/staff/staff.component.html @@ -21,3 +21,6 @@ + + + -- 2.11.0