import classnames from 'classnames/dedupe'; import { debounce } from 'throttle-debounce'; import apiFetch from '@wordpress/api-fetch'; import { BlockControls, InspectorControls, MediaUpload, RichText, useBlockProps, } from '@wordpress/block-editor'; import { BaseControl, Button, Dropdown, ExternalLink, PanelBody, ResizableBox, TextareaControl, TextControl, ToggleControl, ToolbarButton, ToolbarGroup, } from '@wordpress/components'; import { useEffect, useState } from '@wordpress/element'; import { applyFilters } from '@wordpress/hooks'; import { __ } from '@wordpress/i18n'; import DropdownPicker from '../../components/dropdown-picker'; import ImagePicker from '../../components/image-picker'; import RangeControl from '../../components/range-control'; import { maybeDecode, maybeEncode } from '../../utils/encode-decode'; import getIcon from '../../utils/get-icon'; import { ReactComponent as IconMarker } from './icons/marker.svg'; import MapBlock from './map-block'; import styles from './map-styles'; import SearchBox from './search-box'; const { GHOSTKIT } = window; const mapsUrl = `${GHOSTKIT.googleMapsAPIUrl}&libraries=geometry,drawing,places`; let geocoder = false; const MIN_MARKER_WIDTH = 10; const MAX_MARKER_WIDTH = 100; function getStyles(string) { let result = []; try { result = JSON.parse(maybeDecode(string)); } catch (e) { return []; } return result; } function MarkerSettings(props) { const { googleMapURL, title, address, addresses, lat, lng, iconImageURL, iconImageCustomWidth, infoWindowText, onChange, } = props; const previewIcon = iconImageURL ? ( ) : ( ); return ( <> { onChange({ title: value }); }} /> { if (value && value[0]) { onChange({ address: value[0].formatted_address, lat: value[0].geometry.location.lat(), lng: value[0].geometry.location.lng(), }); } }} className="ghostkit-google-maps-search-box" />
{previewIcon} { if (!media || !media.url) { return; } onChange({ iconImageID: media.id, iconImageURL: media.url, iconImageCustomWidth: Math.min( MAX_MARKER_WIDTH, media.width ), iconImageWidth: media.width, iconImageHeight: media.height, }); }} allowedTypes={['image']} value={iconImageURL || false} render={({ open }) => ( )} />
{iconImageCustomWidth ? (
) : null} {iconImageCustomWidth ? (
onChange({ iconImageCustomWidth: val }) } min={MIN_MARKER_WIDTH} max={MAX_MARKER_WIDTH} />
) : null} { onChange({ infoWindowText: val }); }} onRemove={() => { onChange({ infoWindowText: '' }); }} /> ); } /** * Block Edit Class. * * @param props */ export default function BlockEdit(props) { const { attributes, setAttributes, isSelected, toggleSelection } = props; let { className = '' } = props; const { height, zoom, lat, lng, showZoomButtons, showMapTypeButtons, showStreetViewButton, showFullscreenButton, optionScrollWheel, optionDraggable, gestureHandling, markers, fullHeight, style, styleCustom, } = attributes; const [mapID, setMapID] = useState(attributes.apiKey); const [apiKey, setApiKey] = useState(GHOSTKIT.googleMapsAPIKey); const [addresses, setAddresses] = useState({}); function updateMarkerAddress(latLng, address) { if (markers && markers.length > 0) { markers.forEach((marker, index) => { if ( !marker.address && latLng.lat === marker.lat && latLng.lng === marker.lng ) { markers[index].address = address; addresses[latLng.lat + latLng.lng] = address; } }); setAddresses(addresses); } } // Updated. useEffect(() => { // find Address by lat and lng. if ( geocoder || (window.google && window.google.maps && window.google.maps.Geocoder) ) { geocoder = new window.google.maps.Geocoder(); } if (geocoder) { if (markers && markers.length > 0) { markers.forEach((marker) => { if (!marker.address) { if (addresses[marker.lat + marker.lng]) { updateMarkerAddress( { lat: marker.lat, lng: marker.lng, }, addresses[marker.lat + marker.lng] ); } else { geocoder.geocode( { location: { lat: marker.lat, lng: marker.lng, }, }, (results, status) => { if (status === 'OK' && results.length) { updateMarkerAddress( { lat: marker.lat, lng: marker.lng, }, results[0].formatted_address ); } } ); } } }); } } }); const onChangeAPIKey = debounce(600, (newKey) => { GHOSTKIT.googleMapsAPIKey = newKey; setMapID(newKey); }); const saveAPIKey = debounce(3000, (newKey) => { apiFetch({ path: '/ghostkit/v1/update_google_maps_api_key', method: 'POST', data: { key: newKey, }, }); }); function getStylesPicker() { return ( <> { let customString = styleCustom; if (value === 'default') { customString = ''; } else if (value !== 'custom') { styles.forEach((styleData) => { if (value === styleData.value) { customString = JSON.stringify( styleData.json ); } }); } setAttributes({ style: value, styleCustom: maybeEncode(customString), }); }} /> {style === 'custom' ? ( <> setAttributes({ styleCustom: maybeEncode(value), }) } />

{__( 'You can use custom styles presets from the', 'ghostkit' )}{' '} {__('Snazzy Maps', 'ghostkit')} .

) : null} ); } function getMapPreview() { return ( { setAttributes({ markers: newMarkers }); }} options={{ styles: styleCustom ? getStyles(styleCustom) : [], zoom, center: { lat, lng }, zoomControl: showZoomButtons, zoomControlOpt: { style: 'DEFAULT', position: 'RIGHT_BOTTOM', }, mapTypeControl: showMapTypeButtons, streetViewControl: showStreetViewButton, fullscreenControl: showFullscreenButton, gestureHandling: 'cooperative', scrollwheel: false, draggable: optionDraggable, onZoomChange: debounce(500, (val) => setAttributes({ zoom: val }) ), onCenterChange: debounce(500, (val) => setAttributes({ lat: val.lat(), lng: val.lng() }) ), }} /> ); } className = classnames('ghostkit-google-maps', className); // add full height classname. if (fullHeight) { className = classnames(className, 'ghostkit-google-maps-fullheight'); } className = applyFilters('ghostkit.editor.className', className, props); const blockProps = useBlockProps({ className }); return ( <> {apiKey ? ( setAttributes({ fullHeight: !fullHeight }) } isActive={fullHeight} /> { setAttributes({ markers: [ ...markers, ...[ { lat, lng, }, ], ], }); }} /> ( ))} ) : null} setAttributes({ showZoomButtons: val }) } /> setAttributes({ showMapTypeButtons: val }) } /> setAttributes({ showStreetViewButton: val }) } /> setAttributes({ showFullscreenButton: val }) } /> setAttributes({ optionScrollWheel: val }) } /> setAttributes({ optionDraggable: val }) } /> {optionScrollWheel || optionDraggable ? ( { if ( optionScrollWheel && optionDraggable ) { return __( 'Better Scroll & Draggable', 'ghostkit' ); } if (optionScrollWheel) { return __( 'Better Scroll', 'ghostkit' ); } if (optionDraggable) { return __( 'Better Draggable', 'ghostkit' ); } return ''; })()} help={(() => { if ( optionScrollWheel && optionDraggable ) { return __( 'Scroll with pressed Ctrl or ⌘ key to zoom. Draggable with two fingers.', 'ghostkit' ); } if (optionScrollWheel) { return __( 'Scroll with pressed Ctrl or ⌘ key to zoom.', 'ghostkit' ); } if (optionDraggable) { return __( 'Draggable with two fingers.', 'ghostkit' ); } return ''; })()} checked={gestureHandling === 'cooperative'} onChange={() => { setAttributes({ gestureHandling: gestureHandling === 'greedy' ? 'cooperative' : 'greedy', }); }} /> ) : null} ) : null} { setApiKey(value); onChangeAPIKey(value); saveAPIKey(value); }} />

{__( 'A valid API key is required to use Google Maps. How to get API key', 'ghostkit' )}{' '} {__('read here', 'ghostkit')} .

{__( 'This key will be used in all Google Maps blocks on your site.', 'ghostkit' )}

{apiKey ? ( <> {fullHeight ? ( getMapPreview() ) : ( { toggleSelection(false); }} onResizeStop={( event, direction, elt, delta ) => { setAttributes({ height: parseInt( height + delta.height, 10 ), }); toggleSelection(true); }} > {getMapPreview()} )} {isSelected ? (
{ if (value && value[0]) { setAttributes({ lat: value[0].geometry.location.lat(), lng: value[0].geometry.location.lng(), }); } }} className="ghostkit-google-maps-search-box" />

{__( 'You can also drag the map to change the center coordinates.', 'ghostkit' )}

) : null} ) : (
{__( 'Google Maps API Key Required', 'ghostkit' )}
{__( 'Add an API key in block settings.', 'ghostkit' )}
)}
); }