refactor: extract PROP_BY_ATTR + dynamic setter dispatch into helpers
Adds buildAttrMap(props) and setLayerAttr(obj, props, attrMap, name, val) to utils.ts. The former replaces the PROP_BY_ATTR Map construction (2 fewer lines per component), the latter replaces the 6-line dynamic setter dispatch pattern used as the fallback else block in 6 components. For WMS, setLayerAttr returns false when no setter exists, so the caller can fall back to setParams for non-method props.
This commit is contained in:
parent
96b48a6ae2
commit
c69f9c8503
@ -1,5 +1,5 @@
|
||||
import { ImageOverlay, LatLngBounds, LatLngExpression } from 'leaflet';
|
||||
import { buildOptions, parseAttributeValue, parseBoundsAttr } from '../core/utils.js';
|
||||
import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../core/utils.js';
|
||||
import { withProps } from '../core/with-props.js';
|
||||
|
||||
import { registerChildren, unregisterChildren } from '../core/register.js';
|
||||
@ -17,9 +17,7 @@ const PROPS = {
|
||||
className: { kind: 'str', attr: 'class-name', default: '' },
|
||||
} satisfies Record<string, PropDef>;
|
||||
|
||||
const PROP_BY_ATTR = new Map<string, string>(
|
||||
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
|
||||
);
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export class LeafletImageOverlay extends withProps(HTMLElement, PROPS) {
|
||||
#obj?: ImageOverlay;
|
||||
@ -50,15 +48,7 @@ export class LeafletImageOverlay extends withProps(HTMLElement, PROPS) {
|
||||
const el = this.#obj.getElement();
|
||||
if (el) (el as HTMLImageElement).alt = val ?? '';
|
||||
} else {
|
||||
const propName = PROP_BY_ATTR.get(name);
|
||||
if (!propName) return;
|
||||
const setter =
|
||||
`set${propName.charAt(0).toUpperCase()}${propName.slice(1)}` as keyof ImageOverlay;
|
||||
if (typeof this.#obj[setter] === 'function') {
|
||||
const spec = PROPS[propName as keyof typeof PROPS];
|
||||
const value = spec.kind === 'bool-on' ? val !== null : parseAttributeValue(val);
|
||||
(this.#obj[setter] as (v: unknown) => void)(value);
|
||||
}
|
||||
setLayerAttr(this.#obj!, PROPS, PROP_BY_ATTR, name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Marker } from 'leaflet';
|
||||
import { buildOptions, numAttr, parseAttributeValue } from '../core/utils.js';
|
||||
import { buildOptions, numAttr, buildAttrMap, setLayerAttr } from '../core/utils.js';
|
||||
import { withProps } from '../core/with-props.js';
|
||||
|
||||
import { registerChildren, unregisterChildren } from '../core/register.js';
|
||||
@ -15,9 +15,7 @@ const PROPS = {
|
||||
zIndexOffset: { kind: 'num', attr: 'z-index-offset', default: 0 },
|
||||
} satisfies Record<string, PropDef>;
|
||||
|
||||
const PROP_BY_ATTR = new Map<string, string>(
|
||||
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
|
||||
);
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export class LeafletMarker extends withProps(HTMLElement, PROPS) {
|
||||
#obj?: Marker;
|
||||
@ -53,12 +51,7 @@ export class LeafletMarker extends withProps(HTMLElement, PROPS) {
|
||||
const el = this.#obj.getElement();
|
||||
if (el) (el as HTMLImageElement).alt = val ?? '';
|
||||
} else {
|
||||
const propName = PROP_BY_ATTR.get(name);
|
||||
if (!propName) return;
|
||||
const setter = `set${propName.charAt(0).toUpperCase()}${propName.slice(1)}` as keyof Marker;
|
||||
if (typeof this.#obj[setter] === 'function') {
|
||||
(this.#obj[setter] as (v: unknown) => void)(parseAttributeValue(val));
|
||||
}
|
||||
setLayerAttr(this.#obj!, PROPS, PROP_BY_ATTR, name, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { SVGOverlay, LatLngBounds, LatLngExpression } from 'leaflet';
|
||||
import { buildOptions, parseAttributeValue, parseBoundsAttr } from '../core/utils.js';
|
||||
import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../core/utils.js';
|
||||
import { withProps } from '../core/with-props.js';
|
||||
|
||||
import { registerChildren, unregisterChildren } from '../core/register.js';
|
||||
@ -14,9 +14,7 @@ const PROPS = {
|
||||
className: { kind: 'str', attr: 'class-name', default: '' },
|
||||
} satisfies Record<string, PropDef>;
|
||||
|
||||
const PROP_BY_ATTR = new Map<string, string>(
|
||||
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
|
||||
);
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export class LeafletSVGOverlay extends withProps(HTMLElement, PROPS) {
|
||||
#obj?: SVGOverlay;
|
||||
@ -43,15 +41,7 @@ export class LeafletSVGOverlay extends withProps(HTMLElement, PROPS) {
|
||||
if (name === 'bounds') {
|
||||
this.#obj.setBounds(new LatLngBounds(parseBoundsAttr(this) as LatLngExpression[]));
|
||||
} else {
|
||||
const propName = PROP_BY_ATTR.get(name);
|
||||
if (!propName) return;
|
||||
const setter =
|
||||
`set${propName.charAt(0).toUpperCase()}${propName.slice(1)}` as keyof SVGOverlay;
|
||||
if (typeof this.#obj[setter] === 'function') {
|
||||
const spec = PROPS[propName as keyof typeof PROPS];
|
||||
const value = spec.kind === 'bool-on' ? val !== null : parseAttributeValue(val);
|
||||
(this.#obj[setter] as (v: unknown) => void)(value);
|
||||
}
|
||||
setLayerAttr(this.#obj!, PROPS, PROP_BY_ATTR, name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { TileLayer } from 'leaflet';
|
||||
import { buildOptions, parseAttributeValue } from '../core/utils.js';
|
||||
import { buildOptions, buildAttrMap, setLayerAttr, parseAttributeValue } from '../core/utils.js';
|
||||
import { withProps } from '../core/with-props.js';
|
||||
|
||||
import { registerChildren, unregisterChildren } from '../core/register.js';
|
||||
@ -15,9 +15,7 @@ const PROPS = {
|
||||
uppercase: { kind: 'bool-on', attr: 'uppercase' },
|
||||
} satisfies Record<string, PropDef>;
|
||||
|
||||
const PROP_BY_ATTR = new Map<string, string>(
|
||||
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
|
||||
);
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export class LeafletTileLayerWMS extends withProps(HTMLElement, PROPS) {
|
||||
#obj?: TileLayer.WMS;
|
||||
@ -44,13 +42,8 @@ export class LeafletTileLayerWMS extends withProps(HTMLElement, PROPS) {
|
||||
} 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;
|
||||
const spec = PROPS[propName as keyof typeof PROPS];
|
||||
if (typeof this.#obj[setter] === 'function') {
|
||||
const value = spec.kind === 'bool-on' ? val !== null : parseAttributeValue(val);
|
||||
(this.#obj[setter] as (v: unknown) => void)(value);
|
||||
} else {
|
||||
if (!setLayerAttr(this.#obj!, PROPS, PROP_BY_ATTR, name, val)) {
|
||||
const value = spec.kind === 'bool-on' ? val !== null : parseAttributeValue(val);
|
||||
(this.#obj.setParams as unknown as (params: Record<string, unknown>) => void)({
|
||||
[propName]: value,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { TileLayer } from 'leaflet';
|
||||
import { buildOptions, parseAttributeValue } from '../core/utils.js';
|
||||
import { buildOptions, buildAttrMap, setLayerAttr } from '../core/utils.js';
|
||||
import { withProps } from '../core/with-props.js';
|
||||
|
||||
import { registerChildren, unregisterChildren } from '../core/register.js';
|
||||
@ -14,9 +14,7 @@ const PROPS = {
|
||||
zIndex: { kind: 'num', attr: 'z-index', default: 0 },
|
||||
} satisfies Record<string, PropDef>;
|
||||
|
||||
const PROP_BY_ATTR = new Map<string, string>(
|
||||
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
|
||||
);
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export class LeafletTileLayer extends withProps(HTMLElement, PROPS) {
|
||||
#obj?: TileLayer;
|
||||
@ -38,13 +36,7 @@ export class LeafletTileLayer extends withProps(HTMLElement, PROPS) {
|
||||
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;
|
||||
if (typeof this.#obj[setter] === 'function') {
|
||||
(this.#obj[setter] as (v: unknown) => void)(parseAttributeValue(val));
|
||||
}
|
||||
setLayerAttr(this.#obj!, PROPS, PROP_BY_ATTR, name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { VideoOverlay, LatLngBounds, LatLngExpression } from 'leaflet';
|
||||
import { buildOptions, parseAttributeValue, parseBoundsAttr } from '../core/utils.js';
|
||||
import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../core/utils.js';
|
||||
import { withProps } from '../core/with-props.js';
|
||||
|
||||
import { registerChildren, unregisterChildren } from '../core/register.js';
|
||||
@ -18,9 +18,7 @@ const PROPS = {
|
||||
playsInline: { kind: 'bool-on', attr: 'playsinline' },
|
||||
} satisfies Record<string, PropDef>;
|
||||
|
||||
const PROP_BY_ATTR = new Map<string, string>(
|
||||
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
|
||||
);
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export class LeafletVideoOverlay extends withProps(HTMLElement, PROPS) {
|
||||
#obj?: VideoOverlay;
|
||||
@ -61,15 +59,7 @@ export class LeafletVideoOverlay extends withProps(HTMLElement, PROPS) {
|
||||
else if (name === 'playsinline') el.playsInline = val !== null;
|
||||
}
|
||||
} else {
|
||||
const propName = PROP_BY_ATTR.get(name);
|
||||
if (!propName) return;
|
||||
const setter =
|
||||
`set${propName.charAt(0).toUpperCase()}${propName.slice(1)}` as keyof VideoOverlay;
|
||||
if (typeof this.#obj[setter] === 'function') {
|
||||
const spec = PROPS[propName as keyof typeof PROPS];
|
||||
const value = spec.kind === 'bool-on' ? val !== null : parseAttributeValue(val);
|
||||
(this.#obj[setter] as (v: unknown) => void)(value);
|
||||
}
|
||||
setLayerAttr(this.#obj!, PROPS, PROP_BY_ATTR, name, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,6 +50,30 @@ export function parseBoundsAttr(el: HTMLElement): LatLngBoundsExpression {
|
||||
return raw ? (JSON.parse(raw) as LatLngBoundsExpression) : [];
|
||||
}
|
||||
|
||||
export function buildAttrMap(props: Record<string, PropDef>): Map<string, string> {
|
||||
return new Map(Object.entries(props).map(([name, spec]) => [spec.attr, name]));
|
||||
}
|
||||
|
||||
export function setLayerAttr(
|
||||
obj: object,
|
||||
props: Record<string, PropDef>,
|
||||
attrMap: Map<string, string>,
|
||||
name: string,
|
||||
val: string | null,
|
||||
): boolean {
|
||||
const propName = attrMap.get(name);
|
||||
if (!propName) return false;
|
||||
const spec = props[propName as keyof typeof props];
|
||||
const setter = `set${propName.charAt(0).toUpperCase()}${propName.slice(1)}`;
|
||||
const fn = (obj as Record<string, unknown>)[setter];
|
||||
if (typeof fn === 'function') {
|
||||
const value = spec.kind === 'bool-on' ? val !== null : parseAttributeValue(val);
|
||||
(fn as (v: unknown) => void)(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function buildOptions(
|
||||
el: HTMLElement,
|
||||
props: Record<string, PropDef>,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user