From e2752aa7e0deda9b8e4e689199d0a390c76f86ee Mon Sep 17 00:00:00 2001 From: Buddy Date: Mon, 8 Jun 2026 22:45:08 -0700 Subject: [PATCH] refactor: extract child-registration boilerplate into WeakMap helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds registerChildren / unregisterChildren / getChildren to register.ts using module-scoped WeakMaps, removing the duplicated #children / #childHandler fields + lifecycle wiring from 15 components. registerChildren(el, layer) creates the children Map + handler, stores both in WeakMaps, wires the event listener, and calls registerWithParent — all in one call. unregisterChildren(el) tears it down. getChildren(el) gives access to the map for components that need custom child iteration in disconnectedCallback (geojson, layer-group, feature-group). Net: -101 lines, 15 components lose 2-4 fields + 4-8 lifecycle lines each. Components with extra lifecycle work (marker -> dragend, polygon/polyline -> observer + syncCoords) keep their custom additions inline, just the register boilerplate is replaced. --- src/components/leaflet-circle-marker.ts | 17 ++++------------ src/components/leaflet-circle.ts | 17 ++++------------ src/components/leaflet-feature-group.ts | 19 +++++------------- src/components/leaflet-geojson.ts | 19 +++++------------- src/components/leaflet-image-overlay.ts | 17 ++++------------ src/components/leaflet-layer-group.ts | 19 +++++------------- src/components/leaflet-marker.ts | 17 ++++------------ src/components/leaflet-polygon.ts | 17 ++++------------ src/components/leaflet-polyline.ts | 17 ++++------------ src/components/leaflet-rectangle.ts | 17 ++++------------ src/components/leaflet-svg-overlay.ts | 17 ++++------------ src/components/leaflet-tile-layer-wms.ts | 17 ++++------------ src/components/leaflet-tile-layer.ts | 17 ++++------------ src/components/leaflet-video-overlay.ts | 17 ++++------------ src/core/register.ts | 25 ++++++++++++++++++++++++ 15 files changed, 84 insertions(+), 185 deletions(-) diff --git a/src/components/leaflet-circle-marker.ts b/src/components/leaflet-circle-marker.ts index 6ce7c60..a12783b 100644 --- a/src/components/leaflet-circle-marker.ts +++ b/src/components/leaflet-circle-marker.ts @@ -1,12 +1,8 @@ import { CircleMarker } from 'leaflet'; -import { registerWithParent, buildOptions, numAttr } from '../core/utils.js'; +import { buildOptions, numAttr } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import type { PropDef } from '../types/props.js'; @@ -24,22 +20,17 @@ const PROPS = { export class LeafletCircleMarker extends withProps(HTMLElement, PROPS) { #obj?: CircleMarker; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { this.#obj = new CircleMarker( [numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')], buildOptions(this, PROPS, ['lat', 'lng']), ); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-circle.ts b/src/components/leaflet-circle.ts index e88e388..a1405b0 100644 --- a/src/components/leaflet-circle.ts +++ b/src/components/leaflet-circle.ts @@ -1,12 +1,8 @@ import { Circle } from 'leaflet'; -import { registerWithParent, buildOptions, numAttr } from '../core/utils.js'; +import { buildOptions, numAttr } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - type LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import type { PropDef } from '../types/props.js'; @@ -24,22 +20,17 @@ const PROPS = { export class LeafletCircle extends withProps(HTMLElement, PROPS) { #obj?: Circle; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { this.#obj = new Circle( [numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')], buildOptions(this, PROPS, ['lat', 'lng']), ); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-feature-group.ts b/src/components/leaflet-feature-group.ts index 46f668f..b6a8a32 100644 --- a/src/components/leaflet-feature-group.ts +++ b/src/components/leaflet-feature-group.ts @@ -1,15 +1,9 @@ import { FeatureGroup, Layer } from 'leaflet'; -import { buildOptions, registerWithParent } from '../core/utils.js'; -import { - createChildRegisterHandler, - type ChildEntry, - type LeafletRegisterEvent, -} from '../core/register.js'; +import { buildOptions } from '../core/utils.js'; +import { registerChildren, unregisterChildren, getChildren } from '../core/register.js'; export class LeafletFeatureGroup extends HTMLElement { #obj?: FeatureGroup; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; static get observedAttributes() { return []; @@ -17,19 +11,16 @@ export class LeafletFeatureGroup extends HTMLElement { connectedCallback() { this.#obj = new FeatureGroup([], buildOptions(this, {})); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - for (const [el, entry] of this.#children) { + for (const [el, entry] of getChildren(this) ?? []) { if (entry.type === 'popup') this.#obj?.unbindPopup(); else if (entry.type === 'tooltip') this.#obj?.unbindTooltip(); else if (entry.type === 'layer') this.#obj?.removeLayer(el as unknown as Layer); } - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-geojson.ts b/src/components/leaflet-geojson.ts index 30610c4..d4b2141 100644 --- a/src/components/leaflet-geojson.ts +++ b/src/components/leaflet-geojson.ts @@ -1,12 +1,8 @@ import { GeoJSON, PathOptions, Layer } from 'leaflet'; -import { buildOptions, registerWithParent } from '../core/utils.js'; +import { buildOptions } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren, getChildren } from '../core/register.js'; import type { PropDef } from '../types/props.js'; const PROPS = { @@ -31,8 +27,6 @@ const PROP_BY_ATTR = new Map( export class LeafletGeoJSON extends withProps(HTMLElement, PROPS) { #obj?: GeoJSON; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { const raw = this.getAttribute('data'); @@ -41,19 +35,16 @@ export class LeafletGeoJSON extends withProps(HTMLElement, PROPS) { Object.entries(buildOptions(this, PROPS, ['data'])).filter(([, v]) => v !== ''), ); this.#obj = new GeoJSON(data, { style: styleOpts as PathOptions }); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - for (const [el, entry] of this.#children) { + for (const [el, entry] of getChildren(this) ?? []) { if (entry.type === 'popup') this.#obj?.unbindPopup(); else if (entry.type === 'tooltip') this.#obj?.unbindTooltip(); else if (entry.type === 'layer') this.#obj?.removeLayer(el as unknown as Layer); } - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-image-overlay.ts b/src/components/leaflet-image-overlay.ts index e3f4c7b..7362799 100644 --- a/src/components/leaflet-image-overlay.ts +++ b/src/components/leaflet-image-overlay.ts @@ -1,12 +1,8 @@ import { ImageOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet'; -import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js'; +import { buildOptions, parseAttributeValue } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import type { PropDef } from '../types/props.js'; const PROPS = { @@ -27,8 +23,6 @@ const PROP_BY_ATTR = new Map( export class LeafletImageOverlay extends withProps(HTMLElement, PROPS) { #obj?: ImageOverlay; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { const url = this.getAttribute('url') || ''; @@ -37,14 +31,11 @@ export class LeafletImageOverlay extends withProps(HTMLElement, PROPS) { this.#parsedBounds(), buildOptions(this, PROPS, ['url', 'bounds']), ); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-layer-group.ts b/src/components/leaflet-layer-group.ts index 342ca50..8d47c22 100644 --- a/src/components/leaflet-layer-group.ts +++ b/src/components/leaflet-layer-group.ts @@ -1,15 +1,9 @@ import { LayerGroup, Layer } from 'leaflet'; -import { buildOptions, registerWithParent } from '../core/utils.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { buildOptions } from '../core/utils.js'; +import { registerChildren, unregisterChildren, getChildren } from '../core/register.js'; export class LeafletLayerGroup extends HTMLElement { #obj?: LayerGroup; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; static get observedAttributes() { return []; @@ -17,19 +11,16 @@ export class LeafletLayerGroup extends HTMLElement { connectedCallback() { this.#obj = new LayerGroup([], buildOptions(this, {})); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - for (const [el, entry] of this.#children) { + for (const [el, entry] of getChildren(this) ?? []) { if (entry.type === 'popup') this.#obj?.unbindPopup(); else if (entry.type === 'tooltip') this.#obj?.unbindTooltip(); else if (entry.type === 'layer') this.#obj?.removeLayer(el as unknown as Layer); } - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-marker.ts b/src/components/leaflet-marker.ts index 3096008..a44936a 100644 --- a/src/components/leaflet-marker.ts +++ b/src/components/leaflet-marker.ts @@ -1,12 +1,8 @@ import { Marker } from 'leaflet'; -import { registerWithParent, buildOptions, numAttr, parseAttributeValue } from '../core/utils.js'; +import { buildOptions, numAttr, parseAttributeValue } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import type { PropDef } from '../types/props.js'; const PROPS = { @@ -26,8 +22,6 @@ const PROP_BY_ATTR = new Map( export class LeafletMarker extends withProps(HTMLElement, PROPS) { #obj?: Marker; #syncing = false; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { this.#obj = new Marker( @@ -35,15 +29,12 @@ export class LeafletMarker extends withProps(HTMLElement, PROPS) { buildOptions(this, PROPS, ['lat', 'lng']), ); this.#obj.on('dragend', this.#onDragEnd); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); this.#obj?.off('dragend', this.#onDragEnd); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-polygon.ts b/src/components/leaflet-polygon.ts index 2f71bb3..28b377f 100644 --- a/src/components/leaflet-polygon.ts +++ b/src/components/leaflet-polygon.ts @@ -1,12 +1,8 @@ import { Polygon } from 'leaflet'; -import { registerWithParent, buildOptions } from '../core/utils.js'; +import { buildOptions } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import type { PropDef } from '../types/props.js'; import type { LeafletLine } from './leaflet-line.js'; @@ -23,14 +19,10 @@ const PROPS = { export class LeafletPolygon extends withProps(HTMLElement, PROPS) { #obj?: Polygon; #observer?: MutationObserver; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { this.#obj = new Polygon(this.#getCoords(), buildOptions(this, PROPS)); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); this.addEventListener('line-updated', this.#syncCoords); this.#observer = new MutationObserver(() => this.#syncCoords()); @@ -41,8 +33,7 @@ export class LeafletPolygon extends withProps(HTMLElement, PROPS) { this.#observer?.disconnect(); this.#observer = undefined; this.removeEventListener('line-updated', this.#syncCoords); - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-polyline.ts b/src/components/leaflet-polyline.ts index 09936eb..cd2dcb3 100644 --- a/src/components/leaflet-polyline.ts +++ b/src/components/leaflet-polyline.ts @@ -1,12 +1,8 @@ import { Polyline } from 'leaflet'; -import { registerWithParent, buildOptions } from '../core/utils.js'; +import { buildOptions } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import type { PropDef } from '../types/props.js'; import type { LeafletLine } from './leaflet-line.js'; @@ -23,14 +19,10 @@ const PROPS = { export class LeafletPolyline extends withProps(HTMLElement, PROPS) { #obj?: Polyline; #observer?: MutationObserver; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { this.#obj = new Polyline(this.#getCoords(), buildOptions(this, PROPS)); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); this.addEventListener('line-updated', this.#syncCoords); this.#observer = new MutationObserver(() => this.#syncCoords()); @@ -41,8 +33,7 @@ export class LeafletPolyline extends withProps(HTMLElement, PROPS) { this.#observer?.disconnect(); this.#observer = undefined; this.removeEventListener('line-updated', this.#syncCoords); - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-rectangle.ts b/src/components/leaflet-rectangle.ts index 63eb197..f0b049c 100644 --- a/src/components/leaflet-rectangle.ts +++ b/src/components/leaflet-rectangle.ts @@ -1,12 +1,8 @@ import { Rectangle, LatLngBoundsExpression } from 'leaflet'; -import { registerWithParent, buildOptions } from '../core/utils.js'; +import { buildOptions } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import type { PropDef } from '../types/props.js'; @@ -22,19 +18,14 @@ const PROPS = { export class LeafletRectangle extends withProps(HTMLElement, PROPS) { #obj?: Rectangle; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { this.#obj = new Rectangle(this.#parsedBounds(), buildOptions(this, PROPS, ['bounds'])); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-svg-overlay.ts b/src/components/leaflet-svg-overlay.ts index 071e331..0877eaf 100644 --- a/src/components/leaflet-svg-overlay.ts +++ b/src/components/leaflet-svg-overlay.ts @@ -1,12 +1,8 @@ import { SVGOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet'; -import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js'; +import { buildOptions, parseAttributeValue } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import type { PropDef } from '../types/props.js'; const PROPS = { @@ -24,8 +20,6 @@ const PROP_BY_ATTR = new Map( export class LeafletSVGOverlay extends withProps(HTMLElement, PROPS) { #obj?: SVGOverlay; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { const svg = this.querySelector('svg'); @@ -35,14 +29,11 @@ export class LeafletSVGOverlay extends withProps(HTMLElement, PROPS) { this.#parsedBounds(), buildOptions(this, PROPS, ['bounds']), ); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-tile-layer-wms.ts b/src/components/leaflet-tile-layer-wms.ts index 1b4504a..1ae7100 100644 --- a/src/components/leaflet-tile-layer-wms.ts +++ b/src/components/leaflet-tile-layer-wms.ts @@ -1,12 +1,8 @@ import { TileLayer } from 'leaflet'; -import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js'; +import { buildOptions, parseAttributeValue } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import type { PropDef } from '../types/props.js'; const PROPS = { @@ -25,8 +21,6 @@ const PROP_BY_ATTR = new Map( export class LeafletTileLayerWMS extends withProps(HTMLElement, PROPS) { #obj?: TileLayer.WMS; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { const url = this.getAttribute('url') || ''; @@ -34,14 +28,11 @@ export class LeafletTileLayerWMS extends withProps(HTMLElement, PROPS) { url, buildOptions(this, PROPS, ['url']) as Record, ); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-tile-layer.ts b/src/components/leaflet-tile-layer.ts index 9058bfe..1244cab 100644 --- a/src/components/leaflet-tile-layer.ts +++ b/src/components/leaflet-tile-layer.ts @@ -1,12 +1,8 @@ import { TileLayer } from 'leaflet'; -import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js'; +import { buildOptions, parseAttributeValue } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import type { PropDef } from '../types/props.js'; const PROPS = { @@ -24,20 +20,15 @@ const PROP_BY_ATTR = new Map( export class LeafletTileLayer extends withProps(HTMLElement, PROPS) { #obj?: TileLayer; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { const url = this.getAttribute('url') || ''; this.#obj = new TileLayer(url, buildOptions(this, PROPS, ['url'])); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/components/leaflet-video-overlay.ts b/src/components/leaflet-video-overlay.ts index 20905fa..4e6210c 100644 --- a/src/components/leaflet-video-overlay.ts +++ b/src/components/leaflet-video-overlay.ts @@ -1,12 +1,8 @@ import { VideoOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet'; -import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js'; +import { buildOptions, parseAttributeValue } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; -import { - createChildRegisterHandler, - type ChildEntry, - LeafletRegisterEvent, -} from '../core/register.js'; +import { registerChildren, unregisterChildren } from '../core/register.js'; import type { PropDef } from '../types/props.js'; const PROPS = { @@ -28,8 +24,6 @@ const PROP_BY_ATTR = new Map( export class LeafletVideoOverlay extends withProps(HTMLElement, PROPS) { #obj?: VideoOverlay; - #children = new Map(); - #childHandler?: (e: LeafletRegisterEvent) => void; connectedCallback() { const url = this.getAttribute('url') || ''; @@ -38,14 +32,11 @@ export class LeafletVideoOverlay extends withProps(HTMLElement, PROPS) { this.#parsedBounds(), buildOptions(this, PROPS, ['url', 'bounds']), ); - this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); - this.addEventListener('leaflet-register', this.#childHandler); - registerWithParent(this, this.#obj); + registerChildren(this, this.#obj); } disconnectedCallback() { - if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); - this.#children.clear(); + unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } diff --git a/src/core/register.ts b/src/core/register.ts index 2f548ec..0a3dbe3 100644 --- a/src/core/register.ts +++ b/src/core/register.ts @@ -1,4 +1,5 @@ import { Layer, LayerGroup, Popup, Tooltip } from 'leaflet'; +import { registerWithParent } from './utils.js'; export type LeafletRegisterEvent = CustomEvent<{ leafletObject: Layer; @@ -34,3 +35,27 @@ export function createChildRegisterHandler(layer: Layer, children: Map>(); +const handlerMap = new WeakMap void>(); + +export function registerChildren(el: HTMLElement, layer: Layer): Map { + const children = new Map(); + const handler = createChildRegisterHandler(layer, children); + childrenMap.set(el, children); + handlerMap.set(el, handler); + el.addEventListener('leaflet-register', handler); + registerWithParent(el, layer); + return children; +} + +export function unregisterChildren(el: HTMLElement): void { + const handler = handlerMap.get(el); + if (handler) el.removeEventListener('leaflet-register', handler); + childrenMap.delete(el); + handlerMap.delete(el); +} + +export function getChildren(el: HTMLElement): Map | undefined { + return childrenMap.get(el); +}