From c602f66f203dca1b54bca34dd289a0d9ec2c59eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Tue, 18 Oct 2022 12:00:48 -0300 Subject: [PATCH 1/2] Fixed event types and moved emitter --- index.html | 4 ++ src/main.ts | 100 ++++++++++++++++++++++++++++++++++++------ src/types.ts | 18 ++++++-- test/instance.spec.ts | 28 +++++++++++- vite.config.ts | 3 +- 5 files changed, 133 insertions(+), 20 deletions(-) diff --git a/index.html b/index.html index 2e4f46c..db58067 100644 --- a/index.html +++ b/index.html @@ -156,6 +156,10 @@ console.log({ evt }); }); + contextmenu.on('open', function (evt) { + console.log({ evt }); + }); + map.on('moveend', () => { console.log('moveend', contextmenu.isOpen()); }); diff --git a/src/main.ts b/src/main.ts index b727ea6..c36c243 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,9 +3,21 @@ import type { Coordinate } from 'ol/coordinate'; import OlMap from 'ol/Map'; import Control from 'ol/control/Control'; import BaseEvent from 'ol/events/Event'; +import { EventsKey } from 'ol/events'; +import { Types as ObjectEventTypes } from 'ol/ObjectEventType'; +import { CombinedOnSignature, EventTypes as OlEventTypes, OnSignature } from 'ol/Observable'; +import { ObjectEvent } from 'ol/Object'; import { CSS_CLASSES, DEFAULT_ITEMS, DEFAULT_OPTIONS } from './constants'; -import { CallbackObject, CustomEventTypes, EventTypes, Item, MenuEntry, Options } from './types'; +import { + CallbackObject, + ContextMenuEvent, + CustomEventTypes, + EventTypes, + Item, + MenuEntry, + Options, +} from './types'; import emitter from './emitter'; import { addMenuEntries, getLineHeight } from './helpers/dom'; @@ -40,6 +52,54 @@ export default class ContextMenu extends Control { protected menuEntries: Map = new Map(); + declare on: OnSignature & + OnSignature< + `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`, + ContextMenuEvent, + EventsKey + > & + OnSignature & + CombinedOnSignature< + | `${CustomEventTypes.BEFOREOPEN}` + | `${CustomEventTypes.OPEN}` + | ObjectEventTypes + | `${CustomEventTypes.CLOSE}` + | OlEventTypes, + EventsKey + >; + + declare once: OnSignature & + OnSignature< + `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`, + ContextMenuEvent, + EventsKey + > & + OnSignature & + CombinedOnSignature< + | `${CustomEventTypes.BEFOREOPEN}` + | `${CustomEventTypes.OPEN}` + | ObjectEventTypes + | `${CustomEventTypes.CLOSE}` + | OlEventTypes, + EventsKey + >; + + declare un: OnSignature & + OnSignature< + `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`, + ContextMenuEvent, + EventsKey + > & + OnSignature & + CombinedOnSignature< + | `${CustomEventTypes.BEFOREOPEN}` + | `${CustomEventTypes.OPEN}` + | ObjectEventTypes + | `${CustomEventTypes.CLOSE}` + | OlEventTypes, + void + >; + options: Options; constructor(opts: Partial = {}) { @@ -72,14 +132,6 @@ export default class ContextMenu extends Control { }; this.disabled = false; this.opened = false; - - emitter.on( - CustomEventTypes.ADD_MENU_ENTRY, - (item: MenuEntry, element: HTMLLIElement) => { - this.handleAddMenuEntry(item, element); - }, - this - ); } clear() { @@ -164,6 +216,14 @@ export default class ContextMenu extends Control { this.handleMapMove(); }); + emitter.on( + CustomEventTypes.ADD_MENU_ENTRY, + (item: MenuEntry, element: HTMLLIElement) => { + this.handleAddMenuEntry(item, element); + }, + this + ); + this.items = this.options.defaultItems ? this.options.items.concat(DEFAULT_ITEMS) : this.options.items; @@ -190,6 +250,8 @@ export default class ContextMenu extends Control { this.map .getViewport() .removeEventListener(this.options.eventType, this.contextMenuEventListener, false); + + emitter.off(CustomEventTypes.ADD_MENU_ENTRY); } protected removeMenuEntry(id: string) { @@ -203,11 +265,13 @@ export default class ContextMenu extends Control { protected handleContextMenu(evt: MouseEvent) { this.coordinate = this.map.getEventCoordinate(evt); this.pixel = this.map.getEventPixel(evt); - this.dispatchEvent({ - type: CustomEventTypes.BEFOREOPEN, - pixel: this.pixel, - coordinate: this.coordinate, - } as unknown as BaseEvent); + this.dispatchEvent( + new ContextMenuEvent({ + type: CustomEventTypes.BEFOREOPEN, + pixel: this.pixel, + coordinate: this.coordinate, + }) + ); if (this.disabled) return; @@ -238,6 +302,14 @@ export default class ContextMenu extends Control { this.opened = true; this.positionContainer(); this.container.classList.remove(CSS_CLASSES.hidden); + + this.dispatchEvent( + new ContextMenuEvent({ + type: CustomEventTypes.OPEN, + pixel: this.pixel, + coordinate: this.coordinate, + }) + ); } protected getMenuEntriesLength(): number { diff --git a/src/types.ts b/src/types.ts index 69b318e..1bb016c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,7 @@ import type { Coordinate } from 'ol/coordinate'; import type { Pixel } from 'ol/pixel'; import { Map as OlMap } from 'ol'; -import BaseEvent from 'ol/events/Event'; +import BaseEvent from 'ol/events/Event.js'; export enum EventTypes { CONTEXTMENU = 'contextmenu', @@ -16,9 +16,19 @@ export enum CustomEventTypes { ADD_MENU_ENTRY = 'add-menu-entry', } -export interface ContextMenuEvent extends BaseEvent { - coordinate: Coordinate; - pixel: Pixel; +export class ContextMenuEvent extends BaseEvent { + public coordinate: Coordinate; + public pixel: Pixel; + + constructor(options: { + type: `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`; + coordinate: Coordinate; + pixel: Pixel; + }) { + super(options.type); + this.pixel = options.pixel; + this.coordinate = options.coordinate; + } } export type CallbackObject = { diff --git a/test/instance.spec.ts b/test/instance.spec.ts index f1440bf..a20d307 100644 --- a/test/instance.spec.ts +++ b/test/instance.spec.ts @@ -1,6 +1,9 @@ +import OlMap from 'ol/Map'; +import BaseEvent from 'ol/events/Event'; + import { DEFAULT_ITEMS, DEFAULT_OPTIONS } from '../src/constants'; import ContextMenu from '../src/main'; -import { Item } from '../src/types'; +import { ContextMenuEvent, Item } from '../src/types'; const items: Item[] = [ '-', @@ -46,6 +49,11 @@ describe('Instance options', () => { describe('Instance methods', () => { const menu = new ContextMenu(); + // Add map to initialize the emitter + new OlMap({ + controls: [menu], + }); + test('getDefaultItems()', () => { expect(toJSON(menu.getDefaultItems())).toEqual(toJSON(DEFAULT_ITEMS)); }); @@ -103,3 +111,21 @@ describe('Throw errors', () => { }).toThrow(); }); }); + +// EVENTS +// The lines below are not a test per se, but as an ESLint indicator if the events are not correctly declared +const context = new ContextMenu(); + +context.on('beforeopen', (evt: ContextMenuEvent) => { + evt.pixel; + evt.coordinate; +}); + +context.on('open', (evt: ContextMenuEvent) => { + evt.pixel; + evt.coordinate; +}); + +context.on('close', (evt: BaseEvent) => { + evt.target; +}); diff --git a/vite.config.ts b/vite.config.ts index e199010..4dd404f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -9,9 +9,10 @@ import { CSS_CLASSES } from './src/constants'; const pkg = JSON.parse(readFileSync('./package.json', 'utf8')); // eslint-disable-next-line @typescript-eslint/no-shadow -const external = ['ol/control/Control', 'ol/PluggableMap', 'ol']; +const external = ['ol/control/Control', 'ol/events/Event', 'ol/PluggableMap', 'ol']; const globals = { 'ol/control/Control': 'ol.control.Control', + 'ol/events/Event': 'ol.events.Event', ol: 'ol', }; From 8d7d1ff1434838cde489d039b4c2b8fd157cfcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Tue, 18 Oct 2022 12:54:01 -0300 Subject: [PATCH 2/2] Improve ContextMenuEvent to extend MapBrowserEvent --- src/main.ts | 12 ++++++------ src/types.ts | 17 +++++------------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/main.ts b/src/main.ts index c36c243..3a2168a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -268,8 +268,8 @@ export default class ContextMenu extends Control { this.dispatchEvent( new ContextMenuEvent({ type: CustomEventTypes.BEFOREOPEN, - pixel: this.pixel, - coordinate: this.coordinate, + map: this.map, + originalEvent: evt }) ); @@ -281,7 +281,7 @@ export default class ContextMenu extends Control { } setTimeout(() => { - this.openMenu(); + this.openMenu(evt); }); evt.target?.addEventListener( @@ -296,7 +296,7 @@ export default class ContextMenu extends Control { ); } - protected openMenu() { + protected openMenu(evt: MouseEvent) { if (this.menuEntries.size === 0) return; this.opened = true; @@ -306,8 +306,8 @@ export default class ContextMenu extends Control { this.dispatchEvent( new ContextMenuEvent({ type: CustomEventTypes.OPEN, - pixel: this.pixel, - coordinate: this.coordinate, + map: this.map, + originalEvent: evt }) ); } diff --git a/src/types.ts b/src/types.ts index 1bb016c..62ece77 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,5 @@ import type { Coordinate } from 'ol/coordinate'; -import type { Pixel } from 'ol/pixel'; -import { Map as OlMap } from 'ol'; -import BaseEvent from 'ol/events/Event.js'; +import { Map as OlMap, MapBrowserEvent } from 'ol'; export enum EventTypes { CONTEXTMENU = 'contextmenu', @@ -16,18 +14,13 @@ export enum CustomEventTypes { ADD_MENU_ENTRY = 'add-menu-entry', } -export class ContextMenuEvent extends BaseEvent { - public coordinate: Coordinate; - public pixel: Pixel; - +export class ContextMenuEvent extends MapBrowserEvent { constructor(options: { type: `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`; - coordinate: Coordinate; - pixel: Pixel; + map: OlMap; + originalEvent: MouseEvent; }) { - super(options.type); - this.pixel = options.pixel; - this.coordinate = options.coordinate; + super(options.type, options.map, options.originalEvent); } }