import { TileLayer } from 'leaflet'; import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js'; import { createChildRegisterHandler, type ChildEntry } from '../core/register.js'; import type { PropDef, PropTypesFromTable } from '../types/props.js'; const PROPS = { url: { kind: 'str', attr: 'url', default: '' }, layers: { kind: 'str', attr: 'layers', default: '' }, styles: { kind: 'str', attr: 'styles', default: '' }, format: { kind: 'str', attr: 'format', default: 'image/jpeg' }, transparent: { kind: 'bool-on', attr: 'transparent' }, version: { kind: 'str', attr: 'version', default: '1.1.1' }, uppercase: { kind: 'bool-on', attr: 'uppercase' }, } satisfies Record; const PROP_BY_ATTR = new Map( Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), ); type PropTypes = PropTypesFromTable; const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes; export class LeafletTileLayerWMS extends TypedBase { #obj?: TileLayer.WMS; #children = new Map(); #childHandler?: EventListener; static get observedAttributes() { return Object.values(PROPS).map((s) => s.attr); } static { for (const [name, spec] of Object.entries(PROPS)) { Object.defineProperty(LeafletTileLayerWMS.prototype, name, { get(this: LeafletTileLayerWMS) { const val = this.getAttribute(spec.attr); const s = spec as { kind: string; default: unknown }; if (s.kind === 'num') return val !== null ? Number(val) : (s.default as number); if (s.kind === 'bool-on') return this.hasAttribute(spec.attr); return val ?? (s.default as string); }, set(this: LeafletTileLayerWMS, v: number | string | boolean) { const s = spec as { kind: string }; if (s.kind === 'bool-on') this.toggleAttribute(spec.attr, !!v); else this.setAttribute(spec.attr, String(v)); }, configurable: true, enumerable: true, }); } } connectedCallback() { const url = this.getAttribute('url') || ''; this.#obj = new TileLayer.WMS( url, buildOptions(this, PROPS, ['url']) as Record, ); this.#childHandler = createChildRegisterHandler(this.#obj, this.#children) as EventListener; this.addEventListener('leaflet-register', this.#childHandler); registerWithParent(this, this.#obj); } disconnectedCallback() { if (this.#childHandler) this.removeEventListener('leaflet-register', this.#childHandler); this.#children.clear(); this.#obj?.remove(); this.#obj = undefined; } attributeChangedCallback(name: string, _old: string | null, val: string | null) { if (!this.#obj) return; if (name === 'url') { if (val) this.#obj.setUrl(val); } else { const propName = PROP_BY_ATTR.get(name); if (!propName) return; const setter = `set${propName.charAt(0).toUpperCase()}${propName.slice(1)}` as keyof TileLayer.WMS; if (typeof this.#obj[setter] === 'function') { (this.#obj[setter] as (v: unknown) => void)(parseAttributeValue(val)); } else { (this.#obj.setParams as unknown as (params: Record) => void)({ [propName]: parseAttributeValue(val), }); } } } } customElements.define('leaflet-tile-layer-wms', LeafletTileLayerWMS);