# ai-builder/2.1.2/assets/js/src/editor-blocks/map/index.js

AI Builder – Generate pages, blocks, images &amp; translate with AI, version 2.1.2. 216 lines.

- Page: https://pluginprobe.com/plugins/ai-builder/2.1.2/code/assets/js/src/editor-blocks/map/index.js
- Raw: https://pluginprobe.com/plugins/ai-builder/2.1.2/raw/assets/js/src/editor-blocks/map/index.js
- Modified: 2025-10-30T10:51:24+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ai-builder/2.1.2/code/assets/js/src/editor-blocks/map/index.js#L10-L20`.

```javascript
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { useEffect, useState } = wp.element;
const {
    PanelBody,
    SelectControl,
    TextControl,
    Button,
    RangeControl,
    ToggleControl,
} = wp.components;
const { InspectorControls, useBlockProps } = wp.blockEditor || wp.editor;
import "./style.css";

// Marker row component for editor UI
function MarkerRow({ marker, index, onChange, onRemove }) {
    const [lat, setLat] = useState(marker.lat);
    const [lng, setLng] = useState(marker.lng);
    const [title, setTitle] = useState(marker.title || "");
    useEffect(() => {
        onChange(index, { lat: parseFloat(lat) || 0, lng: parseFloat(lng) || 0, title });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [lat, lng, title]);
    return (
        <div className="aibui-map-marker-row">
            <div className="aibui-map-marker-fields">
                <TextControl label={__("Lat", "ai-builder")} value={String(lat)} onChange={setLat} />
                <TextControl label={__("Lng", "ai-builder")} value={String(lng)} onChange={setLng} />
                <TextControl label={__("Title", "ai-builder")} value={title} onChange={setTitle} />
            </div>
            <Button isDestructive onClick={() => onRemove(index)}>
                {__("Remove", "ai-builder")}
            </Button>
        </div>
    );
}

registerBlockType("ai-builder/aibui-map", {
    title: __("Map (AI Builder)", "ai-builder"),
    icon: "location",
    category: "widgets",
    supports: { align: ["wide", "full"], html: false },
    attributes: {
        provider: { type: "string", default: "osm" }, // 'osm' | 'google'
        apiKey: { type: "string", default: "" },
        centerLat: { type: "number", default: 48.8566 },
        centerLng: { type: "number", default: 2.3522 },
        zoom: { type: "number", default: 12 },
        height: { type: "string", default: "360px" },
        showZoomControl: { type: "boolean", default: true },
        draggable: { type: "boolean", default: true },
        markers: {
            type: "array",
            default: [], // [{lat, lng, title}]
        },
    },
    edit: (props) => {
        const { attributes, setAttributes } = props;
        const { provider, apiKey, centerLat, centerLng, zoom, height, markers, showZoomControl, draggable } = attributes;
        const blockProps = useBlockProps({ className: "aibui-map" });

        const setCenter = (patch) => setAttributes({ ...patch });
        const addMarker = () => setAttributes({ markers: [...markers, { lat: centerLat, lng: centerLng, title: "" }] });
        const updateMarker = (idx, patch) => setAttributes({ markers: markers.map((m, i) => (i === idx ? { ...m, ...patch } : m)) });
        const removeMarker = (idx) => setAttributes({ markers: markers.filter((_, i) => i !== idx) });

        useEffect(() => {
            const root = document.querySelector(`#block-${props.clientId}`) || null;
            if (!root) return;
            const canvas = root.querySelector('.aibui-map-canvas');
            if (!canvas) return;
            // Clean up any previous map instance bound to this canvas
            if (canvas.__aibuiMap && typeof canvas.__aibuiMap.remove === 'function') {
                try { canvas.__aibuiMap.remove(); } catch (e) { }
            }
            canvas.__aibuiMap = null;
            canvas.innerHTML = '';
            const initOSM = () => {
                if (window.L && window.L.map) {
                    const map = window.L.map(canvas, { zoomControl: !!showZoomControl, dragging: !!draggable }).setView([centerLat, centerLng], zoom);
                    window.L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '&copy; OpenStreetMap' }).addTo(map);
                    (markers || []).forEach(m => {
                        const mk = window.L.marker([parseFloat(m.lat) || 0, parseFloat(m.lng) || 0]).addTo(map);
                        if (m.title) mk.bindPopup(m.title);
                    });
                    canvas.__aibuiMap = map;
                    return;
                }
                const css = document.createElement('link'); css.rel = 'stylesheet'; css.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'; document.head.appendChild(css);
                const s = document.createElement('script'); s.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js'; s.onload = initOSM; document.head.appendChild(s);
            };
            const initGoogle = () => {
                if (window.google && window.google.maps) {
                    const map = new window.google.maps.Map(canvas, {
                        center: { lat: centerLat, lng: centerLng },
                        zoom: zoom,
                        zoomControl: !!showZoomControl,
                        draggable: !!draggable,
                    });
                    (markers || []).forEach(m => {
                        const mk = new window.google.maps.Marker({ position: { lat: parseFloat(m.lat) || 0, lng: parseFloat(m.lng) || 0 }, map, title: m.title || '' });
                        if (m.title) {
                            const iw = new window.google.maps.InfoWindow({ content: m.title });
                            mk.addListener('click', () => iw.open({ anchor: mk, map }));
                        }
                    });
                    canvas.__aibuiMap = map;
                    return;
                }
                const cbName = '__aibui_gmaps_cb_' + Math.random().toString(36).slice(2);
                window[cbName] = () => { initGoogle(); delete window[cbName]; };
                const s = document.createElement('script');
                const base = 'https://maps.googleapis.com/maps/api/js';
                const qs = (apiKey ? ('key=' + encodeURIComponent(apiKey) + '&') : '') + 'callback=' + cbName;
                s.src = base + '?' + qs; s.async = true; s.defer = true; document.head.appendChild(s);
            };
            if (provider === 'google') initGoogle(); else initOSM();
        }, [provider, apiKey, centerLat, centerLng, zoom, height, JSON.stringify(markers), showZoomControl, draggable, props.clientId]);

        return (
            <div {...blockProps}>
                <InspectorControls>
                    <PanelBody title={__("Map Provider", "ai-builder")} initialOpen>
                        <SelectControl
                            label={__("Provider", "ai-builder")}
                            value={provider}
                            options={[
                                { label: "OpenStreetMap", value: "osm" },
                                { label: "Google Maps", value: "google" },
                            ]}
                            onChange={(v) => setAttributes({ provider: v })}
                        />
                        {provider === "google" && (
                            <TextControl
                                label={__("Google Maps API key", "ai-builder")}
                                value={apiKey}
                                onChange={(v) => setAttributes({ apiKey: v })}
                                help={__("Required to load Google Maps.", "ai-builder")}
                            />
                        )}
                    </PanelBody>
                    <PanelBody title={__("Map Settings", "ai-builder")} initialOpen>
                        <TextControl
                            label={__("Center latitude", "ai-builder")}
                            value={String(centerLat)}
                            onChange={(v) => setCenter({ centerLat: parseFloat(v) || 0 })}
                        />
                        <TextControl
                            label={__("Center longitude", "ai-builder")}
                            value={String(centerLng)}
                            onChange={(v) => setCenter({ centerLng: parseFloat(v) || 0 })}
                        />
                        <RangeControl
                            label={__("Zoom", "ai-builder")}
                            min={1}
                            max={20}
                            value={zoom}
                            onChange={(v) => setAttributes({ zoom: v })}
                        />
                        <TextControl
                            label={__("Height", "ai-builder")}
                            value={height}
                            onChange={(v) => setAttributes({ height: v })}
                            help={__("Any CSS size (e.g. 360px, 50vh)", "ai-builder")}
                        />
                        <ToggleControl
                            label={__("Show zoom control", "ai-builder")}
                            checked={showZoomControl}
                            onChange={(v) => setAttributes({ showZoomControl: v })}
                        />
                        <ToggleControl
                            label={__("Draggable", "ai-builder")}
                            checked={draggable}
                            onChange={(v) => setAttributes({ draggable: v })}
                        />
                    </PanelBody>
                    <PanelBody title={__("Markers", "ai-builder")} initialOpen>
                        {markers.map((m, i) => (
                            <MarkerRow key={i} index={i} marker={m} onChange={updateMarker} onRemove={removeMarker} />
                        ))}
                        <Button isPrimary onClick={addMarker} style={{ marginTop: 8 }}>
                            {__("Add marker", "ai-builder")}
                        </Button>
                    </PanelBody>
                </InspectorControls>

                <div className="aibui-map-preview" style={{ height }}>
                    <div className="aibui-map-canvas" style={{ height: '100%', width: '100%' }} />
                </div>
            </div>
        );
    },
    save: (props) => {
        const { attributes } = props;
        const { provider, apiKey, centerLat, centerLng, zoom, height, markers, showZoomControl, draggable } = attributes;
        const blockProps = wp.blockEditor ? wp.blockEditor.useBlockProps.save({ className: "aibui-map" }) : {};
        return (
            <div
                {...blockProps}
                data-provider={provider}
                data-api-key={provider === "google" ? (apiKey || "") : ""}
                data-center-lat={centerLat}
                data-center-lng={centerLng}
                data-zoom={zoom}
                data-zoom-control={showZoomControl ? "1" : "0"}
                data-draggable={draggable ? "1" : "0"}
            >
                <div className="aibui-map-canvas" style={{ height }} />
                <script type="application/json" className="aibui-map-markers" dangerouslySetInnerHTML={{ __html: JSON.stringify(markers || []) }} />
            </div>
        );
    },
});



```
