diff --git a/com.woltlab.wcf/templates/googleMapsElement.tpl b/com.woltlab.wcf/templates/shared_googleMapsElement.tpl similarity index 84% rename from com.woltlab.wcf/templates/googleMapsElement.tpl rename to com.woltlab.wcf/templates/shared_googleMapsElement.tpl index 7209d793ab5..75459513158 100644 --- a/com.woltlab.wcf/templates/googleMapsElement.tpl +++ b/com.woltlab.wcf/templates/shared_googleMapsElement.tpl @@ -17,5 +17,5 @@ > {if $googleMapsHidden} - {include file='messageUserConsent' host="maps.google.com" url="https://www.google.com/maps/" target=$googleMapsElementID sandbox=true} + {include file='shared_messageUserConsent' host="maps.google.com" url="https://www.google.com/maps/" target=$googleMapsElementID sandbox=true} {/if} diff --git a/com.woltlab.wcf/templates/shared_googleMapsFormField.tpl b/com.woltlab.wcf/templates/shared_googleMapsFormField.tpl new file mode 100644 index 00000000000..6152e17c0c9 --- /dev/null +++ b/com.woltlab.wcf/templates/shared_googleMapsFormField.tpl @@ -0,0 +1,19 @@ +{capture assign='googleMapsElementID'}{$field->getPrefixedId()}_map{/capture} +{include file='shared_googleMapsElement' accessUserLocation=true googleMapsLat=$field->getLatitude() googleMapsLng=$field->getLongitude()} + +getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item='class' glue=' '}{$class}{/implode}"{/if} + value="{$field->getValue()}" + {if $field->isAutofocused()} autofocus{/if} + {if $field->isRequired()} required{/if} + {if $field->isImmutable()} disabled{/if} + {if $field->getPlaceholder() !== null} placeholder="{$field->getPlaceholder()}"{/if} + {if $field->getDocument()->isAjax()} data-dialog-submit-on-enter="true"{/if} + {foreach from=$field->getFieldAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach} + data-google-maps-geocoding="{$googleMapsElementID}" + data-google-maps-geocoding-store="{$field->getPrefixedId()}_" + data-google-maps-marker +> diff --git a/com.woltlab.wcf/templates/messageUserConsent.tpl b/com.woltlab.wcf/templates/shared_messageUserConsent.tpl similarity index 100% rename from com.woltlab.wcf/templates/messageUserConsent.tpl rename to com.woltlab.wcf/templates/shared_messageUserConsent.tpl diff --git a/ts/WoltLabSuite/Core/Form/Builder/Field/GoogleMaps.ts b/ts/WoltLabSuite/Core/Form/Builder/Field/GoogleMaps.ts new file mode 100644 index 00000000000..6e15524962e --- /dev/null +++ b/ts/WoltLabSuite/Core/Form/Builder/Field/GoogleMaps.ts @@ -0,0 +1,24 @@ +/** + * Data handler for a Google Maps form builder field in an Ajax form. + * + * @author Marcel Werk + * @copyright 2001-2025 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.2 + */ +import { FormBuilderData } from "../Data"; +import Value from "./Value"; +import type WoltlabCoreGoogleMapsElement from "WoltLabSuite/Core/Component/GoogleMaps/woltlab-core-google-maps"; + +class GoogleMaps extends Value { + protected _getData(): FormBuilderData { + const map = document.getElementById(this._fieldId + "_map") as WoltlabCoreGoogleMapsElement; + + return { + [this._fieldId]: (this._field as HTMLInputElement).value, + [this._fieldId + "_coordinates"]: `${map.lat},${map.lng}`, + }; + } +} + +export = GoogleMaps; diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/GoogleMaps.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/GoogleMaps.js new file mode 100644 index 00000000000..1e05511fee0 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Form/Builder/Field/GoogleMaps.js @@ -0,0 +1,14 @@ +define(["require", "exports", "tslib", "./Value"], function (require, exports, tslib_1, Value_1) { + "use strict"; + Value_1 = tslib_1.__importDefault(Value_1); + class GoogleMaps extends Value_1.default { + _getData() { + const map = document.getElementById(this._fieldId + "_map"); + return { + [this._fieldId]: this._field.value, + [this._fieldId + "_coordinates"]: `${map.lat},${map.lng}`, + }; + } + } + return GoogleMaps; +}); diff --git a/wcfsetup/install/files/lib/system/form/builder/field/GoogleMapsFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/GoogleMapsFormField.class.php new file mode 100644 index 00000000000..bcd3e7894bd --- /dev/null +++ b/wcfsetup/install/files/lib/system/form/builder/field/GoogleMapsFormField.class.php @@ -0,0 +1,123 @@ + + * @since 6.2 + */ +final class GoogleMapsFormField extends AbstractFormField implements + IAttributeFormField, + IAutoFocusFormField, + ICssClassFormField, + IImmutableFormField, + IPlaceholderFormField +{ + use TInputAttributeFormField { + getReservedFieldAttributes as private getDefaultReservedFieldAttributes; + } + use TAutoFocusFormField; + use TCssClassFormField; + use TImmutableFormField; + use TPlaceholderFormField; + + /** + * @inheritDoc + */ + protected $javaScriptDataHandlerModule = 'WoltLabSuite/Core/Form/Builder/Field/GoogleMaps'; + + /** + * @inheritDoc + */ + protected $templateName = 'shared_googleMapsFormField'; + + private float $latitude = 0; + private float $longitude = 0; + + public function __construct() + { + $this->addFieldClass('long'); + } + + /** + * @return string[] + */ + protected static function getReservedFieldAttributes(): array + { + return \array_merge( + static::getDefaultReservedFieldAttributes(), + [ + 'data-google-maps-geocoding-store', + 'data-google-maps-geocoding', + 'data-google-maps-marker', + ] + ); + } + + #[\Override] + public function readValue() + { + if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { + $this->value = $this->getDocument()->getRequestData($this->getPrefixedId()); + } + + if ($this->getDocument()->hasRequestData($this->getPrefixedId() . '_coordinates')) { + $coordinates = explode(',', $this->getDocument()->getRequestData( + $this->getPrefixedId() . '_coordinates' + )); + if (\count($coordinates) === 2) { + $this->latitude = \floatval($coordinates[0]); + $this->longitude = \floatval($coordinates[1]); + } + } + + return $this; + } + + #[\Override] + public function populate() + { + parent::populate(); + + $this->getDocument()->getDataHandler()->addProcessor(new CustomFormDataProcessor( + 'coordinates', + function (IFormDocument $document, array $parameters) { + if ($this->getValue()) { + $parameters[$this->getPrefixedId() . '_coordinates'] = [ + 'latitude' => $this->getLatitude(), + 'longitude' => $this->getLongitude(), + ]; + } + + return $parameters; + } + )); + + return $this; + } + + public function getLatitude(): float + { + return $this->latitude; + } + + public function getLongitude(): float + { + return $this->longitude; + } + + public function coordinates(float $latitude, float $longitude): static + { + $this->latitude = $latitude; + $this->longitude = $longitude; + + return $this; + } +} diff --git a/wcfsetup/install/files/lib/system/template/TemplateEngine.class.php b/wcfsetup/install/files/lib/system/template/TemplateEngine.class.php index d268f7217cc..725675491fc 100755 --- a/wcfsetup/install/files/lib/system/template/TemplateEngine.class.php +++ b/wcfsetup/install/files/lib/system/template/TemplateEngine.class.php @@ -109,11 +109,13 @@ class TemplateEngine extends SingletonFactory 'formError' => 'shared_formError', 'formNotice' => 'shared_formNotice', 'formSuccess' => 'shared_formSuccess', + 'googleMapsElement' => 'shared_googleMapsElement', 'languageChooser' => 'shared_languageChooser', 'lineBreakSeparatedTextOptionType' => 'shared_lineBreakSeparatedTextOptionType', 'mediaManager' => 'shared_mediaManager', 'messageFormAttachments' => 'shared_messageFormAttachments', 'messageTableOfContents' => 'shared_messageTableOfContents', + 'messageUserConsent' => 'shared_messageUserConsent', 'multipleLanguageInputJavascript' => 'shared_multipleLanguageInputJavascript', 'passwordStrengthLanguage' => 'shared_passwordStrengthLanguage', 'quoteMetaCode' => 'shared_quoteMetaCode',