ol-contextmenu 5.4.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,253 +1,223 @@
1
- # OpenLayers Custom Context Menu
1
+ # 🗺️ OpenLayers Context Menu
2
+
3
+ > A customizable, feature-rich context menu extension for OpenLayers maps
2
4
 
3
5
  <p align="center">
4
- <a href="https://github.com/jonataswalker/ol-contextmenu/actions/workflows/test.yml">
5
- <img src="https://github.com/jonataswalker/ol-contextmenu/actions/workflows/test.yml/badge.svg?branch=master" alt="Build Status">
6
+ <a href="https://github.com/jonataswalker/ol-contextmenu/actions/workflows/ci.yml">
7
+ <img src="https://github.com/jonataswalker/ol-contextmenu/actions/workflows/ci.yml/badge.svg?branch=master" alt="Build Status">
6
8
  </a>
7
9
  <a href="https://www.npmjs.com/package/ol-contextmenu">
8
10
  <img src="https://img.shields.io/npm/v/ol-contextmenu.svg" alt="npm version">
9
11
  </a>
10
12
  <a href="https://img.shields.io/npm/dm/ol-contextmenu">
11
- <img alt="npm" src="https://img.shields.io/npm/dm/ol-contextmenu">
13
+ <img alt="npm downloads" src="https://img.shields.io/npm/dm/ol-contextmenu">
12
14
  </a>
13
15
  <a href="https://github.com/jonataswalker/ol-contextmenu/blob/master/LICENSE">
14
- <img src="https://img.shields.io/npm/l/ol-contextmenu.svg" alt="license">
16
+ <img src="https://img.shields.io/npm/l/ol-contextmenu.svg" alt="MIT License">
15
17
  </a>
16
18
  </p>
17
19
 
18
- A `contextmenu` extension for [OpenLayers](http://openlayers.org/). **Requires** OpenLayers **v7.0.0** or higher.
19
-
20
- ![contextmenu anim](https://raw.githubusercontent.com/jonataswalker/ol-contextmenu/screenshot/images/anim.gif)
20
+ <p align="center">
21
+ <img src="https://raw.githubusercontent.com/jonataswalker/ol-contextmenu/screenshot/images/anim.gif" alt="Context Menu Demo" />
22
+ </p>
21
23
 
22
- ## Demo
24
+ **Quick Links:** [Demo](#-demo) • [Installation](#-installation) • [Quick Start](#-quick-start) • [API](#-api) • [TypeScript](#-typescript) • [Examples](#-examples)
23
25
 
24
- [JSFiddle](https://jsfiddle.net/jonataswalker/ooxs1w5d/)
25
- [CodeSandbox](https://codesandbox.io/s/openlayers-custom-context-menu-5s99kb?file=/src/index.js)
26
+ ---
26
27
 
27
- ## How to use it?
28
+ ## ✨ Features
28
29
 
29
- ##### NPM
30
+ - 🎯 **Easy Integration** - Works seamlessly with OpenLayers 7.x - 10.x
31
+ - 🎨 **Fully Customizable** - Control width, icons, styles, and appearance
32
+ - 🔗 **Nested Submenus** - Unlimited nesting levels for complex menu structures
33
+ - 📦 **Zero CSS Dependencies** - Styles are bundled inline (since v6.0)
34
+ - 🎪 **Event-Driven** - React to `beforeopen`, `open`, and `close` events
35
+ - 🌐 **Multiple Trigger Types** - Context menu, click, or double-click
36
+ - 📱 **Viewport-Aware** - Automatically repositions to stay visible at screen edges
37
+ - 💪 **TypeScript Support** - Full type definitions included out of the box
38
+ - ⚡ **Lightweight** - Minimal footprint with only one dependency (`tiny-emitter`)
39
+ - ✅ **Well Tested** - 191 tests covering all functionality
30
40
 
31
- `npm install ol-contextmenu`
41
+ ## 🎪 Demo
32
42
 
33
- ##### CDN Hosted - [jsDelivr](https://www.jsdelivr.com/package/npm/ol-contextmenu)
43
+ **Try it live:**
44
+ - 🎮 [CodeSandbox](https://codesandbox.io/s/openlayers-custom-context-menu-5s99kb?file=/src/index.js) - Interactive demo with full source
45
+ - 📝 [JSFiddle](https://jsfiddle.net/jonataswalker/ooxs1w5d/) - Quick playground
46
+ - 💻 [Local Examples](./examples) - Webpack, Vite, and CDN examples
34
47
 
35
- Load CSS and Javascript:
48
+ ## 📦 Installation
36
49
 
37
- ```HTML
38
- <link href="https://cdn.jsdelivr.net/npm/ol-contextmenu@latest/dist/ol-contextmenu.css" rel="stylesheet">
39
- <script src="https://cdn.jsdelivr.net/npm/ol-contextmenu"></script>
50
+ **npm (Recommended):**
51
+ ```bash
52
+ npm install ol ol-contextmenu
40
53
  ```
41
54
 
42
- ##### CDN Hosted - UNPKG
43
-
44
- Load CSS and Javascript:
45
-
46
- ```HTML
47
- <link href="https://unpkg.com/ol-contextmenu/dist/ol-contextmenu.css" rel="stylesheet">
48
- <script src="https://unpkg.com/ol-contextmenu"></script>
55
+ **CDN:**
56
+ ```html
57
+ <script src="https://cdn.jsdelivr.net/npm/ol-contextmenu"></script>
49
58
  ```
50
59
 
51
- ##### Self hosted
60
+ **Requires:** OpenLayers 7.0.0 or higher
52
61
 
53
- Download [latest release](https://github.com/jonataswalker/ol-contextmenu/releases/latest) and (obviously) load CSS and Javascript.
62
+ 📖 See [Getting Started Guide](docs/getting-started.md) for detailed installation instructions and setup.
54
63
 
55
- ##### Instantiate with some options and add the Control
64
+ ## 🚀 Quick Start
56
65
 
57
66
  ```javascript
67
+ import ContextMenu from 'ol-contextmenu';
68
+
58
69
  const contextmenu = new ContextMenu({
59
70
  width: 170,
60
- defaultItems: true, // defaultItems are (for now) Zoom In/Zoom Out
71
+ defaultItems: true, // Includes Zoom In/Zoom Out
61
72
  items: [
62
73
  {
63
74
  text: 'Center map here',
64
- classname: 'some-style-class', // add some CSS rules
65
- callback: center, // `center` is your callback function
75
+ callback: (obj, map) => {
76
+ map.getView().setCenter(obj.coordinate);
77
+ },
66
78
  },
67
79
  {
68
80
  text: 'Add a Marker',
69
- classname: 'some-style-class', // you can add this icon with a CSS class
70
- // instead of `icon` property (see next line)
71
- icon: 'img/marker.png', // this can be relative or absolute
72
- callback: marker,
81
+ icon: 'img/marker.png',
82
+ callback: addMarker,
73
83
  },
74
- '-', // this is a separator
84
+ '-', // Separator
75
85
  ],
76
86
  });
87
+
77
88
  map.addControl(contextmenu);
78
89
  ```
79
90
 
80
- ##### You can add a (nested) submenu like this:
81
-
82
- If you provide `items {Array}` a submenu will be created as a child of the current item.
91
+ 📖 See [Getting Started Guide](docs/getting-started.md) for complete setup instructions and [Examples](docs/examples.md) for advanced patterns.
83
92
 
84
- ```javascript
85
- const all_items = [
86
- {
87
- text: 'Some Actions',
88
- items: [
89
- // <== this is a submenu
90
- {
91
- text: 'Action 1',
92
- callback: action,
93
- },
94
- {
95
- text: 'Other action',
96
- callback: action2,
97
- },
98
- ],
99
- },
100
- {
101
- text: 'Add a Marker',
102
- icon: 'img/marker.png',
103
- callback: marker,
104
- },
105
- '-', // this is a separator
106
- ];
107
- ```
93
+ ## 📖 Documentation
108
94
 
109
- ##### Would you like to propagate custom data to the callback handler?
95
+ - **[Getting Started](docs/getting-started.md)** - Installation and basic setup
96
+ - **[API Reference](docs/api-reference.md)** - Complete API documentation
97
+ - **[TypeScript Guide](docs/typescript.md)** - TypeScript usage and type definitions
98
+ - **[Examples & Recipes](docs/examples.md)** - Common patterns and code examples
99
+ - **[Troubleshooting](docs/troubleshooting.md)** - Common issues and solutions
110
100
 
111
- ```javascript
112
- const removeMarker = function (obj) {
113
- vectorLayer.getSource().removeFeature(obj.data.marker);
114
- };
115
- const removeMarkerItem = {
116
- text: 'Remove this Marker',
117
- icon: 'img/marker.png',
118
- callback: removeMarker,
119
- };
120
-
121
- let restore = false;
122
- contextmenu.on('open', function (evt) {
123
- const feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {
124
- return ft;
125
- });
126
- if (feature) {
127
- contextmenu.clear();
128
- removeMarkerItem.data = { marker: feature };
129
- contextmenu.push(removeMarkerItem);
130
- restore = true;
131
- } else if (restore) {
132
- contextmenu.clear();
133
- contextmenu.extend(contextmenu_items);
134
- contextmenu.extend(contextmenu.getDefaultItems());
135
- restore = false;
136
- }
137
- });
138
- ```
101
+ ## 📘 TypeScript
139
102
 
140
- # API
103
+ Full TypeScript support with comprehensive type definitions included:
141
104
 
142
- ## Constructor
105
+ ```typescript
106
+ import ContextMenu, { type Item } from 'ol-contextmenu';
143
107
 
144
- #### `new ContextMenu(options)`
108
+ const items: Item[] = [
109
+ {
110
+ text: 'Center map here',
111
+ callback: (obj, map) => {
112
+ map.getView().setCenter(obj.coordinate);
113
+ },
114
+ },
115
+ ];
145
116
 
146
- ###### `options` is an object with the following possible properties:
117
+ const contextmenu = new ContextMenu({ width: 170, items });
118
+ ```
147
119
 
148
- - `eventType`: `contextmenu`; The listening event type (You could use `'click'`, `'dblclick'`)
149
- - `defaultItems`: `true`; Whether the default items (which are: Zoom In/Out) are enabled
150
- - `width`: `150`; The menu's width
151
- - `items`: `[]`; An array of object|string
120
+ 📖 See the [TypeScript Guide](docs/typescript.md) for complete type definitions and usage patterns.
152
121
 
153
- ## Methods
122
+ ## 🎯 API
154
123
 
155
- #### contextmenu.clear()
124
+ ### Constructor
156
125
 
157
- Remove all elements from the menu.
126
+ ```javascript
127
+ new ContextMenu(options)
128
+ ```
158
129
 
159
- #### contextmenu.close()
130
+ **Options:**
131
+ - `width` (number, default: `150`) - Menu width in pixels
132
+ - `defaultItems` (boolean, default: `true`) - Include default Zoom In/Out items
133
+ - `items` (Item[], default: `[]`) - Array of menu items
134
+ - `eventType` (string, default: `'contextmenu'`) - Event type to trigger menu
160
135
 
161
- Close the menu programmatically.
136
+ ### Methods
162
137
 
163
- #### contextmenu.extend(arr)
138
+ - `clear()` - Remove all items
139
+ - `close()` - Close menu programmatically
140
+ - `extend(items)` - Add multiple items
141
+ - `push(item)` - Add single item
142
+ - `pop()` / `shift()` - Remove items
143
+ - `getDefaultItems()` - Get default items array
144
+ - `isOpen()` - Check if menu is open
145
+ - `enable()` / `disable()` - Control menu state
164
146
 
165
- `@param {Array} arr`
147
+ ### Events
166
148
 
167
- Add items to the menu. This pushes each item in the provided array to the end of the menu.
149
+ - `beforeopen` - Fired before menu opens
150
+ - `open` - Fired when menu opens
151
+ - `close` - Fired when menu closes
168
152
 
169
- Example:
153
+ 📖 See [API Reference](docs/api-reference.md) for complete documentation with examples.
170
154
 
171
- ```js
172
- const contextmenu = new ContextMenu();
173
- map.addControl(contextmenu);
155
+ ## 🎨 Examples
174
156
 
175
- const add_later = [
176
- '-', // this is a separator
177
- {
178
- text: 'Add a Marker',
179
- icon: 'img/marker.png',
180
- callback: marker,
181
- },
182
- ];
183
- contextmenu.extend(add_later);
184
- ```
157
+ - **[Examples & Recipes](docs/examples.md)** - Common patterns and code examples
158
+ - **[Local Examples](./examples)** - Complete working projects:
159
+ - [CDN Example](./examples/contextmenu.html) - No build tools required
160
+ - [Webpack Example](./examples/my-project-with-webpack) - Integration with Webpack
161
+ - [Vite Example](./examples/my-project-with-vite) - Modern setup with Vite + TypeScript
185
162
 
186
- #### contextmenu.push(item)
163
+ ## 🔧 Troubleshooting
187
164
 
188
- `@param {Object|String} item`
165
+ Common issues:
166
+ - **Menu doesn't appear:** Ensure `map.addControl(contextmenu)` is called
167
+ - **Menu cut off:** Update to v5.5.0+ for automatic viewport positioning
168
+ - **TypeScript errors:** Use `import ContextMenu, { type Item } from 'ol-contextmenu'`
189
169
 
190
- Insert the provided item at the end of the menu.
170
+ 📖 See the [Troubleshooting Guide](docs/troubleshooting.md) for detailed solutions and common issues.
191
171
 
192
- #### contextmenu.shift()
172
+ ## 🌍 Browser Support
193
173
 
194
- Remove the first item of the menu.
174
+ Modern browsers supporting ES6+:
175
+ - Chrome/Edge (latest)
176
+ - Firefox (latest)
177
+ - Safari (latest)
195
178
 
196
- #### contextmenu.pop()
179
+ ## 🤝 Contributing
197
180
 
198
- Remove the last item of the menu.
181
+ Contributions are welcome! We appreciate:
182
+ - 🐛 Bug reports
183
+ - 💡 Feature requests
184
+ - 📝 Documentation improvements
185
+ - ✨ Code contributions
199
186
 
200
- #### contextmenu.getDefaultItems()
187
+ Please read our [Contributing Guidelines](CONTRIBUTING.md) before submitting a PR.
201
188
 
202
- Get an array of default items.
189
+ ### Development Setup
203
190
 
204
- #### contextmenu.isOpen()
191
+ ```bash
192
+ # Clone the repository
193
+ git clone https://github.com/jonataswalker/ol-contextmenu.git
194
+ cd ol-contextmenu
205
195
 
206
- Whether the menu is open.
196
+ # Install dependencies
197
+ npm install
207
198
 
208
- #### contextmenu.updatePosition(pixel)
199
+ # Run tests
200
+ npm test
209
201
 
210
- `@param {Array} pixel`
202
+ # Start development server
203
+ npm run dev
211
204
 
212
- Update menu's position.
205
+ # Build for production
206
+ npm run build
207
+ ```
213
208
 
214
- ## Events
209
+ ## 📄 License
215
210
 
216
- #### If you want to disable this plugin under certain circumstances, listen to `beforeopen`
211
+ MIT © [Jonatas Walker](https://github.com/jonataswalker)
217
212
 
218
- ```javascript
219
- contextmenu.on('beforeopen', function (evt) {
220
- const feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {
221
- return ft;
222
- });
223
-
224
- if (feature) {
225
- // open only on features
226
- contextmenu.enable();
227
- } else {
228
- contextmenu.disable();
229
- }
230
- });
231
- ```
213
+ ## 🙏 Acknowledgments
232
214
 
233
- #### Listen and make some changes when context menu opens
215
+ Built with ❤️ for the [OpenLayers](https://openlayers.org/) community.
234
216
 
235
- ```javascript
236
- contextmenu.on('open', function (evt) {
237
- const feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {
238
- return ft;
239
- });
240
-
241
- if (feature) {
242
- // add some other items to the menu
243
- }
244
- });
245
- ```
217
+ Special thanks to all [contributors](https://github.com/jonataswalker/ol-contextmenu/graphs/contributors) who have helped improve this project.
246
218
 
247
- #### Any action when context menu gets closed?
219
+ ---
248
220
 
249
- ```javascript
250
- contextmenu.on('close', function (evt) {
251
- // it's upon you
252
- });
253
- ```
221
+ <p align="center">
222
+ <sub>Made with ❤️ by the community</sub>
223
+ </p>
@@ -1,3 +1,136 @@
1
- export * from './main'
2
- import ContextMenu from './main'
3
- export default ContextMenu
1
+ import { CombinedOnSignature } from 'ol/Observable';
2
+ import { Coordinate } from 'ol/coordinate';
3
+ import { default as default_2 } from 'ol/control/Control';
4
+ import { default as default_3 } from 'ol/Map';
5
+ import { default as default_4 } from 'ol/events/Event';
6
+ import { default as default_5 } from 'ol/MapBrowserEvent';
7
+ import { EventsKey } from 'ol/events';
8
+ import { EventTypes as EventTypes_2 } from 'ol/Observable';
9
+ import { ObjectEvent } from 'ol/Object';
10
+ import { OnSignature } from 'ol/Observable';
11
+ import { Pixel } from 'ol/pixel';
12
+ import { TinyEmitter } from 'tiny-emitter';
13
+ import { Types } from 'ol/ObjectEventType';
14
+
15
+ export declare type CallbackObject = {
16
+ coordinate: Coordinate;
17
+ data: unknown;
18
+ };
19
+
20
+ declare class ContextMenu extends default_2 {
21
+ protected map: default_3;
22
+ protected emitter: TinyEmitter;
23
+ protected container: HTMLDivElement;
24
+ protected coordinate: Coordinate;
25
+ protected pixel: Pixel;
26
+ protected contextMenuEventListener: (evt: MouseEvent) => void;
27
+ protected entryCallbackEventListener: (evt: MouseEvent) => void;
28
+ protected mapMoveListener: () => void;
29
+ protected lineHeight: number;
30
+ protected disabled: boolean;
31
+ protected opened: boolean;
32
+ protected items: Item[];
33
+ protected menuEntries: Map<string, MenuEntry>;
34
+ on: OnSignature<EventTypes_2 | `${CustomEventTypes.CLOSE}`, default_4, EventsKey> & OnSignature<`${CustomEventTypes.OPEN}` | `${CustomEventTypes.BEFOREOPEN}`, ContextMenuEvent, EventsKey> & OnSignature<Types, ObjectEvent, EventsKey> & CombinedOnSignature<EventTypes_2 | Types | `${CustomEventTypes.OPEN}` | `${CustomEventTypes.CLOSE}` | `${CustomEventTypes.BEFOREOPEN}`, EventsKey>;
35
+ once: OnSignature<EventTypes_2 | `${CustomEventTypes.CLOSE}`, default_4, EventsKey> & OnSignature<`${CustomEventTypes.OPEN}` | `${CustomEventTypes.BEFOREOPEN}`, ContextMenuEvent, EventsKey> & OnSignature<Types, ObjectEvent, EventsKey> & CombinedOnSignature<EventTypes_2 | Types | `${CustomEventTypes.OPEN}` | `${CustomEventTypes.CLOSE}` | `${CustomEventTypes.BEFOREOPEN}`, EventsKey>;
36
+ un: OnSignature<EventTypes_2 | `${CustomEventTypes.CLOSE}`, default_4, void> & OnSignature<`${CustomEventTypes.OPEN}` | `${CustomEventTypes.BEFOREOPEN}`, ContextMenuEvent, EventsKey> & OnSignature<Types, ObjectEvent, void> & CombinedOnSignature<EventTypes_2 | Types | `${CustomEventTypes.OPEN}` | `${CustomEventTypes.CLOSE}` | `${CustomEventTypes.BEFOREOPEN}`, void>;
37
+ options: Options;
38
+ constructor(opts?: Partial<Options>);
39
+ clear(): void;
40
+ enable(): void;
41
+ disable(): void;
42
+ getDefaultItems(): SingleItem[];
43
+ countItems(): number;
44
+ extend(items: Item[]): void;
45
+ closeMenu(): void;
46
+ isOpen(): boolean;
47
+ updatePosition(pixel: Pixel): void;
48
+ pop(): void;
49
+ shift(): void;
50
+ push(item: Item): void;
51
+ setMap(map: default_3): void;
52
+ protected removeListeners(): void;
53
+ protected removeMenuEntry(id: string): void;
54
+ protected handleContextMenu(evt: MouseEvent): void;
55
+ protected openMenu(evt: MouseEvent): void;
56
+ protected getMenuEntriesLength(): number;
57
+ protected calculateMenuSize(): {
58
+ h: number;
59
+ w: number;
60
+ };
61
+ protected calculateVerticalPosition(mapSize: [number, number], spaceLeft: {
62
+ h: number;
63
+ w: number;
64
+ }, menuSize: {
65
+ h: number;
66
+ w: number;
67
+ }): number;
68
+ protected adjustPositionAfterRender(mapSize: [number, number], menuSize: {
69
+ h: number;
70
+ w: number;
71
+ }): void;
72
+ protected positionContainer(): void;
73
+ protected handleMapMove(): void;
74
+ protected handleEntryCallback(evt: MouseEvent): void;
75
+ protected handleAddMenuEntry(item: MenuEntry, element: HTMLLIElement): void;
76
+ }
77
+ export default ContextMenu;
78
+
79
+ export declare class ContextMenuEvent extends default_5<any> {
80
+ constructor(options: {
81
+ map: default_3;
82
+ originalEvent: MouseEvent | PointerEvent;
83
+ type: `${CustomEventTypes.OPEN}` | `${CustomEventTypes.BEFOREOPEN}`;
84
+ });
85
+ }
86
+
87
+ export declare enum CustomEventTypes {
88
+ BEFOREOPEN = "beforeopen",
89
+ OPEN = "open",
90
+ CLOSE = "close",
91
+ ADD_MENU_ENTRY = "add-menu-entry"
92
+ }
93
+
94
+ export declare enum EventTypes {
95
+ CONTEXTMENU = "contextmenu",
96
+ CLICK = "click",
97
+ DBLCLICK = "dblclick"
98
+ }
99
+
100
+ export declare type Item = SingleItem | ItemSeparator | ItemWithNested;
101
+
102
+ export declare type ItemSeparator = '-';
103
+
104
+ export declare type ItemWithNested = {
105
+ classname?: string;
106
+ icon?: string;
107
+ items: Item[];
108
+ text: string;
109
+ };
110
+
111
+ export declare type MenuEntry = {
112
+ callback: null | SingleItem['callback'];
113
+ data: unknown;
114
+ id: string;
115
+ isInsideSubmenu: boolean;
116
+ isSeparator: boolean;
117
+ isSubmenu: boolean;
118
+ };
119
+
120
+ export declare type Options = {
121
+ defaultItems: boolean;
122
+ eventType: `${EventTypes}`;
123
+ items: Item[];
124
+ scrollAt: number;
125
+ width: number;
126
+ };
127
+
128
+ export declare type SingleItem = {
129
+ callback: (object: CallbackObject, map: default_3) => void;
130
+ classname?: string;
131
+ data?: unknown;
132
+ icon?: string;
133
+ text: string;
134
+ };
135
+
136
+ export { }
@@ -1,8 +1,9 @@
1
1
 
2
2
  /*!
3
- * ol-contextmenu - v5.4.0
3
+ * ol-contextmenu - v6.0.0
4
4
  * https://github.com/jonataswalker/ol-contextmenu
5
- * Built: Fri Mar 08 2024 12:11:47 GMT+0000 (Coordinated Universal Time)
5
+ * Built: 2026-01-05T22:44:21.378Z
6
6
  */
7
7
 
8
- var ContextMenu=function(E,h){"use strict";var P=Object.defineProperty;var H=(E,h,d)=>h in E?P(E,h,{enumerable:!0,configurable:!0,writable:!0,value:d}):E[h]=d;var a=(E,h,d)=>(H(E,typeof h!="symbol"?h+"":h,d),d);var d={exports:{}};function x(){}x.prototype={on:function(s,t,e){var n=this.e||(this.e={});return(n[s]||(n[s]=[])).push({fn:t,ctx:e}),this},once:function(s,t,e){var n=this;function o(){n.off(s,o),t.apply(e,arguments)}return o._=t,this.on(s,o,e)},emit:function(s){var t=[].slice.call(arguments,1),e=((this.e||(this.e={}))[s]||[]).slice(),n=0,o=e.length;for(n;n<o;n++)e[n].fn.apply(e[n].ctx,t);return this},off:function(s,t){var e=this.e||(this.e={}),n=e[s],o=[];if(n&&t)for(var i=0,l=n.length;i<l;i++)n[i].fn!==t&&n[i].fn._!==t&&o.push(n[i]);return o.length?e[s]=o:delete e[s],this}},d.exports=x;var T=d.exports.TinyEmitter=x,L=(s=>(s.CONTEXTMENU="contextmenu",s.CLICK="click",s.DBLCLICK="dblclick",s))(L||{}),p=(s=>(s.BEFOREOPEN="beforeopen",s.OPEN="open",s.CLOSE="close",s.ADD_MENU_ENTRY="add-menu-entry",s))(p||{});class S extends h{constructor(t){super(t.type,t.map,t.originalEvent)}}const k={width:150,scrollAt:4,eventType:L.CONTEXTMENU,defaultItems:!0,items:[]},m="ol-ctx-menu",r={namespace:m,container:`${m}-container`,separator:`${m}-separator`,submenu:`${m}-submenu`,hidden:`${m}-hidden`,icon:`${m}-icon`,zoomIn:`${m}-zoom-in`,zoomOut:`${m}-zoom-out`,unselectable:"ol-unselectable"},A=[{text:"Zoom In",classname:`${r.zoomIn} ${r.icon}`,callback:(s,t)=>{const e=t.getView();e.animate({zoom:Number(e.getZoom())+1,duration:700,center:s.coordinate})}},{text:"Zoom Out",classname:`${r.zoomOut} ${r.icon}`,callback:(s,t)=>{const e=t.getView();e.animate({zoom:Number(e.getZoom())-1,duration:700,center:s.coordinate})}}];function b(s){const t=document.createDocumentFragment(),e=document.createElement("div");for(e.innerHTML=s;e.firstChild;)t.append(e.firstChild);return t}function I(s){const t=document.importNode(s),e=s.offsetWidth;t.style.cssText=`position: fixed; top: 0; left: 0; overflow: auto; visibility: hidden; pointer-events: none; height: unset; max-height: unset; width: ${e}px`;const n=b("<span>Foo</span>"),o=b("<span>Foo</span>"),i=document.createElement("li"),l=document.createElement("li");i.append(n),l.append(o),t.append(i),t.append(l),s.parentNode?.append(t);const c=t.offsetHeight/2;return s.parentNode?.removeChild(t),c}function $({parentNode:s,item:t,isSubmenu:e=!1,isInsideSubmenu:n=!1,emitter:o}){const i=`_${Math.random().toString(36).slice(2,11)}`;if(typeof t!="string"&&"text"in t){const v=`<span>${t.text}</span>`,g=b(v),f=document.createElement("li");t.classname=t.classname||"",t.icon&&(t.classname===""?t.classname=r.icon:t.classname.includes(r.icon)===!1&&(t.classname+=` ${r.icon}`),f.setAttribute("style",`background-image:url(${t.icon})`)),f.id=i,f.className=t.classname,f.append(g),s.append(f);const N={id:i,isSubmenu:e,isInsideSubmenu:n,isSeparator:!1,callback:"callback"in t?t.callback:null,data:"data"in t?t.data:null};return o.emit(p.ADD_MENU_ENTRY,N,f),f}const l=`<li id="${i}" class="${r.separator}"><hr></li>`,c=b(l);s.append(c);const y=s.lastChild,M={id:i,isSubmenu:!1,isInsideSubmenu:!1,isSeparator:!0,callback:null,data:null};return o.emit(p.ADD_MENU_ENTRY,M,y),y}function w({container:s,items:t,menuWidth:e,isInsideSubmenu:n,emitter:o}){t.forEach(i=>{if(typeof i!="string"&&"items"in i&&Array.isArray(i.items)){const l=$({parentNode:s,item:i,isSubmenu:!0,emitter:o});l.classList.add(r.submenu);const c=document.createElement("ul");c.classList.add(r.container),c.style.width=`${e}px`,l.append(c),w({emitter:o,menuWidth:e,container:c,items:i.items,isInsideSubmenu:!0})}else $({parentNode:s,item:i,isSubmenu:!1,isInsideSubmenu:n,emitter:o})})}function C(s,t){if(!s)throw new Error(t)}class O extends E{constructor(e={}){C(typeof e=="object","@param `opts` should be object type!");const n=document.createElement("div");super({element:n});a(this,"map");a(this,"emitter",new T);a(this,"container");a(this,"coordinate",[]);a(this,"pixel",[]);a(this,"contextMenuEventListener");a(this,"entryCallbackEventListener");a(this,"mapMoveListener");a(this,"lineHeight",0);a(this,"disabled");a(this,"opened");a(this,"items",[]);a(this,"menuEntries",new Map);a(this,"options");this.options={...k,...e};const o=document.createElement("ul");n.append(o),n.style.width=`${this.options.width}px`,n.classList.add(r.container,r.unselectable,r.hidden),this.container=n,this.contextMenuEventListener=i=>{this.handleContextMenu(i)},this.entryCallbackEventListener=i=>{this.handleEntryCallback(i)},this.mapMoveListener=()=>{this.handleMapMove()},this.disabled=!1,this.opened=!1,window.addEventListener("beforeunload",()=>{this.removeListeners()},{once:!0})}clear(){for(const e of this.menuEntries.keys())this.removeMenuEntry(e);this.container.replaceChildren(),this.container.append(document.createElement("ul"))}enable(){this.disabled=!1}disable(){this.disabled=!0}getDefaultItems(){return A}countItems(){return this.menuEntries.size}extend(e){C(Array.isArray(e),"@param `items` should be an Array."),w({items:e,emitter:this.emitter,menuWidth:this.options.width,container:this.container.firstElementChild})}closeMenu(){this.opened=!1,this.container.classList.add(r.hidden),this.dispatchEvent(p.CLOSE)}isOpen(){return this.opened}updatePosition(e){C(Array.isArray(e),"@param `pixel` should be an Array."),this.isOpen()&&(this.pixel=e,this.positionContainer())}pop(){const e=Array.from(this.menuEntries.keys()).pop();e&&this.removeMenuEntry(e)}shift(){const e=Array.from(this.menuEntries.keys()).shift();e&&this.removeMenuEntry(e)}push(e){e&&this.extend([e])}setMap(e){if(super.setMap(e),e){this.map=e,e.getViewport().addEventListener(this.options.eventType,this.contextMenuEventListener,!1),e.on("movestart",()=>{this.handleMapMove()}),this.emitter.on(p.ADD_MENU_ENTRY,(o,i)=>{this.handleAddMenuEntry(o,i)},this),this.items=this.options.defaultItems?this.options.items.concat(A):this.options.items,w({items:this.items,emitter:this.emitter,menuWidth:this.options.width,container:this.container.firstElementChild});const n=this.getMenuEntriesLength();this.lineHeight=n>0?this.container.offsetHeight/n:I(this.container)}else this.removeListeners(),this.clear()}removeListeners(){this.map.getViewport().removeEventListener(this.options.eventType,this.contextMenuEventListener,!1),this.emitter.off(p.ADD_MENU_ENTRY)}removeMenuEntry(e){let n=document.getElementById(e);n?.remove(),n=null,this.menuEntries.delete(e)}handleContextMenu(e){this.coordinate=this.map.getEventCoordinate(e),this.pixel=this.map.getEventPixel(e),this.dispatchEvent(new S({map:this.map,originalEvent:e,type:p.BEFOREOPEN})),!this.disabled&&(this.options.eventType===L.CONTEXTMENU&&(e.stopPropagation(),e.preventDefault()),setTimeout(()=>{this.openMenu(e)}),e.target?.addEventListener("pointerdown",n=>{this.opened&&(n.stopPropagation(),this.closeMenu())},{once:!0}))}openMenu(e){this.opened=!0,this.positionContainer(),this.container.classList.remove(r.hidden),this.dispatchEvent(new S({map:this.map,originalEvent:e,type:p.OPEN}))}getMenuEntriesLength(){return Array.from(this.menuEntries).filter(([,e])=>e.isSeparator===!1&&e.isSubmenu===!1&&e.isInsideSubmenu===!1).length}positionContainer(){const e=this.map.getSize()||[0,0],n={w:e[0]-this.pixel[0],h:e[1]-this.pixel[1]},o=this.getMenuEntriesLength(),i={w:this.container.offsetWidth,h:Math.round(this.lineHeight*o)},l=n.w>=i.w?this.pixel[0]+5:this.pixel[0]-i.w;this.container.style.left=`${l}px`,this.container.style.top=n.h>=i.h?`${this.pixel[1]-10}px`:`${this.pixel[1]-i.h}px`,this.container.style.right="auto",this.container.style.bottom="auto",n.w-=i.w;const c=v=>Array.from(v.children).filter(g=>g.tagName==="LI"&&g.classList.contains(r.submenu));let y=0;const M=(v,g)=>{y+=1,c(v).forEach(N=>{const D=g>=i.w?i.w-8:(i.w+8)*-1,u=N.querySelector(`ul.${r.container}`),_=Math.round(this.lineHeight*Array.from(u.children).filter(z=>z.tagName==="LI").length);u.style.left=`${D}px`,u.style.right="auto",u.style.top=n.h>=_+i.h?"0":`-${u.offsetHeight-25}px`,u.style.bottom="auto",u.style.zIndex=String(y),c(u).length>0&&M(u,g-i.w)})};M(this.container.firstElementChild,n.w)}handleMapMove(){this.closeMenu()}handleEntryCallback(e){e.preventDefault(),e.stopPropagation();const n=e.currentTarget,o=this.menuEntries.get(n.id);if(!o)return;const i={data:o.data,coordinate:this.coordinate};this.closeMenu(),o.callback?.(i,this.map)}handleAddMenuEntry(e,n){this.menuEntries.set(e.id,e),this.positionContainer(),"callback"in e&&typeof e.callback=="function"&&n.addEventListener("click",this.entryCallbackEventListener,!1)}}return O}(ol.control.Control,ol.MapBrowserEvent);
8
+ (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode('.ol-ctx-menu-container{position:absolute;padding:8px;background:#fff;color:#222;font-size:13px;border-radius:5px;box-shadow:#0003 3px 3px 5px;box-sizing:border-box}.ol-ctx-menu-container div,.ol-ctx-menu-container span,.ol-ctx-menu-container a,.ol-ctx-menu-container img,.ol-ctx-menu-container ul,.ol-ctx-menu-container li{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}.ol-ctx-menu-container a img{border:none}.ol-ctx-menu-container *,.ol-ctx-menu-container *:before,.ol-ctx-menu-container *:after{box-sizing:inherit}.ol-ctx-menu-container.ol-ctx-menu-hidden{opacity:0;visibility:hidden;transition:visibility 0s linear .3s,opacity .3s}.ol-ctx-menu-container ul{list-style:none}.ol-ctx-menu-container li{position:relative;line-height:20px;padding:2px 5px;white-space:nowrap}.ol-ctx-menu-container li:not(.ol-ctx-menu-separator):hover{cursor:pointer;background-color:#333;color:#eee}.ol-ctx-menu-container li.ol-ctx-menu-submenu .ol-ctx-menu-container{border:1px solid #eee;padding:8px;top:0;opacity:0;visibility:hidden;transition:visibility 0s linear .3s,opacity .3s}.ol-ctx-menu-container li.ol-ctx-menu-submenu:after{position:absolute;top:7px;right:10px;content:"";display:inline-block;width:.6em;height:.6em;border-right:.3em solid #222;border-top:.3em solid #222;transform:rotate(45deg)}.ol-ctx-menu-container li.ol-ctx-menu-submenu:hover:after{border-color:#eee}.ol-ctx-menu-container:not(.ol-ctx-menu-hidden) li.ol-ctx-menu-submenu:hover>.ol-ctx-menu-container{opacity:1;visibility:visible;transition-delay:0s}.ol-ctx-menu-container li.ol-ctx-menu-separator{padding:0}.ol-ctx-menu-container li.ol-ctx-menu-separator hr{border:0;height:1px;background-image:linear-gradient(to left,#0000,#000000bf,#0000)}.ol-ctx-menu-icon{text-indent:20px;background-size:20px auto;background-repeat:no-repeat;background-position:left center}.ol-ctx-menu-zoom-in{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABaUlEQVQ4T72U7VHCQBCGn90GtAMuNGCswFiBWIFQgWMFxg6wArECsQKhArEBiB1Qwa1zgQn5IAYcxv13k71n3919L8KJQ07M47+BzgG9TRfZ/JBuWhS6BJFHRJICYrZGZIz3z5Ct2+B7gG6I6kt+wewdkQVwjtkAkR5mC8yu26A1oItR/cTsOweQBdgutD8G7jGm2PJ2n8oqUKIpIjd4HxTM8gvaT/F+AlmWnyWaIXKF95eNguFzTYFhNsdWu9kFgFlaFMANUH3D8wDLoLgSTSD2il8NCe2ZXQBxWDGwxmyUzzOMBZ7wy7Qb2K0wQfXjMOBuhlFpZtNty5sFaTQBuTusZdymeqs1SpYKcO9HkE3KbTd9WFijMHJQ5hBNEAYNq5Qd0dhyke0GiE4QzjqfW23mHT8Hl4DG4Lce3FPE7AtbBSdsbNqpoJLgYkRnNeUV+xwJDHTnUEkxHGbhBXUs5TjJjew/KPy94g+NRaIVRYmMXwAAAABJRU5ErkJggg==)}.ol-ctx-menu-container li:hover.ol-ctx-menu-zoom-in{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABc0lEQVQ4T71U21ECQRDsJgGdvQDECMQIxAjECMQILCPwzAAjECIQI0AiEDPQAPaWCBhrcKHuCUcV5f7dY3v6tUscefHIePhfwBBCF8CZqRCReRs1tQxDCH1VfQLQz4EsSY4AvIjIsgm8AhhCGKrqa9zwrqoLAKckB5HtguR1E2gBMITQU9VPAD8GICIGtl3e+xHJBwBT59xtHcsCYJZlUwA3kcGHbfDep51OZywi3/acZZm9vyJ5WR5o38uACmDunNt6ZwAkUxFZDwghDFT1jeSjiJinhVUBVNVJkiTDKO8CQA+AsbNQ7s1Ps0VVn5MkSfcCtmBoDZi1Bdx4eJ7zbBolrwPy3o9J3rWSHPs3A1BbjVKlYBaIyDgvu9LDXDU2RTZmXVW1oKyLxRD+OrkOrJLy5mVM0iaftDhuhVbsvBzMglzKUNW6IV/OOWtCM8MmVvEkmbwt83LaB19fdgOtVquUZJeknaDdobTwbOcvBzPcN/AXH1DFFWP7u9oAAAAASUVORK5CYII=)}.ol-ctx-menu-zoom-out{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABU0lEQVQ4T72U7VECMRRFz3sNaAdkacC1AtcKxApcKnCsQOwAK3CtQKxAqEBsANYOqCDPyTIC+8WCw5jfybn33dxEOPGSE/P4b6BzQG89RT47ZJoWhy5B5BGRZAMxWyEyxvtnyFdt8AagS1F9KQ6YvSMyB84xGyDSw2yO2XUbtAJ0MaqfmH0XAPIA2y7tj4F7jAm2uG1yWQZKNEHkBu+Dg2njWBJNEbnC+8uaIFRuWfuG2QxbbrOrUd0A1Tc8D7AIjkur7DAAsVf8MiWMZ3ZR2m02LPIMscATfjHqBnY7TFD9OAy4zTCCPG/MUKMM5O6wkXFr9dZq7FQqqHk/hDzbFa73cFONTZFDdRyiCcKg5rrSiLaXkiI6RjjrfG6VzDs+B5eAxuDXeYpmNRGzL2wZ/wof+du4GNFpBVqqz5HA4MM5VEYYDrOs+1I6Q9u/4Q8O9wN/AGgWjBVqQjjgAAAAAElFTkSuQmCC)}.ol-ctx-menu-container li:hover.ol-ctx-menu-zoom-out{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABYklEQVQ4T72U4VHCQBCF36tA91KAWIFYgViBWIFYgWMFYgdYgVCBWAFSgdiBFpAsFWSdxcDkQoBkhnF/ZjbfvX377ogjF4/Mw/8CVbUD4MynEJF5k2lqFapqz8yeAPRKkCXJEYAXEVnugm8BVXVgZq/FD+9mtgBwSrJfqF2QvN4FjYCq2jWzTwA/DhARh20qTdMRyQcA0xDCbZ3KCJhl2RTATaHgo+6HLMv8+xXJy+qB3l8FGoB5CKHsXcRV1b6ZvZF8FBH3NKotoJlNkiQZFONdlLtJ3rufbouZPSdJMjwIbKDQEzBrClx7eC4i33Uepmk6JnnXaOQifzMAtdGoRApugYiMI1uqKkrRWAfZo9MxM1+UZzFewl8mN4nYdVM83L7BkwbXLUrF3sfBLQDQBbDy08x8vOohXyEE71lVq9emuEk+3gZa3XYroCvwFyjP8yHJDsnxwaU08GxvS2uFhw78BbzWrxXgMbsHAAAAAElFTkSuQmCC)}')),document.head.appendChild(e)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})();
9
+ var ContextMenu=(function(m,u){"use strict";var B=Object.defineProperty;var j=(m,u,d)=>u in m?B(m,u,{enumerable:!0,configurable:!0,writable:!0,value:d}):m[u]=d;var c=(m,u,d)=>j(m,typeof u!="symbol"?u+"":u,d);var d={exports:{}},A;function $(){if(A)return d.exports;A=1;function o(){}return o.prototype={on:function(i,t,e){var s=this.e||(this.e={});return(s[i]||(s[i]=[])).push({fn:t,ctx:e}),this},once:function(i,t,e){var s=this;function n(){s.off(i,n),t.apply(e,arguments)}return n._=t,this.on(i,n,e)},emit:function(i){var t=[].slice.call(arguments,1),e=((this.e||(this.e={}))[i]||[]).slice(),s=0,n=e.length;for(s;s<n;s++)e[s].fn.apply(e[s].ctx,t);return this},off:function(i,t){var e=this.e||(this.e={}),s=e[i],n=[];if(s&&t)for(var a=0,h=s.length;a<h;a++)s[a].fn!==t&&s[a].fn._!==t&&n.push(s[a]);return n.length?e[i]=n:delete e[i],this}},d.exports=o,d.exports.TinyEmitter=o,d.exports}var _=$(),L=(o=>(o.CONTEXTMENU="contextmenu",o.CLICK="click",o.DBLCLICK="dblclick",o))(L||{}),f=(o=>(o.BEFOREOPEN="beforeopen",o.OPEN="open",o.CLOSE="close",o.ADD_MENU_ENTRY="add-menu-entry",o))(f||{});class C extends u{constructor(i){super(i.type,i.map,i.originalEvent)}}const D={defaultItems:!0,eventType:L.CONTEXTMENU,items:[],scrollAt:4,width:150},E="ol-ctx-menu",r={container:`${E}-container`,hidden:`${E}-hidden`,icon:`${E}-icon`,separator:`${E}-separator`,submenu:`${E}-submenu`,unselectable:"ol-unselectable",zoomIn:`${E}-zoom-in`,zoomOut:`${E}-zoom-out`},P=8*2,S=10,M=2,T=[{callback:(o,i)=>{const t=i.getView();t.animate({center:o.coordinate,duration:700,zoom:Number(t.getZoom())+1})},classname:`${r.zoomIn} ${r.icon}`,text:"Zoom In"},{callback:(o,i)=>{const t=i.getView();t.animate({center:o.coordinate,duration:700,zoom:Number(t.getZoom())-1})},classname:`${r.zoomOut} ${r.icon}`,text:"Zoom Out"}];function v(o){const i=document.createDocumentFragment(),t=document.createElement("div");for(t.innerHTML=o;t.firstChild;)i.append(t.firstChild);return i}function k(o){const i=document.importNode(o),t=o.offsetWidth;i.style.cssText=`position: fixed; top: 0; left: 0; overflow: auto; visibility: hidden; pointer-events: none; height: unset; max-height: unset; width: ${t}px`;const e=v("<span>Foo</span>"),s=v("<span>Foo</span>"),n=document.createElement("li"),a=document.createElement("li");n.append(e),a.append(s),i.append(n),i.append(a),o.parentNode?.append(i);const h=i.offsetHeight/2;return o.parentNode?.removeChild(i),h}function I({emitter:o,isInsideSubmenu:i=!1,isSubmenu:t=!1,item:e,parentNode:s}){const n=`_${Math.random().toString(36).slice(2,11)}`;if(typeof e!="string"&&"text"in e){const x=`<span>${e.text}</span>`,y=v(x),l=document.createElement("li");e.classname=e.classname||"",e.icon&&(e.classname===""?e.classname=r.icon:e.classname.includes(r.icon)===!1&&(e.classname+=` ${r.icon}`),l.setAttribute("style",`background-image:url(${e.icon})`)),l.id=n,l.className=e.classname,l.append(y),s.append(l);const O={callback:"callback"in e?e.callback:null,data:"data"in e?e.data:null,id:n,isInsideSubmenu:i,isSeparator:!1,isSubmenu:t};return o.emit(f.ADD_MENU_ENTRY,O,l),l}const a=`<li id="${n}" class="${r.separator}"><hr></li>`,h=v(a);s.append(h);const g=s.lastChild,b={callback:null,data:null,id:n,isInsideSubmenu:!1,isSeparator:!0,isSubmenu:!1};return o.emit(f.ADD_MENU_ENTRY,b,g),g}function N({container:o,emitter:i,isInsideSubmenu:t,items:e,menuWidth:s}){e.forEach(n=>{if(typeof n!="string"&&"items"in n&&Array.isArray(n.items)){const a=I({emitter:i,isSubmenu:!0,item:n,parentNode:o});a.classList.add(r.submenu);const h=document.createElement("ul");h.classList.add(r.container),h.style.width=`${s}px`,a.append(h),N({container:h,emitter:i,isInsideSubmenu:!0,items:n.items,menuWidth:s})}else I({emitter:i,isInsideSubmenu:t,isSubmenu:!1,item:n,parentNode:o})})}function w(o,i){if(!o)throw new Error(i)}class H extends m{constructor(t={}){w(typeof t=="object","@param `opts` should be object type!");const e=document.createElement("div");super({element:e});c(this,"map");c(this,"emitter",new _.TinyEmitter);c(this,"container");c(this,"coordinate",[]);c(this,"pixel",[]);c(this,"contextMenuEventListener");c(this,"entryCallbackEventListener");c(this,"mapMoveListener");c(this,"lineHeight",0);c(this,"disabled");c(this,"opened");c(this,"items",[]);c(this,"menuEntries",new Map);c(this,"options");this.options={...D,...t};const s=document.createElement("ul");e.append(s),e.style.width=`${this.options.width}px`,e.classList.add(r.container,r.unselectable,r.hidden),this.container=e,this.contextMenuEventListener=n=>{this.handleContextMenu(n)},this.entryCallbackEventListener=n=>{this.handleEntryCallback(n)},this.mapMoveListener=()=>{this.handleMapMove()},this.disabled=!1,this.opened=!1,window.addEventListener("beforeunload",()=>{this.removeListeners()},{once:!0})}clear(){for(const t of this.menuEntries.keys())this.removeMenuEntry(t);this.container.replaceChildren(),this.container.append(document.createElement("ul"))}enable(){this.disabled=!1}disable(){this.disabled=!0}getDefaultItems(){return T}countItems(){return this.menuEntries.size}extend(t){w(Array.isArray(t),"@param `items` should be an Array."),N({container:this.container.firstElementChild,emitter:this.emitter,items:t,menuWidth:this.options.width})}closeMenu(){this.opened=!1,this.container.classList.add(r.hidden),this.dispatchEvent(f.CLOSE)}isOpen(){return this.opened}updatePosition(t){w(Array.isArray(t),"@param `pixel` should be an Array."),this.isOpen()&&(this.pixel=t,this.positionContainer())}pop(){const t=Array.from(this.menuEntries.keys()).pop();t&&this.removeMenuEntry(t)}shift(){const t=Array.from(this.menuEntries.keys()).shift();t&&this.removeMenuEntry(t)}push(t){t&&this.extend([t])}setMap(t){if(super.setMap(t),t){this.map=t,t.getViewport().addEventListener(this.options.eventType,this.contextMenuEventListener,!1),t.on("movestart",()=>{this.handleMapMove()}),this.emitter.on(f.ADD_MENU_ENTRY,(s,n)=>{this.handleAddMenuEntry(s,n)},this),this.items=this.options.defaultItems?this.options.items.concat(T):this.options.items,N({container:this.container.firstElementChild,emitter:this.emitter,items:this.items,menuWidth:this.options.width});const e=this.getMenuEntriesLength();this.lineHeight=e>0?this.container.offsetHeight/e:k(this.container)}else this.removeListeners(),this.clear()}removeListeners(){this.map.getViewport().removeEventListener(this.options.eventType,this.contextMenuEventListener,!1),this.emitter.off(f.ADD_MENU_ENTRY)}removeMenuEntry(t){let e=document.getElementById(t);e?.remove(),e=null,this.menuEntries.delete(t)}handleContextMenu(t){this.coordinate=this.map.getEventCoordinate(t),this.pixel=this.map.getEventPixel(t),this.dispatchEvent(new C({map:this.map,originalEvent:t,type:f.BEFOREOPEN})),!this.disabled&&(this.options.eventType===L.CONTEXTMENU&&(t.stopPropagation(),t.preventDefault()),setTimeout(()=>{this.openMenu(t)}),t.target?.addEventListener("pointerdown",e=>{this.opened&&(e.stopPropagation(),this.closeMenu())},{once:!0}))}openMenu(t){this.opened=!0,this.positionContainer(),this.container.classList.remove(r.hidden),this.dispatchEvent(new C({map:this.map,originalEvent:t,type:f.OPEN}))}getMenuEntriesLength(){return Array.from(this.menuEntries).filter(([,t])=>t.isSeparator===!1&&t.isSubmenu===!1&&t.isInsideSubmenu===!1).length}calculateMenuSize(){const t=this.getMenuEntriesLength(),s=Math.round(this.lineHeight*t)+P,n=this.container.offsetHeight,a=!this.container.classList.contains(r.hidden);return{h:n>0&&a?n:s,w:this.container.offsetWidth}}calculateVerticalPosition(t,e,s){let n;return e.h>=s.h?(n=this.pixel[1]-S,n+s.h>t[1]&&(n=Math.max(0,t[1]-s.h-M))):(n=this.pixel[1]-s.h,n<0&&(n=s.h<=t[1]?0:Math.max(0,t[1]-s.h)),n+s.h>t[1]&&(n=Math.max(0,t[1]-s.h-M))),Math.max(0,Math.min(n,t[1]-s.h-M))}adjustPositionAfterRender(t,e){if(!this.container.classList.contains(r.hidden)){const s=this.container.offsetHeight;s>0&&s!==e.h&&(Number.parseInt(this.container.style.top,10)||0)+s>t[1]&&(this.container.style.top=`${Math.max(0,t[1]-s-M)}px`)}}positionContainer(){const t=this.map.getSize()||[0,0],e=[t[0]||0,t[1]||0],s={h:e[1]-this.pixel[1],w:e[0]-this.pixel[0]},n=this.calculateMenuSize(),a=s.w>=n.w?this.pixel[0]+5:this.pixel[0]-n.w;this.container.style.left=`${a}px`;const h=this.calculateVerticalPosition(e,s,n);this.container.style.top=`${h}px`,this.container.style.right="auto",this.container.style.bottom="auto",this.adjustPositionAfterRender(e,n),s.w-=n.w;const g=y=>Array.from(y.children).filter(l=>l.tagName==="LI"&&l.classList.contains(r.submenu));let b=0;const x=(y,l)=>{b+=1,g(y).forEach(R=>{const U=l>=n.w?n.w-8:(n.w+8)*-1,p=R.querySelector(`ul.${r.container}`),F=Math.round(this.lineHeight*Array.from(p.children).filter(V=>V.tagName==="LI").length);p.style.left=`${U}px`,p.style.right="auto",p.style.top=s.h>=F+n.h?"0":`-${p.offsetHeight-25}px`,p.style.bottom="auto",p.style.zIndex=String(b),g(p).length>0&&x(p,l-n.w)})};x(this.container.firstElementChild,s.w)}handleMapMove(){this.closeMenu()}handleEntryCallback(t){t.preventDefault(),t.stopPropagation();const e=t.currentTarget,s=this.menuEntries.get(e.id);if(!s)return;const n={coordinate:this.coordinate,data:s.data};this.closeMenu(),s.callback?.(n,this.map)}handleAddMenuEntry(t,e){this.menuEntries.set(t.id,t),this.positionContainer(),"callback"in t&&typeof t.callback=="function"&&e.addEventListener("click",this.entryCallbackEventListener,!1)}}return H})(ol.control.Control,ol.MapBrowserEvent);