class WoMap extends HTMLElement { #map = null; #mounted = false; static get observedAttributes() { return ['lat', 'lng', 'site-name', 'access-notes', 'wo-number']; } connectedCallback() { this.style.display = 'block'; // Light DOM — Leaflet needs real DOM, not shadow root if (!this.querySelector('.wo-map-root')) this.#build(); } attributeChangedCallback() { if (this.#mounted) this.#update(); } #build() { const lat = parseFloat(this.getAttribute('lat')); const lng = parseFloat(this.getAttribute('lng')); const siteName = this.getAttribute('site-name') || 'Work Site'; const accessNotes = this.getAttribute('access-notes') || ''; const woNumber = this.getAttribute('wo-number') || ''; this.innerHTML = `
${lat && lng ? `
Get Directions
` : `
No location set for this work order
`} ${accessNotes ? `
${this.#esc(accessNotes)}
` : ''}
`; if (window.lucide) lucide.createIcons({ root: this }); if (lat && lng) { this.#initMap(lat, lng, siteName, woNumber); this.#setDirectionsLink(lat, lng); } this.#mounted = true; } #initMap(lat, lng, siteName, woNumber) { if (typeof L === 'undefined') { // Leaflet not yet loaded — retry once it fires window.addEventListener('load', () => this.#initMap(lat, lng, siteName, woNumber), { once: true }); return; } const mapId = `leaflet-map-${this.getAttribute('wo-id') || 'map'}`; const container = this.querySelector(`#${mapId}`); if (!container) return; // Prevent double-init if (container._leaflet_id) return; this.#map = L.map(container, { zoomControl: true }).setView([lat, lng], 16); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', maxZoom: 19, }).addTo(this.#map); const icon = L.divIcon({ className: '', html: `
${this.#esc(woNumber || '📍')}
`, iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [0, -32], }); L.marker([lat, lng], { icon }) .addTo(this.#map) .bindPopup(`${this.#esc(siteName)}
${lat.toFixed(5)}, ${lng.toFixed(5)}`) .openPopup(); } #setDirectionsLink(lat, lng) { const btn = this.querySelector('#directions-btn'); if (!btn) return; const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; btn.href = isIOS ? `maps://maps.apple.com/?daddr=${lat},${lng}&dirflg=d` : `https://maps.google.com/maps?daddr=${lat},${lng}`; } #update() { if (this.#map) { this.#map.remove(); this.#map = null; } this.#mounted = false; this.#build(); } #esc(s) { return (s || '').replace(/&/g,'&').replace(//g,'>'); } } customElements.define('wo-map', WoMap);