├── Classes ├── Backend │ └── Preview │ │ └── Maps2PluginPreview.php ├── Client │ ├── AbstractClient.php │ ├── ClientFactory.php │ ├── ClientInterface.php │ ├── GoogleMapsClient.php │ ├── OpenStreetMapClient.php │ └── Request │ │ ├── AbstractRequest.php │ │ ├── GoogleMaps │ │ └── GeocodeRequest.php │ │ ├── OpenStreetMap │ │ └── GeocodeRequest.php │ │ ├── RequestFactory.php │ │ └── RequestInterface.php ├── Configuration │ └── ExtConf.php ├── Controller │ ├── CityMapController.php │ ├── PoiCollectionController.php │ └── Traits │ │ ├── InjectExtConfTrait.php │ │ ├── InjectGeoCodeServiceTrait.php │ │ ├── InjectLinkHelperTrait.php │ │ ├── InjectPoiCollectionRepositoryTrait.php │ │ └── InjectSettingsHelperTrait.php ├── Domain │ ├── Model │ │ ├── Category.php │ │ ├── PoiCollection.php │ │ ├── Position.php │ │ └── Search.php │ ├── Repository │ │ └── PoiCollectionRepository.php │ └── Traits │ │ ├── GetExtConfTrait.php │ │ ├── GetMapHelperTrait.php │ │ └── GetWebPathOfFileReferenceTrait.php ├── Event │ ├── AllowCreationOfPoiCollectionEvent.php │ ├── ControllerActionEventInterface.php │ ├── ModifyQueryOfFindPoiCollectionsEvent.php │ ├── PostProcessFluidVariablesEvent.php │ ├── PostProcessPoiCollectionRecordEvent.php │ ├── PreAddForeignRecordEvent.php │ └── RenderInfoWindowContentEvent.php ├── EventListener │ └── PreventPageCacheForMiddlewareEventListener.php ├── ExpressionLanguage │ ├── AllowMapProviderRequestConditionProvider.php │ └── AllowMapProviderRequestFunctionsProvider.php ├── Form │ ├── Element │ │ ├── GoogleMapsElement.php │ │ ├── OpenStreetMapElement.php │ │ └── ReadOnlyInputTextElement.php │ ├── FieldInformation │ │ └── InfoWindowContent.php │ └── Resolver │ │ └── MapProviderResolver.php ├── Helper │ ├── AddressHelper.php │ ├── LinkHelper.php │ ├── MapHelper.php │ ├── MessageHelper.php │ ├── OverlayHelper.php │ ├── SettingsHelper.php │ └── StoragePidHelper.php ├── Hook │ └── CreateMaps2RecordHook.php ├── Mapper │ ├── GoogleMapsMapper.php │ ├── MapperFactory.php │ ├── MapperInterface.php │ └── OpenStreetMapMapper.php ├── Middleware │ ├── GetInfoWindowContentMiddleware.php │ └── InitFeSessionMiddleware.php ├── Service │ ├── CacheService.php │ ├── GeoCodeService.php │ ├── InfoWindowContentService.php │ ├── MapProviderRequestService.php │ ├── MapService.php │ └── PoiCollectionService.php ├── Tca │ ├── Maps2Registry.php │ └── Type │ │ └── FloatType.php ├── Traits │ └── GetTypo3RequestTrait.php ├── Update │ ├── MigratePluginToContentElementUpdate.php │ ├── MigratePoiRecordsToConfigurationMapUpdate.php │ ├── MoveOldFlexFormSettingsUpdate.php │ └── NewGeocodeUriForOsmUpdate.php ├── Utility │ └── DatabaseUtility.php └── ViewHelpers │ ├── Cache │ ├── GetCacheViewHelper.php │ ├── HasCacheViewHelper.php │ └── SetCacheViewHelper.php │ ├── ConvertToJsonViewHelper.php │ ├── Form │ ├── HiddenViewHelper.php │ └── RenderHiddenFieldsForGetViewHelper.php │ ├── GetEnvironmentViewHelper.php │ ├── IsRequestToMapProviderAllowedViewHelper.php │ ├── RequestUriForOverlayViewHelper.php │ └── TrimExplodeViewHelper.php ├── Configuration ├── ContentSecurityPolicies.php ├── ExpressionLanguage.php ├── Extbase │ └── Persistence │ │ └── Classes.php ├── FlexForms │ ├── CityMap.xml │ ├── Maps2.xml │ └── Radius.xml ├── Icons.php ├── JavaScriptModules.php ├── RequestMiddlewares.php ├── Services.yaml ├── Sets │ ├── GoogleMaps │ │ ├── config.yaml │ │ ├── settings.definitions.yaml │ │ └── setup.typoscript │ ├── Maps2 │ │ ├── config.yaml │ │ ├── settings.definitions.yaml │ │ └── setup.typoscript │ └── OpenStreetMap │ │ ├── config.yaml │ │ ├── settings.definitions.yaml │ │ └── setup.typoscript └── TCA │ ├── Overrides │ ├── sys_category.php │ ├── sys_template.php │ ├── tt_content.php │ └── tx_maps2_domain_model_poicollection.php │ └── tx_maps2_domain_model_poicollection.php ├── Documentation ├── AdministratorManual │ ├── GoogleApiKeys │ │ └── Index.rst │ ├── Index.rst │ ├── Routing │ │ └── Index.rst │ ├── Templates │ │ ├── Index.rst │ │ ├── Start │ │ │ └── Index.rst │ │ └── ViewHelpers │ │ │ ├── Cache │ │ │ ├── GetCacheViewHelper.rst │ │ │ ├── HasCacheViewHelper.rst │ │ │ └── SetCacheViewHelper.rst │ │ │ ├── ConvertToJsonViewHelper.rst │ │ │ ├── Index.rst │ │ │ ├── IsRequestToMapProviderAllowedViewHelper.rst │ │ │ ├── RequestUriForOverlayViewHelper.rst │ │ │ └── TrimExplodeViewHelper.rst │ └── Upgrade │ │ └── Index.rst ├── ChangeLog │ └── Index.rst ├── Configuration │ ├── Extension │ │ └── Index.rst │ ├── Index.rst │ ├── Plugins │ │ └── Index.rst │ └── TypoScript │ │ └── Index.rst ├── DeveloperManual │ ├── Api │ │ └── Index.rst │ ├── Index.rst │ ├── Maps2Registry │ │ └── Index.rst │ └── Template │ │ └── Index.rst ├── FAQ │ └── Index.rst ├── Images │ ├── AdministratorManual │ │ └── maps2-include-TypoScript.png │ ├── GoogleApiKeys │ │ ├── WizardActivatedApis.png │ │ ├── WizardPickProduct.png │ │ └── WizardSelectProject.png │ ├── Introduction │ │ ├── maps2-type-Area.png │ │ ├── maps2-type-Point.png │ │ ├── maps2-type-Radius.png │ │ └── maps2-type-Route.png │ ├── Typo3.png │ └── UserManual │ │ └── BackendView.png ├── Includes.rst.txt ├── Index.rst ├── Installation │ └── Index.rst ├── Introduction │ └── Index.rst ├── User │ ├── HowToStart │ │ └── Index.rst │ ├── Index.rst │ └── Maps2Record │ │ └── Index.rst └── guides.xml ├── LICENSE.txt ├── README.md ├── Resources ├── Private │ ├── .htaccess │ ├── Language │ │ ├── ExtConf.xlf │ │ ├── FlexForms.xlf │ │ ├── locallang.xlf │ │ └── locallang_db.xlf │ ├── Layouts │ │ └── Default.html │ ├── Partials │ │ ├── InfoWindowContent.html │ │ ├── LoadAssets.html │ │ └── Maps2 │ │ │ ├── EditPoiCollection.html │ │ │ ├── Overlay.html │ │ │ └── PoiCollection.html │ └── Templates │ │ ├── CityMap │ │ ├── Search.html │ │ └── Show.html │ │ ├── InfoWindowContent.html │ │ ├── InfoWindowContentNoCache.html │ │ ├── PluginPreview │ │ └── Maps2.html │ │ ├── PoiCollection │ │ ├── ListRadius.html │ │ ├── Overlay.html │ │ ├── Search.html │ │ └── Show.html │ │ └── Tca │ │ ├── GoogleMaps.html │ │ └── OpenStreetMap.html └── Public │ ├── Css │ ├── GoogleMapsModule.css │ └── Leaflet │ │ ├── Leaflet.css │ │ └── images │ │ ├── layers-2x.png │ │ ├── layers.png │ │ ├── marker-icon-2x.png │ │ ├── marker-icon.png │ │ └── marker-shadow.png │ ├── Icons │ ├── Extension.svg │ ├── MarkerClusterer │ │ ├── m1.png │ │ ├── m2.png │ │ ├── m3.png │ │ ├── m4.png │ │ └── m5.png │ ├── RecordTypeArea.png │ ├── RecordTypePoint.png │ ├── RecordTypeRadius.png │ ├── RecordTypeRoute.png │ ├── TypeSelectArea.png │ ├── TypeSelectPoint.png │ ├── TypeSelectRadius.png │ ├── TypeSelectRoute.png │ ├── marker.png │ ├── marker.svg │ ├── plugin_wizard.svg │ ├── relation.gif │ └── tx_maps2_domain_model_poi.png │ └── JavaScript │ ├── Classes.js │ ├── Classes.js.map │ ├── GoogleMaps2.min.js │ ├── GoogleMaps2.min.js.map │ ├── GoogleMapsModule.min.js │ ├── GoogleMapsModule.min.js.map │ ├── MarkerClusterer.js │ ├── OpenStreetMap2.min.js │ ├── OpenStreetMap2.min.js.map │ ├── OpenStreetMapModule.min.js │ ├── OpenStreetMapModule.min.js.map │ ├── leaflet.min.js │ └── leaflet.min.js.map ├── composer.json ├── ext_conf_template.txt ├── ext_emconf.php ├── ext_localconf.php └── ext_tables.sql /Classes/Backend/Preview/Maps2PluginPreview.php: -------------------------------------------------------------------------------- 1 | getRecord(); 46 | if (!$this->isValidPlugin($ttContentRecord)) { 47 | return ''; 48 | } 49 | 50 | $view = $this->viewFactory->create(new ViewFactoryData( 51 | templatePathAndFilename: self::PREVIEW_TEMPLATE, 52 | )); 53 | $view->assignMultiple($ttContentRecord); 54 | 55 | $this->addPluginName($view, $ttContentRecord); 56 | 57 | // Add data from column pi_flexform 58 | $piFlexformData = $this->getPiFlexformData($ttContentRecord); 59 | if ($piFlexformData !== []) { 60 | $view->assign('pi_flexform_transformed', $piFlexformData); 61 | } 62 | 63 | if ($ttContentRecord['CType'] === 'maps2_maps2') { 64 | $this->addPoiCollection($view, $piFlexformData); 65 | } 66 | 67 | return $view->render(); 68 | } 69 | 70 | protected function isValidPlugin(array $ttContentRecord): bool 71 | { 72 | if (!isset($ttContentRecord['CType'])) { 73 | return false; 74 | } 75 | 76 | return in_array($ttContentRecord['CType'], self::ALLOWED_PLUGINS, true); 77 | } 78 | 79 | protected function addPluginName(ViewInterface $view, array $ttContentRecord): void 80 | { 81 | $langKey = sprintf( 82 | 'plugin.%s.title', 83 | str_replace('maps2_', '', $ttContentRecord['CType']), 84 | ); 85 | 86 | $view->assign( 87 | 'pluginName', 88 | LocalizationUtility::translate('LLL:EXT:maps2/Resources/Private/Language/locallang_db.xlf:' . $langKey), 89 | ); 90 | } 91 | 92 | protected function getPiFlexformData(array $ttContentRecord): array 93 | { 94 | $data = []; 95 | if (!empty($ttContentRecord['pi_flexform'] ?? '')) { 96 | $data = $this->flexFormService->convertFlexFormContentToArray($ttContentRecord['pi_flexform']); 97 | } 98 | 99 | return $data; 100 | } 101 | 102 | protected function addPoiCollection(ViewInterface $view, array $piFlexformData): void 103 | { 104 | if ( 105 | isset($piFlexformData['settings']['poiCollection']) 106 | && $piFlexformData['settings']['poiCollection'] !== '0' 107 | && MathUtility::canBeInterpretedAsInteger($piFlexformData['settings']['poiCollection']) 108 | ) { 109 | $poiCollectionRecord = $this->poiCollectionService->findByUid( 110 | (int)$piFlexformData['settings']['poiCollection'], 111 | $GLOBALS['TYPO3_REQUEST'] ?? null, 112 | ); 113 | if ($poiCollectionRecord !== null) { 114 | $view->assign('poiCollectionRecord', $poiCollectionRecord); 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Classes/Client/AbstractClient.php: -------------------------------------------------------------------------------- 1 | isValidRequest()) { 33 | $this->messageHelper->addFlashMessage( 34 | 'URI is empty or contains invalid chars. URI: ' . $request->getUri(), 35 | 'Invalid request URI', 36 | ContextualFeedbackSeverity::ERROR, 37 | ); 38 | return []; 39 | } 40 | 41 | $processedResponse = []; 42 | $response = $this->requestFactory->request($request->getUri()); 43 | if ($response->getStatusCode() === 200) { 44 | $processedResponse = \json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR); 45 | $this->checkResponseForErrors($processedResponse); 46 | } else { 47 | $this->messageHelper->addFlashMessage( 48 | 'MapProvider returns a response with a status code different than 200', 49 | 'Client Error', 50 | ContextualFeedbackSeverity::ERROR, 51 | ); 52 | } 53 | 54 | if ($this->hasErrors()) { 55 | $processedResponse = []; 56 | } 57 | 58 | return $processedResponse; 59 | } 60 | 61 | public function hasErrors(): bool 62 | { 63 | return $this->messageHelper->hasErrorMessages(); 64 | } 65 | 66 | /** 67 | * @return AbstractMessage[] 68 | */ 69 | public function getErrors(): array 70 | { 71 | return $this->messageHelper->getErrorMessages(); 72 | } 73 | 74 | abstract protected function checkResponseForErrors(?array $processedResponse): void; 75 | } 76 | -------------------------------------------------------------------------------- /Classes/Client/ClientFactory.php: -------------------------------------------------------------------------------- 1 | GoogleMapsClient::class, 27 | 'osm' => OpenStreetMapClient::class, 28 | ]; 29 | 30 | public function __construct(protected MapHelper $mapHelper) {} 31 | 32 | public function create(): ClientInterface 33 | { 34 | /** @var ClientInterface $client */ 35 | $client = GeneralUtility::makeInstance( 36 | $this->mapping[$this->mapHelper->getMapProvider()], 37 | ); 38 | 39 | return $client; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Classes/Client/ClientInterface.php: -------------------------------------------------------------------------------- 1 | messageHelper->addFlashMessage( 28 | 'The response of Google Maps was not a valid JSON response.', 29 | 'Invalid JSON response', 30 | ContextualFeedbackSeverity::ERROR, 31 | ); 32 | } elseif ($processedResponse['status'] !== 'OK') { 33 | if ($processedResponse['status'] === 'ZERO_RESULTS') { 34 | $this->messageHelper->addFlashMessage( 35 | LocalizationUtility::translate( 36 | 'error.noPositionsFound.body', 37 | 'maps2', 38 | [ 39 | 0 => $this->title, 40 | ], 41 | ), 42 | LocalizationUtility::translate( 43 | 'error.noPositionsFound.title', 44 | 'maps2', 45 | ), 46 | ContextualFeedbackSeverity::ERROR, 47 | ); 48 | } else { 49 | $this->messageHelper->addFlashMessage( 50 | $processedResponse['error_message'], 51 | 'Error', 52 | ContextualFeedbackSeverity::ERROR, 53 | ); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Classes/Client/OpenStreetMapClient.php: -------------------------------------------------------------------------------- 1 | messageHelper->addFlashMessage( 28 | 'The response of Open Street Map was not a valid JSON response.', 29 | 'Invalid JSON response', 30 | ContextualFeedbackSeverity::ERROR, 31 | ); 32 | } elseif ($processedResponse === []) { 33 | $this->messageHelper->addFlashMessage( 34 | LocalizationUtility::translate( 35 | 'error.noPositionsFound.body', 36 | 'maps2', 37 | [ 38 | 0 => $this->title, 39 | ], 40 | ), 41 | LocalizationUtility::translate( 42 | 'error.noPositionsFound.title', 43 | 'maps2', 44 | ), 45 | ContextualFeedbackSeverity::ERROR, 46 | ); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Classes/Client/Request/AbstractRequest.php: -------------------------------------------------------------------------------- 1 | uri; 31 | } 32 | 33 | public function setUri(string $uri): void 34 | { 35 | $this->uri = trim($uri); 36 | } 37 | 38 | public function getParameters(): array 39 | { 40 | return $this->parameters; 41 | } 42 | 43 | public function setParameters(array $parameters): void 44 | { 45 | $this->parameters = $parameters; 46 | } 47 | 48 | /** 49 | * @param mixed $value 50 | */ 51 | public function addParameter(string $parameter, $value): void 52 | { 53 | $this->parameters[$parameter] = $value; 54 | } 55 | 56 | /** 57 | * @return mixed 58 | */ 59 | public function getParameter(string $parameter) 60 | { 61 | return $this->parameters[$parameter] ?? null; 62 | } 63 | 64 | public function hasParameter(string $parameter): bool 65 | { 66 | return array_key_exists($parameter, $this->parameters); 67 | } 68 | 69 | /** 70 | * Prepare address for an uri 71 | * Further it will add some additional information like country 72 | */ 73 | protected function updateAddressForUri(string $address): string 74 | { 75 | // if address can be interpreted as zip, attach the default country to prevent a worldwide search 76 | if ( 77 | MathUtility::canBeInterpretedAsInteger($address) 78 | && $this->extConf->getDefaultCountry() !== '' 79 | ) { 80 | $address .= ' ' . $this->extConf->getDefaultCountry(); 81 | } 82 | 83 | return rawurlencode($address); 84 | } 85 | 86 | public function isValidRequest(): bool 87 | { 88 | if ($this->getUri() === '') { 89 | return false; 90 | } 91 | 92 | return (bool)filter_var($this->getUri(), FILTER_VALIDATE_URL); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Classes/Client/Request/GoogleMaps/GeocodeRequest.php: -------------------------------------------------------------------------------- 1 | uri = $this->extConf->getGoogleMapsGeocodeUri(); 29 | } 30 | 31 | /** 32 | * Get URI for Geocode 33 | * 34 | * @throws \Exception 35 | */ 36 | public function getUri(): string 37 | { 38 | if ($this->uri === '') { 39 | return ''; 40 | } 41 | 42 | if (!$this->hasParameter('address')) { 43 | return $this->uri; 44 | } 45 | 46 | return sprintf( 47 | $this->uri, 48 | $this->updateAddressForUri( 49 | (string)$this->getParameter('address'), 50 | ), 51 | $this->extConf->getGoogleMapsGeocodeApiKey(), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Classes/Client/Request/OpenStreetMap/GeocodeRequest.php: -------------------------------------------------------------------------------- 1 | uri = $this->extConf->getOpenStreetMapGeocodeUri(); 29 | } 30 | 31 | /** 32 | * Get URI for Geocode 33 | * 34 | * @throws \Exception 35 | */ 36 | public function getUri(): string 37 | { 38 | if ($this->uri === '') { 39 | return ''; 40 | } 41 | 42 | if (!$this->hasParameter('address')) { 43 | return $this->uri; 44 | } 45 | 46 | return sprintf( 47 | $this->uri, 48 | $this->updateAddressForUri( 49 | (string)$this->getParameter('address'), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Classes/Client/Request/RequestFactory.php: -------------------------------------------------------------------------------- 1 | 'JWeiland\\Maps2\\Client\\Request\\GoogleMaps', 25 | 'osm' => 'JWeiland\\Maps2\\Client\\Request\\OpenStreetMap', 26 | ]; 27 | 28 | public function __construct(protected MapHelper $mapHelper) {} 29 | 30 | /** 31 | * Create a new Request by its filename 32 | * 33 | * @throws \Exception 34 | */ 35 | public function create(string $filename): RequestInterface 36 | { 37 | $className = sprintf( 38 | '%s\\%s', 39 | $this->mapping[$this->mapHelper->getMapProvider()], 40 | $this->sanitizeFilename($filename), 41 | ); 42 | 43 | if (!class_exists($className)) { 44 | throw new \RuntimeException( 45 | sprintf('Class "%s" to create a new Request could not be found', $className), 46 | 1733471535, 47 | ); 48 | } 49 | 50 | /** @var RequestInterface $request */ 51 | $request = GeneralUtility::makeInstance($className); 52 | 53 | return $request; 54 | } 55 | 56 | protected function sanitizeFilename(string $filename): string 57 | { 58 | return ucfirst(GeneralUtility::split_fileref($filename)['filebody']); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Classes/Client/Request/RequestInterface.php: -------------------------------------------------------------------------------- 1 | geoCodeService = $geoCodeService; 36 | } 37 | 38 | public function initializeObject(): void 39 | { 40 | $this->settings = $this->settingsHelper->getMergedSettings(); 41 | } 42 | 43 | protected function initializeView($view): void 44 | { 45 | $contentRecord = $this->request->getAttribute('currentContentObject')->data; 46 | 47 | // Remove unneeded columns from tt_content array 48 | unset( 49 | $contentRecord['pi_flexform'], 50 | $contentRecord['l18n_diffsource'], 51 | ); 52 | 53 | $view->assign('data', $contentRecord); 54 | $view->assign('environment', [ 55 | 'settings' => $this->settingsHelper->getPreparedSettings($this->settings), 56 | 'extConf' => ObjectAccess::getGettableProperties($this->extConf), 57 | 'id' => $this->getPageArguments()->getPageId(), 58 | 'contentRecord' => $contentRecord, 59 | ]); 60 | } 61 | 62 | public function showAction(): ResponseInterface 63 | { 64 | return $this->htmlResponse(); 65 | } 66 | 67 | public function searchAction(string $street): ResponseInterface 68 | { 69 | $position = $this->geoCodeService->getFirstFoundPositionByAddress( 70 | strip_tags($street) . ' ' . $this->settings['autoAppend'], 71 | ); 72 | 73 | if ($position instanceof Position) { 74 | $this->view->assign('latitude', $position->getLatitude()); 75 | $this->view->assign('longitude', $position->getLongitude()); 76 | $this->view->assign('address', rawurldecode($street)); 77 | } 78 | 79 | return $this->htmlResponse(); 80 | } 81 | 82 | protected function getPageArguments(): PageArguments 83 | { 84 | return $this->request->getAttribute('routing'); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Classes/Controller/Traits/InjectExtConfTrait.php: -------------------------------------------------------------------------------- 1 | extConf = $extConf; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Classes/Controller/Traits/InjectGeoCodeServiceTrait.php: -------------------------------------------------------------------------------- 1 | geoCodeService = $geoCodeService; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Classes/Controller/Traits/InjectLinkHelperTrait.php: -------------------------------------------------------------------------------- 1 | linkHelper = $linkHelper; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Classes/Controller/Traits/InjectPoiCollectionRepositoryTrait.php: -------------------------------------------------------------------------------- 1 | poiCollectionRepository = $poiCollectionRepository; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Classes/Controller/Traits/InjectSettingsHelperTrait.php: -------------------------------------------------------------------------------- 1 | settingsHelper = $settingsHelper; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Classes/Domain/Model/Position.php: -------------------------------------------------------------------------------- 1 | formattedAddress; 29 | } 30 | 31 | public function setFormattedAddress(string $formattedAddress): void 32 | { 33 | $this->formattedAddress = $formattedAddress; 34 | } 35 | 36 | public function getLatitude(): float 37 | { 38 | return $this->latitude; 39 | } 40 | 41 | public function setLatitude(float $latitude): void 42 | { 43 | $this->latitude = $latitude; 44 | } 45 | 46 | public function getLongitude(): float 47 | { 48 | return $this->longitude; 49 | } 50 | 51 | public function setLongitude(float $longitude): void 52 | { 53 | $this->longitude = $longitude; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Classes/Domain/Model/Search.php: -------------------------------------------------------------------------------- 1 | address; 27 | } 28 | 29 | public function setAddress(string $address): void 30 | { 31 | $this->address = $address; 32 | } 33 | 34 | public function getRadius(): int 35 | { 36 | return $this->radius; 37 | } 38 | 39 | public function setRadius(int $radius): void 40 | { 41 | $this->radius = $radius; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Classes/Domain/Traits/GetExtConfTrait.php: -------------------------------------------------------------------------------- 1 | getOriginalResource(); 28 | } 29 | 30 | if ($coreFileReference instanceof CoreFileReference && $coreFileReference->getPublicUrl() !== null) { 31 | return GeneralUtility::locationHeaderUrl($coreFileReference->getPublicUrl()); 32 | } 33 | 34 | return ''; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Classes/Event/AllowCreationOfPoiCollectionEvent.php: -------------------------------------------------------------------------------- 1 | foreignLocationRecord; 30 | } 31 | 32 | public function getForeignTableName(): string 33 | { 34 | return $this->foreignTableName; 35 | } 36 | 37 | public function getForeignColumnName(): string 38 | { 39 | return $this->foreignColumnName; 40 | } 41 | 42 | public function getOptions(): array 43 | { 44 | return $this->options; 45 | } 46 | 47 | public function isValid(): bool 48 | { 49 | return $this->isValid; 50 | } 51 | 52 | public function setIsValid(bool $isValid): void 53 | { 54 | $this->isValid = $isValid; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Classes/Event/ControllerActionEventInterface.php: -------------------------------------------------------------------------------- 1 | queryBuilder; 31 | } 32 | 33 | public function getSettings(): array 34 | { 35 | return $this->settings; 36 | } 37 | 38 | public function getPoiCollectionUid(): int 39 | { 40 | return $this->poiCollectionUid; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Classes/Event/PostProcessFluidVariablesEvent.php: -------------------------------------------------------------------------------- 1 | request; 31 | } 32 | 33 | public function getControllerName(): string 34 | { 35 | return $this->request->getControllerName(); 36 | } 37 | 38 | public function getActionName(): string 39 | { 40 | return $this->request->getControllerActionName(); 41 | } 42 | 43 | public function getSettings(): array 44 | { 45 | return $this->settings; 46 | } 47 | 48 | public function getFluidVariables(): array 49 | { 50 | return $this->fluidVariables; 51 | } 52 | 53 | public function addFluidVariable(string $key, $value): void 54 | { 55 | $this->fluidVariables[$key] = $value; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Classes/Event/PostProcessPoiCollectionRecordEvent.php: -------------------------------------------------------------------------------- 1 | poiCollectionTableName; 30 | } 31 | 32 | public function getPoiCollectionUid(): int 33 | { 34 | return $this->poiCollectionUid; 35 | } 36 | 37 | public function getForeignTableName(): string 38 | { 39 | return $this->foreignTableName; 40 | } 41 | 42 | public function getForeignLocationRecord(): array 43 | { 44 | return $this->foreignLocationRecord; 45 | } 46 | 47 | public function getOptions(): array 48 | { 49 | return $this->options; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Classes/Event/PreAddForeignRecordEvent.php: -------------------------------------------------------------------------------- 1 | foreignRecord; 28 | } 29 | 30 | public function getTableName(): string 31 | { 32 | return $this->tableName; 33 | } 34 | 35 | public function getColumnName(): string 36 | { 37 | return $this->columnName; 38 | } 39 | 40 | public function setForeignRecord(array $foreignRecord): void 41 | { 42 | $this->foreignRecord = $foreignRecord; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Classes/Event/RenderInfoWindowContentEvent.php: -------------------------------------------------------------------------------- 1 | poiCollectionRecord; 31 | } 32 | 33 | /** 34 | * Keep in mind: This event was called by a Middleware. The request object is not fully compiled! 35 | * Attributes like ContentObjectRenderer are not defined until now. 36 | */ 37 | public function getRequest(): ServerRequestInterface 38 | { 39 | return $this->request; 40 | } 41 | 42 | public function getInfoWindowContent(): string 43 | { 44 | return $this->infoWindowContent; 45 | } 46 | 47 | public function setInfoWindowContent(string $infoWindowContent): void 48 | { 49 | $this->infoWindowContent = $infoWindowContent; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Classes/EventListener/PreventPageCacheForMiddlewareEventListener.php: -------------------------------------------------------------------------------- 1 | setShouldUseCachedPageData( 31 | $event->getRequest()->getHeader('ext-maps2') !== ['infoWindowContent'], 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Classes/ExpressionLanguage/AllowMapProviderRequestConditionProvider.php: -------------------------------------------------------------------------------- 1 | expressionLanguageProviders = [ 24 | AllowMapProviderRequestFunctionsProvider::class, 25 | ]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Classes/ExpressionLanguage/AllowMapProviderRequestFunctionsProvider.php: -------------------------------------------------------------------------------- 1 | getIsRequestToMapProviderAllowed(), 33 | ]; 34 | } 35 | 36 | protected function getIsRequestToMapProviderAllowed(): ExpressionFunction 37 | { 38 | // Need local variable for static callable 39 | $mapHelper = $this->mapHelper; 40 | 41 | return new ExpressionFunction( 42 | 'isRequestToMapProviderAllowed', 43 | static function (): void { 44 | // Not implemented, we only use the evaluator 45 | }, 46 | static fn($existingVariables) => $mapHelper->isRequestToMapProviderAllowed(), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Classes/Form/FieldInformation/InfoWindowContent.php: -------------------------------------------------------------------------------- 1 | initializeResultArray(); 26 | 27 | $address = GeneralUtility::trimExplode(',', $this->data['databaseRow']['address']); 28 | 29 | $html = []; 30 | $html[] = '

' . $this->getLanguageService()->sL('LLL:EXT:maps2/Resources/Private/Language/locallang_db.xlf:info_window_content.preview') . '

'; 31 | $html[] = '
'; 32 | $html[] = '
'; 33 | $html[] = '
'; 34 | $html[] = '
' . $this->data['databaseRow']['title'] . '
' . implode('
', $address) . '

'; 35 | $html[] = '
' . $this->data['databaseRow']['info_window_content'] . '
'; 36 | $html[] = '
'; 37 | $html[] = '
'; 38 | $html[] = '
'; 39 | 40 | $resultArray['html'] = implode('', $html); 41 | 42 | return $resultArray; 43 | } 44 | 45 | protected function getLanguageService(): LanguageService 46 | { 47 | return $GLOBALS['LANG']; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Classes/Form/Resolver/MapProviderResolver.php: -------------------------------------------------------------------------------- 1 | data = $data; 34 | } 35 | 36 | /** 37 | * Returns either a map based on Google Maps or Open Street Map 38 | * 39 | * @return string New class name 40 | */ 41 | public function resolve(): string 42 | { 43 | if ($this->mapHelper->getMapProvider($this->data['databaseRow']) === 'osm') { 44 | return OpenStreetMapElement::class; 45 | } 46 | 47 | return GoogleMapsElement::class; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Classes/Helper/LinkHelper.php: -------------------------------------------------------------------------------- 1 | siteFinder = $siteFinder; 31 | } 32 | 33 | public function buildUriToCurrentPage(array $parameters, ServerRequestInterface $request): string 34 | { 35 | $router = $this->getRouter($request); 36 | if (!$router instanceof RouterInterface) { 37 | return ''; 38 | } 39 | 40 | $mergedParameters = [ 41 | '_language' => $request->getAttribute('language'), 42 | ]; 43 | 44 | ArrayUtility::mergeRecursiveWithOverrule($mergedParameters, $parameters); 45 | 46 | return (string)$router->generateUri( 47 | $this->getCurrentPageUid($request), 48 | $mergedParameters, 49 | RouterInterface::ABSOLUTE_URL, 50 | ); 51 | } 52 | 53 | protected function getRouter(ServerRequestInterface $request): ?RouterInterface 54 | { 55 | $site = $this->getCurrentSite($request); 56 | if (!$site instanceof Site) { 57 | return null; 58 | } 59 | 60 | return $site->getRouter(); 61 | } 62 | 63 | protected function getCurrentSite(ServerRequestInterface $request): ?Site 64 | { 65 | $site = $request->getAttribute('site'); 66 | if ($site instanceof Site) { 67 | return $site; 68 | } 69 | 70 | return null; 71 | } 72 | 73 | protected function getCurrentPageUid(ServerRequestInterface $request): int 74 | { 75 | $pageUid = $this->getCurrentPageUidFromRequest($request); 76 | if ($pageUid === 0) { 77 | $pageUid = $this->getCurrentPageUidFromQueryParameters($request); 78 | } 79 | 80 | return $pageUid; 81 | } 82 | 83 | protected function getCurrentPageUidFromRequest(ServerRequestInterface $request): int 84 | { 85 | $routing = $request->getAttribute('routing'); 86 | if ($routing instanceof PageArguments) { 87 | return $routing->getPageId(); 88 | } 89 | 90 | return 0; 91 | } 92 | 93 | protected function getCurrentPageUidFromQueryParameters(ServerRequestInterface $request): int 94 | { 95 | $queryParameters = $this->getQueryParameters($request); 96 | 97 | return (int)(array_key_exists('id', $queryParameters) ? $queryParameters['id'] : 0); 98 | } 99 | 100 | protected function getQueryParameters(ServerRequestInterface $request): array 101 | { 102 | if (is_array($request->getQueryParams())) { 103 | return $request->getQueryParams(); 104 | } 105 | 106 | return []; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Classes/Helper/SettingsHelper.php: -------------------------------------------------------------------------------- 1 | configurationManager = $configurationManager; 28 | } 29 | 30 | /** 31 | * This method will merge TypoScript and FlexForm settings of EXT:maps2 and should be called 32 | * by maps2 only. 33 | * Be careful using this method from within foreign extensions. The context may differ. It may happen 34 | * that FlexForm settings of your plugin will be merged with TypoScript settings of maps2. This can 35 | * lead to unforeseen miss-configuration. 36 | */ 37 | public function getMergedSettings(): array 38 | { 39 | $typoScriptSettings = $this->configurationManager->getConfiguration( 40 | ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, 41 | 'maps2', 42 | 'invalid', // invalid plugin name, to get fresh unmerged settings 43 | ); 44 | 45 | // In context of a maps2 plugin this will return the merged (TS and FlexForm) settings 46 | $mergedSettings = $this->configurationManager->getConfiguration( 47 | ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, 48 | ); 49 | 50 | foreach ($mergedSettings as $setting => $value) { 51 | if ($value === '' && isset($typoScriptSettings['settings'][$setting])) { 52 | $mergedSettings[$setting] = $typoScriptSettings['settings'][$setting]; 53 | } 54 | } 55 | 56 | return $mergedSettings; 57 | } 58 | 59 | /** 60 | * If possible you should always set $settings. In context of controllers $settings contains a merged version 61 | * of TS settings and FlexForm settings. If you don't have any settings by hand, leave empty, and we will 62 | * try to get settings from TypoScript (no FlexForm settings!!!) 63 | */ 64 | public function getPreparedSettings(array $settings = []): array 65 | { 66 | $settings = $settings ?: $this->getTypoScriptSettings(); 67 | 68 | $settings['forceZoom'] = (bool)($settings['forceZoom'] ?? false); 69 | 70 | // https://wiki.openstreetmap.org/wiki/Tile_servers tolds to use ${x} placeholders, but they don't work. 71 | if (!empty($settings['mapTile'])) { 72 | $settings['mapTile'] = str_replace( 73 | ['${s}', '${x}', '${y}', '${z}'], 74 | ['{s}', '{x}', '{y}', '{z}'], 75 | $settings['mapTile'], 76 | ); 77 | } 78 | 79 | if ( 80 | !empty($settings['markerClusterer']['enable']) 81 | && !empty($settings['markerClusterer']['imagePath']) 82 | ) { 83 | $settings['markerClusterer']['enable'] = 1; 84 | if (method_exists(PathUtility::class, 'getPublicResourceWebPath')) { 85 | $settings['markerClusterer']['imagePath'] = PathUtility::getPublicResourceWebPath($settings['markerClusterer']['imagePath']); 86 | } else { 87 | $settings['markerClusterer']['imagePath'] = PathUtility::getAbsoluteWebPath( 88 | GeneralUtility::getFileAbsFileName( 89 | $settings['markerClusterer']['imagePath'], 90 | ), 91 | ); 92 | } 93 | } 94 | 95 | return $settings; 96 | } 97 | 98 | protected function getTypoScriptSettings(): array 99 | { 100 | return $this->configurationManager->getConfiguration( 101 | ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, 102 | 'Maps2', 103 | 'Maps2', 104 | ) ?? []; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Classes/Mapper/GoogleMapsMapper.php: -------------------------------------------------------------------------------- 1 | attach($this->getPosition($data)); 29 | } 30 | 31 | return $objectStorage; 32 | } 33 | 34 | protected function getPosition(array $data): Position 35 | { 36 | $position = GeneralUtility::makeInstance(Position::class); 37 | $position->setFormattedAddress($data['formatted_address']); 38 | 39 | try { 40 | $position->setLatitude((float)ArrayUtility::getValueByPath($data, 'geometry/location/lat')); 41 | $position->setLongitude((float)ArrayUtility::getValueByPath($data, 'geometry/location/lng')); 42 | } catch (\RuntimeException) { 43 | // Path of ArrayUtility does not exist 44 | $position->setLatitude(0.0); 45 | $position->setLongitude(0.0); 46 | } 47 | 48 | return $position; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Classes/Mapper/MapperFactory.php: -------------------------------------------------------------------------------- 1 | GoogleMapsMapper::class, 24 | 'osm' => OpenStreetMapMapper::class, 25 | ]; 26 | 27 | public function __construct(protected MapHelper $mapHelper) {} 28 | 29 | public function create(): MapperInterface 30 | { 31 | /** @var MapperInterface $client */ 32 | $client = GeneralUtility::makeInstance( 33 | $this->mapping[$this->mapHelper->getMapProvider()], 34 | ); 35 | 36 | return $client; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Classes/Mapper/MapperInterface.php: -------------------------------------------------------------------------------- 1 | attach($this->getPosition($data)); 28 | } 29 | 30 | return $objectStorage; 31 | } 32 | 33 | protected function getPosition(array $data): Position 34 | { 35 | $position = GeneralUtility::makeInstance(Position::class); 36 | $position->setFormattedAddress($this->getFormattedAddress($data)); 37 | $position->setLatitude((float)($data['lat'] ?? 0.0)); 38 | $position->setLongitude((float)($data['lon'] ?? 0.0)); 39 | 40 | return $position; 41 | } 42 | 43 | /** 44 | * Extract address parts from Response to build a formatted address 45 | */ 46 | protected function getFormattedAddress(array $data): string 47 | { 48 | if (array_key_exists('address', $data)) { 49 | $data['address']['city'] = $this->getCityFromAddress($data['address']); 50 | 51 | $formattedAddress = sprintf( 52 | '%s %s, %s %s, %s', 53 | $data['address']['road'] ?? $data['address']['footway'] ?? '', 54 | $data['address']['house_number'] ?? '', 55 | $data['address']['postcode'] ?? '', 56 | $data['address']['city'], 57 | $data['address']['country'] ?? '', 58 | ); 59 | } else { 60 | // 'display_name' can be a very long name. 61 | // We hope address key is set above to return a reduced formattedAddress 62 | $formattedAddress = $data['display_name']; 63 | } 64 | 65 | return trim((string)$formattedAddress, " ,\t\n\r\0\x0B"); 66 | } 67 | 68 | /** 69 | * Open Street Map differs between small and big cities. 70 | * That's why we have to check each kind of city size to get the city name itself. 71 | */ 72 | protected function getCityFromAddress(array $address): string 73 | { 74 | $sortedCityTypes = ['village', 'town', 'city']; 75 | $city = ''; 76 | 77 | foreach ($sortedCityTypes as $type) { 78 | if (array_key_exists($type, $address)) { 79 | $city = $address[$type]; 80 | } 81 | } 82 | 83 | return $city; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Classes/Middleware/GetInfoWindowContentMiddleware.php: -------------------------------------------------------------------------------- 1 | getHeader('ext-maps2') !== ['infoWindowContent']) { 35 | return $handler->handle($request); 36 | } 37 | 38 | $postData = $this->getPostData($request); 39 | 40 | if (isset($postData['error'])) { 41 | return new JsonResponse($postData); 42 | } 43 | 44 | if (!array_key_exists('poiCollection', $postData)) { 45 | return new JsonResponse([ 46 | 'error' => 'No POI collection provided', 47 | ]); 48 | } 49 | 50 | $poiCollectionUid = (int)$postData['poiCollection']; 51 | 52 | if ($poiCollectionUid === 0) { 53 | return new JsonResponse([ 54 | 'error' => 'POI collection UID can not be empty', 55 | ]); 56 | } 57 | 58 | $poiCollectionRecord = $this->poiCollectionService->findByUid($poiCollectionUid, $request); 59 | 60 | if ($poiCollectionRecord === null) { 61 | return new JsonResponse([ 62 | 'error' => 'No POI collection record with requested UID found', 63 | ]); 64 | } 65 | 66 | return new JsonResponse([ 67 | 'content' => $this->infoWindowContentService->render($poiCollectionRecord, $request), 68 | ]); 69 | } 70 | 71 | protected function getPostData(ServerRequestInterface $request): array 72 | { 73 | try { 74 | $payload = json_decode((string)$request->getBody(), true, 512, JSON_THROW_ON_ERROR); 75 | } catch (\JsonException) { 76 | $payload = [ 77 | 'errors' => [ 78 | 'Given post stream does not contain valid JSON string', 79 | ], 80 | ]; 81 | } 82 | 83 | return is_array($payload) ? $payload : []; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Classes/Middleware/InitFeSessionMiddleware.php: -------------------------------------------------------------------------------- 1 | handle($request); 40 | if ( 41 | $this->extConf->getExplicitAllowMapProviderRequests() 42 | && $this->mapHelper->isRequestToMapProviderAllowed() 43 | ) { 44 | $cookie = $this->createCookie($request); 45 | $response = $response->withAddedHeader('Set-Cookie', $cookie->__toString()); 46 | } 47 | 48 | return $response; 49 | } 50 | 51 | protected function createCookie(ServerRequestInterface $request): Cookie 52 | { 53 | $normalizedParams = $request->getAttribute('normalizedParams'); 54 | 55 | // Store consent in COOKIE 56 | $cookieSameSite = $this->sanitizeSameSiteCookieValue( 57 | strtolower($GLOBALS['TYPO3_CONF_VARS']['BE']['cookieSameSite'] ?? Cookie::SAMESITE_STRICT), 58 | ); 59 | 60 | // SameSite Cookie = None needs the secure option (only allowed on HTTPS) 61 | $isSecure = $cookieSameSite === Cookie::SAMESITE_NONE || $normalizedParams->isHttps(); 62 | 63 | return new Cookie( 64 | 'mapProviderRequestsAllowedForMaps2', 65 | '1', 66 | $this->getCookieExpire(), 67 | $normalizedParams->getSitePath(), 68 | null, 69 | $isSecure, 70 | false, // Should be false to allow JS based consent tools to delete this cookie 71 | false, 72 | $cookieSameSite, 73 | ); 74 | } 75 | 76 | protected function getCookieExpire(): int 77 | { 78 | // If COOKIE is activated, set expire to FE sessionDataLifetime which is 1 day by default 79 | $maxSessionLifetime = $GLOBALS['TYPO3_CONF_VARS']['FE']['sessionDataLifetime'] ?? 60 * 60 * 24; 80 | $expire = GeneralUtility::makeInstance(Context::class) 81 | ->getPropertyFromAspect('date', 'timestamp') + $maxSessionLifetime; 82 | 83 | // If session only is activated, $expire = 0 will delete our created COOKIE after closing the browser 84 | if ($this->extConf->getExplicitAllowMapProviderRequestsBySessionOnly()) { 85 | $expire = 0; 86 | } 87 | 88 | return (int)$expire; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Classes/Service/CacheService.php: -------------------------------------------------------------------------------- 1 | isFrontendEnvironment()) { 37 | throw new \RuntimeException( 38 | 'getCacheIdentifier can only be called from FE, as we have to add the true language ID to PoiCollection', 39 | 1733471017, 40 | ); 41 | } 42 | 43 | // We do not add the original sys_language_uid of PoiCollection, as it can be the same for different languages. 44 | $poiCollection['language'] = $this->getLanguageUid(); 45 | 46 | return sprintf( 47 | '%s%s', 48 | $prefix, 49 | $this->hashService->hmac( 50 | \json_encode(array_diff_key($poiCollection, ['uid', 'pid', 'language', 'title', 'address'])), 51 | $prefix, 52 | ), 53 | ); 54 | } 55 | 56 | /** 57 | * Add UID and PID of PoiCollection as Cache-Tags to Cache-Entry. 58 | * Please do not use "infoWindowPid" and "infoWindowUid" as Cache-Tag-Prefix in your template, 59 | * as we will override them here. 60 | */ 61 | public function getCacheTags(array $poiCollection, array $cacheTags = []): array 62 | { 63 | return array_merge( 64 | $cacheTags, 65 | [ 66 | 'infoWindowPid' . ($poiCollection['pid'] ?? 0), 67 | 'infoWindowUid' . ($poiCollection['uid'] ?? 0), 68 | ], 69 | ); 70 | } 71 | 72 | /** 73 | * Returns the calculated (incl. fallback) sys_language_uid 74 | * 75 | * @throws \Exception 76 | */ 77 | protected function getLanguageUid(): int 78 | { 79 | if (!$this->isFrontendEnvironment()) { 80 | throw new \RuntimeException( 81 | 'getLanguageId can only be called from FE, as we have to add the true language ID to PoiCollection', 82 | 1733470968, 83 | ); 84 | } 85 | 86 | return (int)GeneralUtility::makeInstance(Context::class) 87 | ->getPropertyFromAspect('language', 'id'); 88 | } 89 | 90 | protected function isFrontendEnvironment(): bool 91 | { 92 | return defined('TYPO3') && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Classes/Service/GeoCodeService.php: -------------------------------------------------------------------------------- 1 | client = $clientFactory->create(); 40 | } 41 | 42 | /** 43 | * @return ObjectStorage|Position[] 44 | * @throws \Exception 45 | */ 46 | public function getPositionsByAddress(string $address): ObjectStorage 47 | { 48 | $positions = new ObjectStorage(); 49 | 50 | // Prevent calls to Map Providers GeoCode API, if address is empty 51 | if (trim($address) === '') { 52 | return $positions; 53 | } 54 | 55 | $geocodeRequest = $this->requestFactory->create('GeocodeRequest'); 56 | $geocodeRequest->addParameter('address', $address); 57 | 58 | $response = $this->client->processRequest($geocodeRequest); 59 | if ($response !== []) { 60 | $positions = $this->mapperFactory->create()->map($response); 61 | } 62 | 63 | return $positions; 64 | } 65 | 66 | public function getFirstFoundPositionByAddress(string $address): ?Position 67 | { 68 | $position = null; 69 | $positions = $this->getPositionsByAddress($address); 70 | if ($positions->count() !== 0) { 71 | $positions->rewind(); 72 | /** @var Position $position */ 73 | $position = $positions->current(); 74 | } 75 | 76 | return $position; 77 | } 78 | 79 | public function hasErrors(): bool 80 | { 81 | return $this->client->hasErrors(); 82 | } 83 | 84 | /** 85 | * @return FlashMessage[] 86 | */ 87 | public function getErrors(): array 88 | { 89 | return $this->client->getErrors(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Classes/Service/MapProviderRequestService.php: -------------------------------------------------------------------------------- 1 | mapHelper->isRequestToMapProviderAllowed(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Classes/Service/PoiCollectionService.php: -------------------------------------------------------------------------------- 1 | getQueryBuilder($request); 40 | 41 | try { 42 | $poiCollectionRecord = $queryBuilder 43 | ->select('*') 44 | ->from(self::TABLE) 45 | ->where( 46 | $queryBuilder->expr()->eq( 47 | 'uid', 48 | $queryBuilder->createNamedParameter($poiCollectionUid, Connection::PARAM_INT), 49 | ), 50 | ) 51 | ->executeQuery() 52 | ->fetchAssociative(); 53 | } catch (Exception) { 54 | return null; 55 | } 56 | 57 | if (is_array($poiCollectionRecord)) { 58 | $this->pageRepository->versionOL(self::TABLE, $poiCollectionRecord); 59 | if (is_array($poiCollectionRecord)) { 60 | $poiCollectionRecord = $this->pageRepository->getLanguageOverlay( 61 | self::TABLE, 62 | $poiCollectionRecord, 63 | ); 64 | } 65 | } 66 | 67 | return is_array($poiCollectionRecord) ? $poiCollectionRecord : null; 68 | } 69 | 70 | private function getQueryBuilder(ServerRequestInterface $request): QueryBuilder 71 | { 72 | $queryBuilder = $this->queryBuilder; 73 | 74 | if (ApplicationType::fromRequest($request)->isFrontend()) { 75 | $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class)); 76 | } else { 77 | $queryBuilder 78 | ->getRestrictions() 79 | ->removeAll() 80 | ->add(GeneralUtility::makeInstance(DeletedRestriction::class)); 81 | } 82 | 83 | return $queryBuilder; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Classes/Tca/Type/FloatType.php: -------------------------------------------------------------------------------- 1 | 'maps2_maps2', 27 | 'maps2_overlay' => 'maps2_overlay', 28 | 'maps2_searchwithinradius' => 'maps2_searchwithinradius', 29 | 'maps2_citymap' => 'maps2_citymap', 30 | ]; 31 | } 32 | 33 | public function getTitle(): string 34 | { 35 | return 'Migrate plugins to Content Elements'; 36 | } 37 | 38 | public function getDescription(): string 39 | { 40 | return 'The modern way to register plugins for TYPO3 is to register them as content element types. ' . 41 | 'Running this wizard will migrate all maps2 plugins to content element (CType)'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Classes/Update/NewGeocodeUriForOsmUpdate.php: -------------------------------------------------------------------------------- 1 | getOsmGeocodeUri() === $this->oldOsmGeocodeUri; 47 | } 48 | 49 | public function executeUpdate(): bool 50 | { 51 | if ($this->getOsmGeocodeUri() === $this->oldOsmGeocodeUri) { 52 | try { 53 | $maps2ExtensionConfiguration = $this->getExtensionConfiguration()->get('maps2'); 54 | if ( 55 | is_array($maps2ExtensionConfiguration) 56 | && array_key_exists('openStreetMapGeocodeUri', $maps2ExtensionConfiguration) 57 | ) { 58 | $maps2ExtensionConfiguration['openStreetMapGeocodeUri'] = $this->newOsmGeocodeUri; 59 | $this->getExtensionConfiguration()->set( 60 | 'maps2', 61 | $maps2ExtensionConfiguration, 62 | ); 63 | } 64 | 65 | return true; 66 | } catch (ExtensionConfigurationExtensionNotConfiguredException | ExtensionConfigurationPathDoesNotExistException) { 67 | } 68 | } 69 | 70 | return false; 71 | } 72 | 73 | private function getOsmGeocodeUri(): string 74 | { 75 | try { 76 | return $this->getExtensionConfiguration()->get('maps2', 'openStreetMapGeocodeUri'); 77 | } catch (ExtensionConfigurationExtensionNotConfiguredException | ExtensionConfigurationPathDoesNotExistException) { 78 | return ''; 79 | } 80 | } 81 | 82 | private function getExtensionConfiguration(): ExtensionConfiguration 83 | { 84 | return GeneralUtility::makeInstance(ExtensionConfiguration::class); 85 | } 86 | 87 | private function getTypo3Version(): Typo3Version 88 | { 89 | return GeneralUtility::makeInstance(Typo3Version::class); 90 | } 91 | 92 | public function getPrerequisites(): array 93 | { 94 | return []; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Classes/Utility/DatabaseUtility.php: -------------------------------------------------------------------------------- 1 | getConnectionForTable($tableName); 32 | try { 33 | return $connection->createSchemaManager()->listTableColumns($tableName); 34 | } catch (Exception) { 35 | } 36 | 37 | return []; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/Cache/GetCacheViewHelper.php: -------------------------------------------------------------------------------- 1 | registerArgument( 36 | 'prefix', 37 | 'string', 38 | 'A prefix for the cache identifier.', 39 | false, 40 | 'infoWindow', 41 | ); 42 | $this->registerArgument( 43 | 'poiCollection', 44 | 'array', 45 | 'We need the PoiCollection record to build a better language independent CacheIdentifier.', 46 | true, 47 | ); 48 | } 49 | 50 | /** 51 | * Returns cache entry by given cache identifier 52 | * Info: here is no check if cache entry exists. Please use maps:cache.hasCache instead/before 53 | */ 54 | public function render(): string 55 | { 56 | $poiCollectionRecord = $this->arguments['poiCollection']; 57 | 58 | try { 59 | return $this->cache->get( 60 | $this->cacheService->getCacheIdentifier( 61 | $poiCollectionRecord, 62 | $this->arguments['prefix'], 63 | ), 64 | ); 65 | } catch (\Exception) { 66 | } 67 | 68 | return ''; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/Cache/HasCacheViewHelper.php: -------------------------------------------------------------------------------- 1 | registerArgument( 31 | 'prefix', 32 | 'string', 33 | 'A prefix for the cache identifier.', 34 | false, 35 | 'infoWindow', 36 | ); 37 | $this->registerArgument( 38 | 'poiCollection', 39 | 'array', 40 | 'We need the PoiCollection record to build a better language independent CacheIdentifier.', 41 | true, 42 | ); 43 | } 44 | 45 | /** 46 | * Checks if caching framework has the requested cache entry 47 | */ 48 | public function render(): bool 49 | { 50 | $poiCollectionRecord = $this->arguments['poiCollection']; 51 | 52 | try { 53 | return $this->cache->has( 54 | $this->cacheService->getCacheIdentifier( 55 | $poiCollectionRecord, 56 | $this->arguments['prefix'], 57 | ), 58 | ); 59 | } catch (\Exception) { 60 | } 61 | 62 | return false; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/Cache/SetCacheViewHelper.php: -------------------------------------------------------------------------------- 1 | registerArgument( 36 | 'prefix', 37 | 'string', 38 | 'A prefix for the cache identifier.', 39 | false, 40 | 'infoWindow', 41 | ); 42 | $this->registerArgument( 43 | 'poiCollection', 44 | 'array', 45 | 'We need the PoiCollection record to build a better language independent CacheIdentifier.', 46 | true, 47 | ); 48 | $this->registerArgument( 49 | 'data', 50 | 'string', 51 | 'The data to be stored', 52 | true, 53 | ); 54 | $this->registerArgument( 55 | 'tags', 56 | 'array', 57 | 'Tags to associate with this cache entry', 58 | false, 59 | [], 60 | ); 61 | $this->registerArgument( 62 | 'lifetime', 63 | 'int', 64 | 'Lifetime of this cache entry in seconds. If null is specified, the default lifetime is used. "0" means unlimited lifetime', 65 | ); 66 | } 67 | 68 | /** 69 | * Saves data in a cache file. 70 | */ 71 | public function render(): void 72 | { 73 | $poiCollectionRecord = $this->arguments['poiCollection']; 74 | 75 | try { 76 | $this->cache->set( 77 | $this->cacheService->getCacheIdentifier($poiCollectionRecord, $this->arguments['prefix']), 78 | $this->arguments['data'], 79 | $this->cacheService->getCacheTags($poiCollectionRecord, $this->arguments['tags']), 80 | ($this->arguments['lifetime'] === null ? null : (int)$this->arguments['lifetime']), 81 | ); 82 | } catch (\Exception) { 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/ConvertToJsonViewHelper.php: -------------------------------------------------------------------------------- 1 | renderChildren(); 43 | 44 | if ($poiCollections instanceof PoiCollection) { 45 | $poiCollections = [$poiCollections]; 46 | } 47 | 48 | try { 49 | if (self::valueContainsPoiCollections($poiCollections)) { 50 | $json = self::getPoiCollectionsAsJson($poiCollections); 51 | } else { 52 | $json = json_encode($poiCollections, JSON_THROW_ON_ERROR); 53 | } 54 | } catch (\JsonException) { 55 | $json = '{}'; 56 | } 57 | 58 | return htmlspecialchars($json); 59 | } 60 | 61 | /** 62 | * Convert poiCollections to array and pass them through json_encode 63 | * 64 | * @param PoiCollection[] $poiCollections 65 | */ 66 | protected function getPoiCollectionsAsJson(array|QueryResultInterface|ObjectStorage $poiCollections): string 67 | { 68 | $poiCollectionsAsArray = []; 69 | foreach ($poiCollections as $poiCollection) { 70 | $poiCollectionAsArray = ObjectAccess::getGettableProperties($poiCollection); 71 | unset($poiCollectionAsArray['markerIcons']); 72 | 73 | $poiCollectionAsArray['categories'] = []; 74 | /** @var Category $category */ 75 | foreach ($poiCollection->getCategories() as $category) { 76 | $categoryProperties = ObjectAccess::getGettableProperties($category); 77 | unset($categoryProperties['maps2MarkerIcons'], $categoryProperties['parent']); 78 | $poiCollectionAsArray['categories'][] = $categoryProperties; 79 | } 80 | 81 | $poiCollectionsAsArray[] = $poiCollectionAsArray; 82 | } 83 | 84 | try { 85 | return json_encode($poiCollectionsAsArray, JSON_THROW_ON_ERROR); 86 | } catch (\JsonException $e) { 87 | return '{}'; 88 | } 89 | } 90 | 91 | /** 92 | * Check, if value contains entries of type PoiCollection 93 | */ 94 | protected function valueContainsPoiCollections(mixed $value): bool 95 | { 96 | // With PHP 8.1 reset() and current() should not be used with objects anymore. 97 | // Extract the values as simple array to be compatible in the future. 98 | if ($value instanceof \ArrayObject) { 99 | $value = $value->getArrayCopy(); 100 | } 101 | 102 | $containsPoiCollections = false; 103 | if (is_array($value)) { 104 | reset($value); 105 | $poiCollection = current($value); 106 | $containsPoiCollections = $poiCollection instanceof PoiCollection; 107 | } elseif ($value instanceof \Iterator) { 108 | $value->rewind(); 109 | $poiCollection = $value->current(); 110 | $containsPoiCollections = $poiCollection instanceof PoiCollection; 111 | } 112 | 113 | return $containsPoiCollections; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/Form/HiddenViewHelper.php: -------------------------------------------------------------------------------- 1 | ` tag. 18 | * This VH is a copy of the original f:hidden VH with ONE difference: 19 | * It adds a required __identity flag for property 20 | * Many other f:form.* VHs do so, but f:hidden not. Don't know why. 21 | * Remove this VH, if this is resolved: https://forge.typo3.org/issues/90331 22 | */ 23 | class HiddenViewHelper extends AbstractFormFieldViewHelper 24 | { 25 | /** 26 | * @var string 27 | */ 28 | protected $tagName = 'input'; 29 | 30 | public function initializeArguments(): void 31 | { 32 | parent::initializeArguments(); 33 | } 34 | 35 | /** 36 | * Renders the hidden field. 37 | */ 38 | public function render(): string 39 | { 40 | $name = $this->getName(); 41 | $this->registerFieldNameForFormTokenGeneration($name); 42 | $this->setRespectSubmittedDataValue(true); 43 | 44 | $this->tag->addAttribute('type', 'hidden'); 45 | $this->tag->addAttribute('name', $name); 46 | $this->tag->addAttribute('value', $this->getValueAttribute()); 47 | 48 | // Add required __identify field 49 | $this->addAdditionalIdentityPropertiesIfNeeded(); 50 | 51 | return $this->tag->render(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/GetEnvironmentViewHelper.php: -------------------------------------------------------------------------------- 1 | renderingContext->getVariableProvider(); 47 | $extbaseRequest = self::getExtbaseRequest($this->renderingContext); 48 | if (!$extbaseRequest instanceof RequestInterface) { 49 | return ''; 50 | } 51 | 52 | $templateVariableContainer->add( 53 | 'environment', 54 | [ 55 | 'settings' => $this->settingsHelper->getPreparedSettings(), 56 | 'extConf' => ObjectAccess::getGettableProperties($this->extConf), 57 | 'ajaxUrl' => $this->linkHelper->buildUriToCurrentPage([], $extbaseRequest), 58 | 'contentRecord' => $extbaseRequest->getAttribute('currentContentObject')->data, 59 | ], 60 | ); 61 | 62 | $content = $this->renderChildren(); 63 | 64 | $templateVariableContainer->remove('environment'); 65 | 66 | return $content; 67 | } 68 | 69 | private function getExtbaseRequest(RenderingContextInterface $renderingContext): ?RequestInterface 70 | { 71 | if ( 72 | $renderingContext instanceof RenderingContext 73 | && $renderingContext->hasAttribute(ServerRequestInterface::class) 74 | && $renderingContext->getAttribute(ServerRequestInterface::class) instanceof RequestInterface 75 | ) { 76 | return $renderingContext->getAttribute(ServerRequestInterface::class); 77 | } 78 | 79 | return null; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/IsRequestToMapProviderAllowedViewHelper.php: -------------------------------------------------------------------------------- 1 | mapHelper->isRequestToMapProviderAllowed(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/RequestUriForOverlayViewHelper.php: -------------------------------------------------------------------------------- 1 | registerArgument( 33 | 'ttContentUid', 34 | 'int', 35 | 'The tt_content UID of the record which shows the map', 36 | false, 37 | 0, 38 | ); 39 | } 40 | 41 | /** 42 | * Convert all array and object types into a json string. Useful for data-Attributes 43 | */ 44 | public function render(): string 45 | { 46 | $uriBuilder = $this->uriBuilder 47 | ->reset() 48 | ->setAddQueryString('untrusted') 49 | ->setArguments([ 50 | 'tx_maps2_maps2' => [ 51 | 'mapProviderRequestsAllowedForMaps2' => 1, 52 | ], 53 | ]) 54 | ->setArgumentsToBeExcludedFromQueryString(['cHash']); 55 | 56 | if (($this->settingsHelper->getPreparedSettings()['overlay']['link']['addSection'] ?? '') === '1') { 57 | $ttContentUid = (int)($arguments['ttContentUid'] ?? 0); 58 | if ($ttContentUid) { 59 | $uriBuilder->setSection('c' . $ttContentUid); 60 | } 61 | } 62 | 63 | $request = $this->renderingContext->getAttribute(ServerRequestInterface::class); 64 | $this->uriBuilder->setRequest($request); 65 | 66 | return $uriBuilder->build(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Classes/ViewHelpers/TrimExplodeViewHelper.php: -------------------------------------------------------------------------------- 1 | registerArgument( 25 | 'delimiter', 26 | 'string', 27 | 'The delimiter where the string should be exploded', 28 | false, 29 | ',', 30 | ); 31 | } 32 | 33 | /** 34 | * Implements a ViewHelper to trim explode comma separated strings 35 | * 36 | * @return string[] 37 | */ 38 | public function render(): array 39 | { 40 | return GeneralUtility::trimExplode($this->arguments['delimiter'], $this->renderChildren()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Configuration/ExpressionLanguage.php: -------------------------------------------------------------------------------- 1 | [ 14 | AllowMapProviderRequestConditionProvider::class, 15 | ], 16 | ]; 17 | -------------------------------------------------------------------------------- /Configuration/Extbase/Persistence/Classes.php: -------------------------------------------------------------------------------- 1 | [ 23 | 'tableName' => 'sys_category', 24 | 'properties' => [], 25 | ], 26 | ]; 27 | -------------------------------------------------------------------------------- /Configuration/Icons.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'provider' => SvgIconProvider::class, 16 | 'source' => 'EXT:maps2/Resources/Public/Icons/plugin_wizard.svg', 17 | ], 18 | 'ext-maps2-record-type-point' => [ 19 | 'provider' => BitmapIconProvider::class, 20 | 'source' => 'EXT:maps2/Resources/Public/Icons/RecordTypePoint.png', 21 | ], 22 | 'ext-maps2-record-type-area' => [ 23 | 'provider' => BitmapIconProvider::class, 24 | 'source' => 'EXT:maps2/Resources/Public/Icons/RecordTypeArea.png', 25 | ], 26 | 'ext-maps2-record-type-route' => [ 27 | 'provider' => BitmapIconProvider::class, 28 | 'source' => 'EXT:maps2/Resources/Public/Icons/RecordTypeRoute.png', 29 | ], 30 | 'ext-maps2-record-type-radius' => [ 31 | 'provider' => BitmapIconProvider::class, 32 | 'source' => 'EXT:maps2/Resources/Public/Icons/RecordTypeRadius.png', 33 | ], 34 | ]; 35 | -------------------------------------------------------------------------------- /Configuration/JavaScriptModules.php: -------------------------------------------------------------------------------- 1 | [ 12 | 'backend', 13 | 'core', 14 | ], 15 | 'imports' => [ 16 | '@jweiland/maps2/' => [ 17 | 'path' => 'EXT:maps2/Resources/Public/JavaScript/', 18 | 'exclude' => [ 19 | 'EXT:maps2/Resources/Public/JavaScript/leaflet.min.js', 20 | ], 21 | ], 22 | 'leaflet' => 'EXT:maps2/Resources/Public/JavaScript/leaflet.min.js', 23 | ], 24 | ]; 25 | -------------------------------------------------------------------------------- /Configuration/RequestMiddlewares.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'jweiland/maps2/initialize-fe-session' => [ 16 | 'target' => InitFeSessionMiddleware::class, 17 | 'after' => [ 18 | 'typo3/cms-frontend/tsfe', 19 | ], 20 | 'before' => [ 21 | 'typo3/cms-frontend/prepare-tsfe-rendering', 22 | ], 23 | ], 24 | 'jweiland/maps2/info-window-content' => [ 25 | 'target' => GetInfoWindowContentMiddleware::class, 26 | 'after' => [ 27 | 'typo3/cms-frontend/prepare-tsfe-rendering', 28 | ], 29 | 'before' => [ 30 | 'typo3/cms-frontend/output-compression', 31 | ], 32 | ], 33 | ], 34 | ]; 35 | -------------------------------------------------------------------------------- /Configuration/Services.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | _defaults: 3 | autowire: true 4 | autoconfigure: true 5 | public: false 6 | 7 | JWeiland\Maps2\: 8 | resource: '../Classes/*' 9 | exclude: '../Classes/Domain/Model/*' 10 | 11 | cache.maps2CachedHtml: 12 | class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface 13 | factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache'] 14 | arguments: ['maps2_cachedhtml'] 15 | 16 | querybuilder.tx_maps2_domain_model_poicollection: 17 | class: 'TYPO3\CMS\Core\Database\Query\QueryBuilder' 18 | factory: 19 | - '@TYPO3\CMS\Core\Database\ConnectionPool' 20 | - 'getQueryBuilderForTable' 21 | arguments: 22 | - 'tx_maps2_domain_model_poicollection' 23 | 24 | # Called by makeInstance in TYPO3's PluginPreview 25 | JWeiland\Maps2\Backend\Preview\Maps2PluginPreview: 26 | public: true 27 | 28 | # Called by makeInstance in our RequestFactory 29 | JWeiland\Maps2\Client\Request\GoogleMaps\GeocodeRequest: 30 | public: true 31 | 32 | # Called by makeInstance in our RequestFactory 33 | JWeiland\Maps2\Client\Request\OpenStreetMap\GeocodeRequest: 34 | public: true 35 | 36 | # Called by makeInstance in our ClientFactory 37 | JWeiland\Maps2\Client\GoogleMapsClient: 38 | public: true 39 | 40 | # Called by makeInstance in our ClientFactory 41 | JWeiland\Maps2\Client\OpenStreetMapClient: 42 | public: true 43 | 44 | # Called by makeInstance in various TCA files 45 | JWeiland\Maps2\Configuration\ExtConf: 46 | public: true 47 | 48 | # Called by makeInstance in TYPO3's AbstractConditionMatcher 49 | JWeiland\Maps2\ExpressionLanguage\AllowMapProviderRequestFunctionsProvider: 50 | public: true 51 | 52 | # Called by makeInstance in TYPO3's NodeRegistry 53 | JWeiland\Maps2\Form\Element\ReadOnlyInputTextElement: 54 | public: true 55 | 56 | # Called by makeInstance in TYPO3's NodeRegistry 57 | JWeiland\Maps2\Form\FieldInformation\InfoWindowContent: 58 | public: true 59 | 60 | # Called by makeInstance in TYPO3's NodeRegistry 61 | JWeiland\Maps2\Form\Resolver\MapProviderResolver: 62 | public: true 63 | 64 | # Called by makeInstance in our PoiCollection 65 | JWeiland\Maps2\Helper\MapHelper: 66 | public: true 67 | 68 | # Called by makeInstance in our GetEnvironmentViewHelper 69 | JWeiland\Maps2\Helper\SettingsHelper: 70 | public: true 71 | 72 | # Called by makeInstance in TYPO3's DataHandler 73 | JWeiland\Maps2\Hook\CreateMaps2RecordHook: 74 | public: true 75 | 76 | # Called by makeInstance in PoiCollection model to add foreign records 77 | JWeiland\Maps2\Service\MapService: 78 | public: true 79 | 80 | JWeiland\Maps2\Service\PoiCollectionService: 81 | arguments: 82 | $queryBuilder: '@querybuilder.tx_maps2_domain_model_poicollection' 83 | 84 | JWeiland\Maps2\ViewHelpers\Cache\GetCacheViewHelper: 85 | arguments: 86 | $cache: '@cache.maps2CachedHtml' 87 | JWeiland\Maps2\ViewHelpers\Cache\HasCacheViewHelper: 88 | arguments: 89 | $cache: '@cache.maps2CachedHtml' 90 | JWeiland\Maps2\ViewHelpers\Cache\SetCacheViewHelper: 91 | arguments: 92 | $cache: '@cache.maps2CachedHtml' 93 | 94 | JWeiland\Maps2\Tca\Maps2Registry: 95 | tags: 96 | - name: event.listener 97 | method: 'addMaps2DatabaseSchemasToTablesDefinition' 98 | event: TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent 99 | -------------------------------------------------------------------------------- /Configuration/Sets/GoogleMaps/config.yaml: -------------------------------------------------------------------------------- 1 | name: jweiland/maps2-googlemaps 2 | label: Maps2 - Google Maps 3 | 4 | dependencies: 5 | - jweiland/maps2-default 6 | -------------------------------------------------------------------------------- /Configuration/Sets/GoogleMaps/settings.definitions.yaml: -------------------------------------------------------------------------------- 1 | categories: 2 | Maps2.googlemaps: 3 | label: 'Google Maps' 4 | parent: Maps2 5 | 6 | settings: 7 | maps2.enableMarkerClusterer: 8 | label: 'Enable Marker Clusterer' 9 | category: Maps2.googlemaps 10 | description: 'If you have a lot of POIs, some POIs will be joined to a single POI with the amount of joined POIs as label' 11 | type: bool 12 | default: false 13 | maps2.googleMapsJavaScriptApiKey: 14 | label: 'JavaScript API Key' 15 | category: Maps2.googlemaps 16 | description: 'Enter the Google Maps JavaScript API key which you can get from google cloud console' 17 | type: string 18 | default: '' 19 | -------------------------------------------------------------------------------- /Configuration/Sets/GoogleMaps/setup.typoscript: -------------------------------------------------------------------------------- 1 | # Prevent including both static maps of map providers on one page 2 | page.includeJSFooterlibs.markerClustererForMaps2 > 3 | 4 | [isRequestToMapProviderAllowed()] 5 | page.includeJSFooterlibs { 6 | markerClustererForMaps2 = EXT:maps2/Resources/Public/JavaScript/MarkerClusterer.js 7 | markerClustererForMaps2.if.isTrue = {$maps2.enableMarkerClusterer} 8 | } 9 | [ELSE] 10 | # Requests to Google Maps are not allowed. Inform the user about cookies and request permissions for 3rd party. 11 | tt_content.maps2_maps2.20.pluginName = Overlay 12 | tt_content.maps2_searchwithinradius.20.pluginName = Overlay 13 | tt_content.maps2_citymap.20.pluginName = Overlay 14 | [END] 15 | 16 | plugin.tx_maps2 { 17 | settings { 18 | mapProvider = gm 19 | mapTypeControl = 1 20 | scaleControl = 1 21 | streetViewControl = 1 22 | fullscreenMapControl = 1 23 | googleMapsJavaScriptApiKey = {$maps2.googleMapsJavaScriptApiKey} 24 | mapTypeId = google.maps.MapTypeId.ROADMAP 25 | markerClusterer { 26 | enable = {$maps2.enableMarkerClusterer} 27 | imagePath = EXT:maps2/Resources/Public/Icons/MarkerClusterer/m 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Configuration/Sets/Maps2/config.yaml: -------------------------------------------------------------------------------- 1 | name: jweiland/maps2-default 2 | label: Maps2 - Default Set 3 | -------------------------------------------------------------------------------- /Configuration/Sets/Maps2/settings.definitions.yaml: -------------------------------------------------------------------------------- 1 | categories: 2 | Maps2: 3 | label: 'Maps2' 4 | Maps2.templates: 5 | label: 'Templates' 6 | parent: 'Maps2' 7 | Maps2.templates.infoWindowContent: 8 | label: 'Info Window Content' 9 | parent: 'Maps2.templates' 10 | Maps2.pages: 11 | label: 'Pages' 12 | parent: 'Maps2' 13 | 14 | settings: 15 | maps2.templateRootPath: 16 | label: 'Templates' 17 | category: 'Maps2.templates' 18 | description: 'Path to template root' 19 | type: string 20 | default: 'EXT:maps2/Resources/Private/Templates/' 21 | maps2.partialRootPath: 22 | label: 'Partials' 23 | category: 'Maps2.templates' 24 | description: 'Path to partial root' 25 | type: string 26 | default: 'EXT:maps2/Resources/Private/Partials/' 27 | maps2.layoutRootPath: 28 | label: 'Layouts' 29 | category: 'Maps2.templates' 30 | description: 'Path to layout root' 31 | type: string 32 | default: 'EXT:maps2/Resources/Private/Layouts/' 33 | maps2.infoWindowContent.templatePath: 34 | label: 'Template path for info window content' 35 | category: 'Maps2.templates.infoWindowContent' 36 | description: 'If you click on a marker (POI) a little info window will appear. With this setting you can change the template to your own needs.' 37 | type: string 38 | default: 'EXT:maps2/Resources/Private/Templates/InfoWindowContent.html' 39 | maps2.infoWindowContent.imageHeight: 40 | label: 'Image Height' 41 | category: 'Maps2.templates.infoWindowContent' 42 | description: 'Define the image height for images in info window content of a POI. Values like 150c or 120m are also allowed.' 43 | type: string 44 | default: '150c' 45 | maps2.infoWindowContent.imageWidth: 46 | label: 'Image Width' 47 | category: 'Maps2.templates.infoWindowContent' 48 | description: 'Define the image width for images in info window content of a POI. Values like 150c or 120m are also allowed.' 49 | type: string 50 | default: '150c' 51 | 52 | maps2.storagePid: 53 | label: 'Default storage PID' 54 | category: 'Maps2.pages' 55 | description: 'Folder that stores all POIs' 56 | type: int 57 | default: 0 58 | -------------------------------------------------------------------------------- /Configuration/Sets/Maps2/setup.typoscript: -------------------------------------------------------------------------------- 1 | plugin.tx_maps2 { 2 | view { 3 | templateRootPaths { 4 | 0 = {$maps2.templateRootPath} 5 | 10 = 6 | } 7 | 8 | partialRootPaths { 9 | 0 = {$maps2.partialRootPath} 10 | 10 = 11 | } 12 | 13 | layoutRootPaths { 14 | 0 = {$maps2.layoutRootPath} 15 | 10 = 16 | } 17 | } 18 | 19 | persistence { 20 | storagePid = {$maps2.storagePid} 21 | classes { 22 | JWeiland\Maps2\Domain\Model\PoiCollection { 23 | mapping.columns { 24 | distance.config { 25 | type = passthrough 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | settings { 33 | zoom = 10 34 | zoomControl = 1 35 | overlay { 36 | link { 37 | addSection = 1 38 | } 39 | } 40 | 41 | infoWindowContent { 42 | view { 43 | dataProcessing { 44 | 10 = files 45 | 10 { 46 | as = infoWindowImages 47 | references { 48 | fieldName = info_window_images 49 | table = tx_maps2_domain_model_poicollection 50 | } 51 | } 52 | } 53 | } 54 | 55 | image { 56 | width = {$maps2.infoWindowContent.imageWidth} 57 | height = {$maps2.infoWindowContent.imageHeight} 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Configuration/Sets/OpenStreetMap/config.yaml: -------------------------------------------------------------------------------- 1 | name: jweiland/maps2-openstreetmap 2 | label: Maps2 - OpenStreetMap 3 | 4 | dependencies: 5 | - jweiland/maps2-default 6 | -------------------------------------------------------------------------------- /Configuration/Sets/OpenStreetMap/settings.definitions.yaml: -------------------------------------------------------------------------------- 1 | categories: 2 | Maps2.openstreetmap: 3 | label: 'OpenStreetMap' 4 | parent: Maps2 5 | 6 | settings: 7 | maps2.mapTile: 8 | label: 'Map Tile URL' 9 | category: Maps2.openstreetmap 10 | description: 'Define map tile: Please visit https://wiki.openstreetmap.org/wiki/Tile_servers to see all available map tiles. Be careful: If you switch a tile you may have to update the tile attribution, too' 11 | type: string 12 | default: 'https://{s}.tile.openstreetmap.org/${z}/${x}/${y}.png' 13 | maps2.mapTileAttribution: 14 | label: 'Map Tile Attribution' 15 | category: Maps2.openstreetmap 16 | description: 'Map tile attribution: OpenStreetMap license requires a correct map tile attribution. If you update map tile you may need to update this value, too' 17 | type: string 18 | default: '© OpenStreetMap contributors' 19 | -------------------------------------------------------------------------------- /Configuration/Sets/OpenStreetMap/setup.typoscript: -------------------------------------------------------------------------------- 1 | # Prevent including both static maps of map providers on one page 2 | page.includeJSFooterlibs.markerClustererForMaps2 > 3 | 4 | [isRequestToMapProviderAllowed()] 5 | [ELSE] 6 | # Requests to OpenStreetMap are not allowed. Inform the user about cookies and request permissions for 3rd party. 7 | tt_content.maps2_maps2.20.pluginName = Overlay 8 | tt_content.maps2_searchwithinradius.20.pluginName = Overlay 9 | tt_content.maps2_citymap.20.pluginName = Overlay 10 | [END] 11 | 12 | plugin.tx_maps2 { 13 | settings { 14 | mapProvider = osm 15 | mapTile = {$maps2.mapTile} 16 | mapTileAttribution = {$maps2.mapTileAttribution} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Configuration/TCA/Overrides/sys_category.php: -------------------------------------------------------------------------------- 1 | getMapProvider(); 23 | 24 | $newSysCategoryColumn = [ 25 | 'maps2_marker_icons' => [ 26 | 'exclude' => 1, 27 | 'label' => $ll . 'sys_category.maps2_marker_icons.' . $mapProvider, 28 | 'description' => $ll . 'sys_category.maps2_marker_icons.' . $mapProvider . '.description', 29 | 'config' => [ 30 | 'type' => 'file', 31 | 'minitems' => 0, 32 | 'maxitems' => 1, 33 | 'allowed' => 'common-image-types', 34 | ], 35 | ], 36 | 'maps2_marker_icon_width' => [ 37 | 'exclude' => true, 38 | 'label' => $ll . 'sys_category.maps2_marker_icon_width.' . $mapProvider, 39 | 'description' => $ll . 'sys_category.maps2_marker_icon_width.' . $mapProvider . '.description', 40 | 'config' => [ 41 | 'type' => 'number', 42 | 'format' => 'integer', 43 | ], 44 | ], 45 | 'maps2_marker_icon_height' => [ 46 | 'exclude' => true, 47 | 'label' => $ll . 'sys_category.maps2_marker_icon_height.' . $mapProvider, 48 | 'description' => $ll . 'sys_category.maps2_marker_icon_height.' . $mapProvider . '.description', 49 | 'config' => [ 50 | 'type' => 'number', 51 | 'format' => 'integer', 52 | ], 53 | ], 54 | 'maps2_marker_icon_anchor_pos_x' => [ 55 | 'exclude' => true, 56 | 'label' => $ll . 'sys_category.maps2_marker_icon_anchor_pos_x.' . $mapProvider, 57 | 'description' => $ll . 'sys_category.maps2_marker_icon_anchor_pos_x.' . $mapProvider . '.description', 58 | 'config' => [ 59 | 'type' => 'number', 60 | 'format' => 'integer', 61 | ], 62 | ], 63 | 'maps2_marker_icon_anchor_pos_y' => [ 64 | 'exclude' => true, 65 | 'label' => $ll . 'sys_category.maps2_marker_icon_anchor_pos_y.' . $mapProvider, 66 | 'description' => $ll . 'sys_category.maps2_marker_icon_anchor_pos_y.' . $mapProvider . '.description', 67 | 'config' => [ 68 | 'type' => 'number', 69 | 'format' => 'integer', 70 | ], 71 | ], 72 | ]; 73 | 74 | ExtensionManagementUtility::addTCAcolumns('sys_category', $newSysCategoryColumn); 75 | ExtensionManagementUtility::addToAllTCAtypes( 76 | 'sys_category', 77 | '--div--;LLL:EXT:maps2/Resources/Private/Language/locallang_db.xlf:tab.maps2.' . $mapHelper->getMapProvider() . ', maps2_marker_icons, maps2_marker_icon_width, maps2_marker_icon_height, maps2_marker_icon_anchor_pos_x, maps2_marker_icon_anchor_pos_y', 78 | ); 79 | }); 80 | -------------------------------------------------------------------------------- /Configuration/TCA/Overrides/sys_template.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Configuration/TCA/Overrides/sys_template.php -------------------------------------------------------------------------------- /Configuration/TCA/Overrides/tt_content.php: -------------------------------------------------------------------------------- 1 | getMapProvider(); 26 | 27 | // Set default for poi collection type 28 | $GLOBALS['TCA']['tx_maps2_domain_model_poicollection']['columns']['collection_type']['config']['default'] 29 | = $extConf->getDefaultMapType(); 30 | 31 | // Set latitude/longitude to float representation of extension configuration 32 | $GLOBALS['TCA']['tx_maps2_domain_model_poicollection']['columns']['latitude']['config']['default'] = number_format( 33 | $extConf->getDefaultLatitude(), 34 | 6, 35 | ); 36 | $GLOBALS['TCA']['tx_maps2_domain_model_poicollection']['columns']['longitude']['config']['default'] = number_format( 37 | $extConf->getDefaultLongitude(), 38 | 6, 39 | ); 40 | 41 | // If both map providers are allowed in ExtensionManager we have to add a selectbox for map provider to TCA 42 | if ($extConf->getMapProvider() === 'both') { 43 | ExtensionManagementUtility::addToAllTCAtypes( 44 | 'tx_maps2_domain_model_poicollection', 45 | 'map_provider', 46 | '', 47 | 'before:configuration_map', 48 | ); 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _admin-manual: 5 | 6 | ==================== 7 | Administrator manual 8 | ==================== 9 | 10 | .. only:: html 11 | 12 | This chapter describes how to manage the extension from a superuser point of view. 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | :titlesonly: 17 | 18 | GoogleApiKeys/Index 19 | Routing/Index 20 | Upgrade/Index 21 | Templates/Index 22 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Routing/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _routing: 5 | 6 | ======= 7 | Routing 8 | ======= 9 | 10 | `EXT:maps2` does not have a list and detail view, so there is no need to 11 | configure any route enhancers. But, it is possible to link to a POI 12 | from foreign extensions. That is possible by defining the PoiCollection 13 | UID as GET parameter `tx_maps2_maps2[poiCollectionUid]` in URI. 14 | 15 | For this case you can use following configuration. 16 | 17 | .. hint:: 18 | 19 | As PoiCollection records do NOT have any slug column defined, we really 20 | prefer to use just the UID of the record. Please prevent the usage of 21 | any title column as that may lead to unexpected escaping problems in URI. 22 | If you really want to use a title please create a slug column on your own 23 | and reference that column in aspect yourself. 24 | 25 | Example Configuration 26 | ===================== 27 | 28 | .. code-block:: yaml 29 | 30 | routeEnhancers: 31 | Maps2Plugin: 32 | type: Extbase 33 | extension: Maps2 34 | plugin: Maps2 35 | routes: 36 | - 37 | routePath: '/poi/{poiCollectionUid}' 38 | _controller: 'PoiCollection::show' 39 | defaultController: 'PoiCollection::show' 40 | aspects: 41 | poiCollectionUid: 42 | type: PersistedAliasMapper 43 | tableName: 'tx_maps2_domain_model_poicollection' 44 | routeFieldName: 'uid' 45 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ========= 5 | Templates 6 | ========= 7 | 8 | .. only:: html 9 | 10 | This chapter is all about templating EXT:maps2 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | :titlesonly: 15 | 16 | Start/Index 17 | ViewHelpers/Index 18 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/Start/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ============================ 5 | Changing & editing templates 6 | ============================ 7 | 8 | EXT:maps2 is using fluid as template engine. If you are know how to manage fluid 9 | templates, you can skip this section. 10 | 11 | 12 | Changing paths of the template 13 | ============================== 14 | 15 | You should never edit the original templates of an extension as those changes 16 | will vanish if you upgrade the extension. As any extbase based extension, you 17 | can find the templates in the directory ``Resources/Private/``. 18 | 19 | If you want to change a template, copy the desired files to the directory where 20 | you store the templates. This should be a directory in your SitePackage 21 | extension. Multiple fallbacks can be defined which makes it far easier to 22 | customize the templates. 23 | 24 | .. code-block:: typoscript 25 | 26 | plugin.tx_maps2 { 27 | view { 28 | templateRootPaths > 29 | templateRootPaths { 30 | 0 = EXT:maps2/Resources/Private/Templates/ 31 | 1 = EXT:site_package/Resources/Private/Extensions/Maps2/Templates/ 32 | } 33 | partialRootPaths > 34 | partialRootPaths { 35 | 0 = EXT:maps2/Resources/Private/Partials/ 36 | 1 = EXT:site_package/Resources/Private/Extensions/Maps2/Partials/ 37 | } 38 | layoutRootPaths > 39 | layoutRootPaths { 40 | 0 = EXT:maps2/Resources/Private/Layouts/ 41 | 1 = EXT:site_package/Resources/Private/Extensions/Maps2/Templates/Layouts/ 42 | } 43 | } 44 | } 45 | 46 | Change the templates using TypoScript constants 47 | ----------------------------------------------- 48 | 49 | You can use the following TypoScript in the **constants** to change 50 | the paths 51 | 52 | .. code-block:: typoscript 53 | 54 | plugin.tx_maps2 { 55 | view { 56 | templateRootPath = EXT:site_package/Resources/Private/Extensions/Maps2/Templates/ 57 | partialRootPath = EXT:site_package/Resources/Private/Extensions/Maps2/Partials/ 58 | layoutRootPath = EXT:site_package/Resources/Private/Extensions/Maps2/Layouts/ 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/Cache/GetCacheViewHelper.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ========================== 5 | Cache / GetCacheViewHelper 6 | ========================== 7 | 8 | This is a ViewHelper to retrieve a cache entry. 9 | 10 | General properties 11 | ================== 12 | 13 | .. confval-menu:: 14 | :name: confval-get-cache 15 | :display: table 16 | :required: 17 | :type: 18 | 19 | .. confval:: prefix 20 | :name: get-cache-prefix 21 | :required: false 22 | :type: string 23 | 24 | If you want you can define a prefix for the generated CacheIdentifier. Leave 25 | this value empty to use "infoWindow" as default value 26 | 27 | .. confval:: poiCollection 28 | :name: get-cache-poiCollection 29 | :required: true 30 | :type: PoiCollection 31 | 32 | You must assign the PoiCollection object to this ViewHelper. We extract some 33 | data from PoiCollection to build a more unique CacheIdentifier which can differ 34 | Caches in multilingual environment. 35 | 36 | Examples 37 | ======== 38 | 39 | Basic example 40 | ------------- 41 | 42 | .. code-block:: html 43 | 44 | {maps2:cache.getCache(poiCollection: poiCollection)} 45 | 46 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/Cache/HasCacheViewHelper.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ========================== 5 | Cache / HasCacheViewHelper 6 | ========================== 7 | 8 | This is a ViewHelper to check, if a cache entry exists. 9 | 10 | General properties 11 | ================== 12 | 13 | .. confval-menu:: 14 | :name: confval-has-cache 15 | :display: table 16 | :required: 17 | :type: 18 | 19 | .. confval:: prefix 20 | :name: has-cache-prefix 21 | :required: false 22 | :type: string 23 | 24 | If you want you can define a prefix for the generated CacheIdentifier. Leave 25 | this value empty to use "infoWindow" as default value 26 | 27 | .. confval:: poiCollection 28 | :name: has-cache-poiCollection 29 | :required: true 30 | :type: PoiCollection 31 | 32 | You must assign the PoiCollection object to this ViewHelper. We extract some 33 | data from PoiCollection to build a more unique CacheIdentifier which can differ 34 | Caches in multilingual environment. 35 | 36 | Examples 37 | ======== 38 | 39 | Basic example 40 | ------------- 41 | 42 | .. code-block:: html 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/Cache/SetCacheViewHelper.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ========================== 5 | Cache / SetCacheViewHelper 6 | ========================== 7 | 8 | This is a ViewHelper to set a new cache entry. 9 | 10 | General properties 11 | ================== 12 | 13 | .. confval-menu:: 14 | :name: confval-set-cache 15 | :display: table 16 | :required: 17 | :type: 18 | 19 | .. confval:: prefix 20 | :name: set-cache-prefix 21 | :required: false 22 | :type: string 23 | 24 | If you want you can define a prefix for the generated CacheIdentifier. Leave 25 | this value empty to use "infoWindow" as default value 26 | 27 | .. confval:: poiCollection 28 | :name: set-cache-poiCollection 29 | :required: true 30 | :type: PoiCollection 31 | 32 | You must assign the PoiCollection object to this ViewHelper. We extract some 33 | data from PoiCollection to build a more unique CacheIdentifier which can differ 34 | Caches in multilingual environment. 35 | 36 | .. confval:: data 37 | :name: set-cache-data 38 | :required: true 39 | :type: string 40 | 41 | The data as string which has to be stored. 42 | 43 | .. confval:: tags 44 | :name: set-cache-tags 45 | :required: false 46 | :type: array 47 | 48 | You can define some additional CacheEntryTags if you want. By default we add 49 | two additional Cache Tags named `infoWindowUid{PoiCollectionUid}` and 50 | `infoWindowPid{PoiCollectionPid}` 51 | 52 | .. confval:: lifetime 53 | :name: set-cache-lifetime 54 | :required: false 55 | :type: int 56 | 57 | How long (in seconds) the CacheEntry should be available, before it will be 58 | re-generated? Keep this value empty to use the Default Value of Storage-Backend. 59 | 0 for unlimited. 60 | 61 | 62 | Examples 63 | ======== 64 | 65 | Basic example 66 | ------------- 67 | 68 | .. code-block:: html 69 | 70 | {maps2:cache.setCache(poiCollection: poiCollection, data: '{content->f:format.raw()}')} 71 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/ConvertToJsonViewHelper.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ======================= 5 | ConvertToJsonViewHelper 6 | ======================= 7 | 8 | This is a ViewHelper to convert an array into JSON format. 9 | 10 | Examples 11 | ======== 12 | 13 | Basic example 14 | ------------- 15 | 16 | .. code-block:: html 17 | 18 |
19 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ======================== 5 | ViewHelpers of EXT:maps2 6 | ======================== 7 | 8 | ViewHelpers are used to add logic inside the view. 9 | There're basic things like if/else conditions, loops and so on. The system 10 | extension fluid has the most important ViewHelpers already included. 11 | 12 | To be able to use a ViewHelper in your template, you need to follow always the 13 | same structure which is: 14 | 15 | .. code-block:: html 16 | 17 | bar 18 | 19 | This would call the ViewHelper foo of the namespace **f** which stands for 20 | fluid. If you want to use ViewHelpers from other extensions you need to add the 21 | namespace declaration at the beginning of the template. Add or update following 22 | lines in your template, partial or layout: 23 | 24 | .. code-block:: html 25 | 26 | 30 | 31 | Now you can use a ViewHelper of maps2 with a code like: 32 | 33 | .. code-block:: html 34 | 35 | 36 | 37 | If you want to know what a ViewHelper does, it is very easy to find the related 38 | PHP class by looking at the namespace and the name of the ViewHelper. Having 39 | e.g. ``JWeiland\Maps2\ViewHelpers`` and ``convertToJson`` you will find the 40 | class at ``maps2\Classes\ViewHelpers\ConvertToJsonViewHelper.php``. 41 | 42 | The most awesome thing is that you can use ViewHelpers of any extension in any 43 | other template by just adding another namespace declaration like: 44 | 45 | .. code-block:: html 46 | 47 | 52 | 53 | and call the ViewHelper like 54 | 55 | .. code-block:: html 56 | 57 | 58 | 59 | All ViewHelpers 60 | =============== 61 | 62 | .. toctree:: 63 | :maxdepth: 2 64 | :titlesonly: 65 | :glob: 66 | 67 | ConvertToJsonViewHelper 68 | IsRequestToMapProviderAllowedViewHelper 69 | RequestUriForOverlayViewHelper 70 | TrimExplodeViewHelper 71 | 72 | Cache/GetCacheViewHelper 73 | Cache/HasCacheViewHelper 74 | Cache/SetCacheViewHelper 75 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/IsRequestToMapProviderAllowedViewHelper.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ======================================= 5 | IsRequestToMapProviderAllowedViewHelper 6 | ======================================= 7 | 8 | Use this ViewHelper to check user consent, if requests to map providers like 9 | Google Maps or OpenStreetMap are allowed or not. 10 | 11 | 12 | Examples 13 | ======== 14 | 15 | Basic example 16 | ------------- 17 | 18 | .. code-block:: html 19 | 20 | 21 | 22 | ...do something to show the map or what ever you want... 23 | 24 | 25 | ...show overlay or add a message what user should do to see the map... 26 | 27 | 28 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/RequestUriForOverlayViewHelper.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ============================== 5 | RequestUriForOverlayViewHelper 6 | ============================== 7 | 8 | This ViewHelper creates an URI with a special parameter which allows the map to 9 | be visible for the user. 10 | 11 | 12 | Examples 13 | ======== 14 | 15 | Basic example 16 | ------------- 17 | 18 | .. code-block:: html 19 | 20 | 21 | Link to current page. Map will be shown somewhere on that page. 22 | 23 | 24 | Scroll to content element 25 | ------------------------- 26 | 27 | If you add `ttContentUid` to ViewHelper it will add a link section (#174) 28 | to the end of the URI. If all of your content elements contain an `id` attribute 29 | like `c174` the target page will scroll to this specific content element 30 | directly. 31 | 32 | .. code-block:: html 33 | 34 | 35 | Link to current page and scroll to content element with map. 36 | 37 | -------------------------------------------------------------------------------- /Documentation/AdministratorManual/Templates/ViewHelpers/TrimExplodeViewHelper.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | ===================== 5 | TrimExplodeViewHelper 6 | ===================== 7 | 8 | This is a ViewHelper to convert a comma separated value into an array. 9 | All values will be trimmed. 10 | 11 | General properties 12 | ================== 13 | 14 | .. t3-field-list-table:: 15 | :header-rows: 1 16 | 17 | - :Name: Name: 18 | :Type: Type: 19 | :Description: Description: 20 | :Default value: Default value: 21 | 22 | - :Name: 23 | \* delimiter 24 | :Type: 25 | string 26 | :Description: 27 | Delimiter 28 | :Default value: 29 | , 30 | 31 | Examples 32 | ======== 33 | 34 | Basic example 35 | ------------- 36 | 37 | .. code-block:: html 38 | 39 | 40 | ..do something with {address} 41 | 42 | -------------------------------------------------------------------------------- /Documentation/Configuration/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _configuration: 5 | 6 | ============= 7 | Configuration 8 | ============= 9 | 10 | Minimal Example 11 | =============== 12 | 13 | .. hint:: 14 | 15 | If you want to work with Google Maps in TYPO3 backend you or an 16 | administrator have to configure the Google Maps API keys in 17 | :ref:`Configure extension ` to get a working environment. 18 | 19 | * Include site set `Maps2 - Default Set` in "Sets for this Site" in your site. 20 | * include one of these site sets `Maps2 - Google Maps` or 21 | `Maps2 - Open Street Map` in "Sets for this Site" in your site. 22 | 23 | Update at least `Default storage PID` and `JavaScript API Key` settings of 24 | maps2 in Site Settings. 25 | 26 | .. toctree:: 27 | :maxdepth: 2 28 | 29 | Extension/Index 30 | Plugins/Index 31 | TypoScript/Index 32 | -------------------------------------------------------------------------------- /Documentation/DeveloperManual/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _developer-manual: 5 | 6 | ================ 7 | Developer manual 8 | ================ 9 | 10 | This chapter describes how to manage the extension from a developer point 11 | of view. 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | :titlesonly: 16 | 17 | Api/Index 18 | Maps2Registry/Index 19 | Template/Index 20 | -------------------------------------------------------------------------------- /Documentation/DeveloperManual/Template/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _developer-template: 5 | 6 | ======== 7 | Template 8 | ======== 9 | 10 | With EXT:maps2 version 10.0.0 we have remove PoiCollection- and 11 | EditPoiCollection ViewHelper. This part will explain how to change your 12 | template to use the new implementation. 13 | 14 | PoiCollection 15 | ============= 16 | 17 | Add static TS template `Maps2 Default (maps2)` and one of 18 | the `Maps2 for Google Maps (maps2)` or `Maps2 for Open Street Map (maps2)` 19 | templates to the page where your extension/plugin belongs to, as far as not 20 | already done in root page. 21 | 22 | In case of `Maps2 for Google Maps (maps2)`please check, if following 23 | TS constant is set: 24 | 25 | .. code-block:: typoscript 26 | 27 | plugin.tx_maps2.view.googleMapsJavaScriptApiKey 28 | 29 | Add a further entry for `maps2` to `partialRootPaths` configuration of your 30 | extension, so that fluid can find our new partials: 31 | 32 | .. code-block:: typoscript 33 | 34 | plugin.tx_myext.view.partialRootPaths { 35 | 0 = EXT:my_ext/Resources/Private/Partials/ 36 | 1 = EXT:maps2/Resources/Private/Partials/ 37 | } 38 | 39 | Replace old `maps2:widget.poiCollection` ViewHelper in templates of your 40 | extension: 41 | 42 | .. code-block:: html 43 | 44 | 45 | 46 | with following HTML: 47 | 48 | .. code-block:: html 49 | 50 | 53 | 54 | 55 | EditPoiCollection 56 | ================= 57 | 58 | Add static TS template `Maps2 Default (maps2)` and one of the 59 | `Maps2 for Google Maps (maps2)` or `Maps2 for Open Street Map (maps2)` templates 60 | to the page where your extension/plugin belongs to, as far as not already done 61 | in root page. 62 | 63 | In case of `Maps2 for Google Maps (maps2)`please check, if following 64 | TS constant is set: 65 | 66 | .. code-block:: typoscript 67 | 68 | plugin.tx_maps2.view.googleMapsJavaScriptApiKey 69 | 70 | Add a further entry for `maps2` to `partialRootPaths` configuration of your 71 | extension, so that fluid can find our new partials: 72 | 73 | .. code-block:: typoscript 74 | 75 | plugin.tx_myext.view.partialRootPaths { 76 | 0 = EXT:my_ext/Resources/Private/Partials/ 77 | 1 = EXT:maps2/Resources/Private/Partials/ 78 | } 79 | 80 | Replace old `maps2:widget.editPoiCollection` ViewHelper in templates of your 81 | extension: 82 | 83 | .. code-block:: html 84 | 85 | 89 | 90 | with following html: 91 | 92 | .. code-block:: html 93 | 94 | 97 | -------------------------------------------------------------------------------- /Documentation/Images/AdministratorManual/maps2-include-TypoScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/AdministratorManual/maps2-include-TypoScript.png -------------------------------------------------------------------------------- /Documentation/Images/GoogleApiKeys/WizardActivatedApis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/GoogleApiKeys/WizardActivatedApis.png -------------------------------------------------------------------------------- /Documentation/Images/GoogleApiKeys/WizardPickProduct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/GoogleApiKeys/WizardPickProduct.png -------------------------------------------------------------------------------- /Documentation/Images/GoogleApiKeys/WizardSelectProject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/GoogleApiKeys/WizardSelectProject.png -------------------------------------------------------------------------------- /Documentation/Images/Introduction/maps2-type-Area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/Introduction/maps2-type-Area.png -------------------------------------------------------------------------------- /Documentation/Images/Introduction/maps2-type-Point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/Introduction/maps2-type-Point.png -------------------------------------------------------------------------------- /Documentation/Images/Introduction/maps2-type-Radius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/Introduction/maps2-type-Radius.png -------------------------------------------------------------------------------- /Documentation/Images/Introduction/maps2-type-Route.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/Introduction/maps2-type-Route.png -------------------------------------------------------------------------------- /Documentation/Images/Typo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/Typo3.png -------------------------------------------------------------------------------- /Documentation/Images/UserManual/BackendView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Documentation/Images/UserManual/BackendView.png -------------------------------------------------------------------------------- /Documentation/Includes.rst.txt: -------------------------------------------------------------------------------- 1 | .. More information about this file: 2 | https://docs.typo3.org/m/typo3/docs-how-to-document/main/en-us/GeneralConventions/FileStructure.html#includes-rst-txt 3 | 4 | .. ---------- 5 | .. text roles 6 | .. ---------- 7 | 8 | .. role:: aspect(emphasis) 9 | .. role:: bash(code) 10 | .. role:: html(code) 11 | .. role:: js(code) 12 | .. role:: php(code) 13 | .. role:: rst(code) 14 | .. role:: sep(strong) 15 | .. role:: sql(code) 16 | .. role:: ts(code) 17 | :class: typoscript 18 | 19 | .. role:: tsconfig(code) 20 | :class: typoscript 21 | 22 | .. role:: typoscript(code) 23 | .. role:: xml(code) 24 | :class: html 25 | 26 | .. role:: yaml(code) 27 | 28 | .. default-role:: code 29 | 30 | .. --------- 31 | .. highlight 32 | .. --------- 33 | 34 | .. By default, code blocks use PHP syntax highlighting 35 | 36 | .. highlight:: php 37 | -------------------------------------------------------------------------------- /Documentation/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | .. _start: 4 | 5 | ===== 6 | Maps2 7 | ===== 8 | 9 | :Language: 10 | en 11 | 12 | :Version: 13 | |release| 14 | 15 | :Description: 16 | This TYPO3 extension supports the rendering of a map based on Google Maps or 17 | OpenStreetMap. The map can be additionally enriched with markers, routes, 18 | area and radius overlays and these overlays can be grouped into categories 19 | for easy and recurring assignment. 20 | 21 | :Keywords: 22 | typo3,TYPO3 CMS,google maps,osm,open street map,openstreetmap,maps2 23 | 24 | :Copyright: 25 | 2013-2021 26 | 27 | :Author: 28 | Stefan Froemken 29 | 30 | :Email: 31 | projects@jweiland.net 32 | 33 | :License: 34 | This document is published under the Open Content License 35 | available from http://www.opencontent.org/opl.shtml 36 | 37 | :Rendered: 38 | |today| 39 | 40 | 41 | .. toctree:: 42 | :titlesonly: 43 | 44 | Introduction/Index 45 | Installation/Index 46 | Configuration/Index 47 | User/Index 48 | AdministratorManual/Index 49 | DeveloperManual/Index 50 | FAQ/Index 51 | ChangeLog/Index 52 | -------------------------------------------------------------------------------- /Documentation/Installation/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _installation: 5 | 6 | ============ 7 | Installation 8 | ============ 9 | 10 | Target group: **Administrators** 11 | 12 | .. contents:: 13 | :backlinks: top 14 | :class: compact-list 15 | :depth: 1 16 | :local: 17 | 18 | .. _installation_composer: 19 | 20 | Composer mode 21 | ============= 22 | 23 | If your TYPO3 installation uses Composer, install the latest release of this 24 | extension through: 25 | 26 | .. code-block:: bash 27 | 28 | composer require jweiland/maps2 29 | 30 | If you are not using the latest version, you need to 31 | add a version constraint, for example: 32 | 33 | .. code-block:: bash 34 | 35 | composer require jweiland/maps2:"^9.3" 36 | 37 | Installing the extension prior to TYPO3 11.4 38 | -------------------------------------------- 39 | 40 | Before TYPO3 11.4 it was still necessary to manually activate extensions 41 | installed via Composer using the Extension Manager. Activate it as follows: 42 | 43 | * Navigate to :guilabel:`Admin Tools > Extensions > Installed Extensions` 44 | * Search for `maps2` 45 | * Activate the extension by clicking on the :guilabel:`Activate` button in the 46 | :guilabel:`A/D` column 47 | 48 | 49 | .. _installation_legacy: 50 | 51 | Legacy mode 52 | =========== 53 | 54 | If you are working with a TYPO3 installation that does not use Composer, install 55 | the extension in the Extension Manager: 56 | 57 | * Navigate to :guilabel:`Admin Tools > Extensions > Get Extensions`. 58 | * Click on :guilabel:`Update now` 59 | * Search for `maps2` 60 | * Click :guilabel:`Import and install` on the side of the extension entry 61 | 62 | and activate it: 63 | 64 | * Navigate to :guilabel:`Admin Tools > Extensions > Installed Extensions` 65 | * Search for `maps2` 66 | * Activate the extension by clicking on the :guilabel:`Activate` button in the 67 | :guilabel:`A/D` column 68 | 69 | .. seealso:: 70 | 71 | On page `Installing extensions `_ 72 | both TYPO3 installation modes are explained in detail. 73 | 74 | **Next step** 75 | 76 | Please edit ExtensionManager configuration of maps2 to decide, if you will use 77 | Google Maps or OpenStreetMap as your default rendering service: 78 | :ref:`Configure extension `. 79 | -------------------------------------------------------------------------------- /Documentation/Introduction/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _introduction: 5 | 6 | ============ 7 | Introduction 8 | ============ 9 | 10 | 11 | .. _what-it-does: 12 | 13 | What does it do? 14 | ================ 15 | 16 | maps2 is an extension for TYPO3 CMS. It can render you a map based on Google Maps and/or OpenStreetMap. If you 17 | want, you can create Markers, Routes, Area and Radius overlays. Assign these overlays to categories to 18 | build a map, with all points based on selected category. 19 | 20 | 21 | .. _screenshots: 22 | 23 | Screenshots 24 | =========== 25 | 26 | See maps2 in action. 27 | 28 | Point 29 | ----- 30 | 31 | .. figure:: ../Images/Introduction/maps2-type-Point.png 32 | :width: 500px 33 | :alt: Type: Point 34 | 35 | Introduction Package just after installation (caption of the image) 36 | 37 | How the Frontend of the Introduction Package looks like just after installation (legend of the image) 38 | 39 | Radius 40 | ------ 41 | 42 | .. figure:: ../Images/Introduction/maps2-type-Radius.png 43 | :width: 500px 44 | :alt: Type: Radius 45 | 46 | Introduction Package just after installation (caption of the image) 47 | 48 | How the Frontend of the Introduction Package looks like just after installation (legend of the image) 49 | 50 | Area 51 | ---- 52 | 53 | .. figure:: ../Images/Introduction/maps2-type-Area.png 54 | :width: 500px 55 | :alt: Type: Area 56 | 57 | Introduction Package just after installation (caption of the image) 58 | 59 | How the Frontend of the Introduction Package looks like just after installation (legend of the image) 60 | 61 | Route 62 | ----- 63 | 64 | .. figure:: ../Images/Introduction/maps2-type-Route.png 65 | :width: 500px 66 | :alt: Type: Route 67 | 68 | Introduction Package just after installation (caption of the image) 69 | 70 | How the Frontend of the Introduction Package looks like just after installation (legend of the image) 71 | -------------------------------------------------------------------------------- /Documentation/User/HowToStart/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _howToStart: 5 | 6 | ============ 7 | How to start 8 | ============ 9 | 10 | This walkthrough will help you to implement the extension maps2 at your 11 | TYPO3 site. The installation is covered :ref:`here `. 12 | 13 | .. only:: html 14 | 15 | .. contents:: 16 | :local: 17 | :depth: 1 18 | 19 | .. _howToStartCreateRecords: 20 | 21 | Create the records 22 | ================== 23 | 24 | Before any maps2 record can be shown in the frontend those need to be 25 | created. 26 | 27 | #. Create a new sysfolder. 28 | (Of course you can also use an existing sysfolder). 29 | 30 | #. Switch to **List module** 31 | 32 | #. Use the icon in the topbar "Create new record" and search for "Maps2" and 33 | its record "Marking". 34 | 35 | #. Click on "Marking" to create a new maps2 record. 36 | 37 | #. Give it a title (required) 38 | 39 | #. Choose a type of record you want to create. This will reload the form to 40 | show further fields especially for this record type. Alternative you can 41 | click on one of these type images to switch the type. 42 | 43 | #. After reload you should see some more tabs now. Click on tab "Map" 44 | 45 | #. Field "Address" is required, but you can not fill it. Please use the search 46 | field at top of map to search for an address and press . If an 47 | address was found, we will automatically fill the required address field 48 | in a formatted representation of the searched address. 49 | 50 | .. _howToStartAddPlugin: 51 | 52 | Add a plugin to a page 53 | ====================== 54 | 55 | A plugin is used to render a defined selection of records in the frontend. 56 | Follow this steps to add a plugin to a page: 57 | 58 | Maps2: Show map - Plugin 59 | ------------------------ 60 | 61 | #. Create a new page with a title like "Location" which will be used to show 62 | a Marking record. 63 | 64 | #. Add a new content element, switch to Tab "Plugins" and select the 65 | entry "Maps2: Show map" 66 | 67 | #. Change the 1 :sup:`st` field to one of your created Marking records. 68 | 69 | #. Save the plugin. 70 | 71 | Here are some more possible configuration of the plugin: 72 | 73 | If you leave marking and category field empty we will show all POIs of 74 | configured StorageFolder 75 | 76 | If you leave marking field empty, but select some categories we will show all 77 | POIs of selected category. As long as they are available in configured 78 | StorageFolder. 79 | 80 | If marking and category field is set, marking field has precedence. 81 | 82 | If there is a PoiCollection UID in URI this POI has precedence over marking and 83 | category settings. 84 | 85 | Info: If there will be shown more than one POI on the map it is not possible to 86 | set zoom anymore. We are working with the BoundedBox feature of Google Maps 87 | and OpenStreetMap to zoom out until all POIs are visible. 88 | 89 | Maps2: Search Radius - Plugin 90 | ----------------------------- 91 | 92 | #. Create a new page with a title like "Radius Search" which will be used to 93 | show a form, where a website visitor can enter an address and a range to 94 | search for Markings. 95 | 96 | #. Add a new content element of type "General Plugin" 97 | 98 | #. Switch over to tab "Plugin" and select "Maps2: Search Radius" from selectbox 99 | "Selected Plugin" 100 | 101 | #. After reload go to Tab "Plugin" again and change the 1 :sup:`st` field to a 102 | location where you want to search. Something like "germany" or a city name. 103 | 104 | #. Save the plugin. 105 | 106 | Maps2: City Map - Plugin 107 | ------------------------ 108 | 109 | #. Create a new page with a title like "City Map" which will be used to show 110 | a form, where a website visitor can enter a street name. 111 | 112 | #. Add a new content element of type "General Plugin" 113 | 114 | #. Switch over to tab "Plugin" and select "Maps2: City Map" from selectbox 115 | "Selected Plugin" 116 | 117 | #. After reload go to Tab "Plugin" again and Change the 1 :sup:`st` field to 118 | location where you want to search. Type in a city name and the results will 119 | be reduced to that city. 120 | 121 | #. Save the plugin. 122 | -------------------------------------------------------------------------------- /Documentation/User/Index.rst: -------------------------------------------------------------------------------- 1 | .. include:: /Includes.rst.txt 2 | 3 | 4 | .. _userManual: 5 | 6 | =========== 7 | User manual 8 | =========== 9 | 10 | .. only:: html 11 | 12 | This chapter describes how to use the extension from a user point of view. 13 | 14 | The section "*Maps2Record*" lists all the fields of the record and 15 | "*HowToStart*" describes all available plugins. 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | :titlesonly: 20 | 21 | HowToStart/Index 22 | Maps2Record/Index 23 | -------------------------------------------------------------------------------- /Documentation/guides.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TYPO3 Extension `maps2` 2 | 3 | [![Packagist][packagist-logo-stable]][extension-packagist-url] 4 | [![Latest Stable Version][extension-build-shield]][extension-ter-url] 5 | [![Total Downloads][extension-downloads-badge]][extension-packagist-url] 6 | [![Monthly Downloads][extension-monthly-downloads]][extension-packagist-url] 7 | [![TYPO3 13.4][TYPO3-shield]][TYPO3-13-url] 8 | 9 | ![Build Status][extension-ci-shield] 10 | 11 | This TYPO3 extension supports the rendering of a map based on Google Maps or 12 | OpenStreetMap. The map can be additionally enriched with markers, routes, 13 | area and radius overlays and these overlays can be grouped into categories 14 | for easy and recurring assignment. 15 | 16 | | Type | URL | 17 | |--------------|-----------------------------------------------------| 18 | | Repository: | https://github.com/jweiland-net/maps2 | 19 | | Read online: | https://docs.typo3.org/p/jweiland/maps2/main/en-us/ | 20 | | TER: | https://extensions.typo3.org/extension/maps2 | 21 | 22 | [extension-build-shield]: https://poser.pugx.org/jweiland/maps2/v/stable.svg?style=for-the-badge 23 | 24 | [extension-ci-shield]: https://github.com/jweiland-net/maps2/actions/workflows/ci.yml/badge.svg 25 | 26 | [extension-downloads-badge]: https://poser.pugx.org/jweiland/maps2/d/total.svg?style=for-the-badge 27 | 28 | [extension-monthly-downloads]: https://poser.pugx.org/jweiland/maps2/d/monthly?style=for-the-badge 29 | 30 | [extension-ter-url]: https://extensions.typo3.org/extension/maps2/ 31 | 32 | [extension-packagist-url]: https://packagist.org/packages/jweiland/maps2/ 33 | 34 | [packagist-logo-stable]: https://img.shields.io/badge/--grey.svg?style=for-the-badge&logo=packagist&logoColor=white 35 | 36 | [TYPO3-13-url]: https://get.typo3.org/version/13 37 | 38 | [TYPO3-shield]: https://img.shields.io/badge/TYPO3-13.4-green.svg?style=for-the-badge&logo=typo3 39 | -------------------------------------------------------------------------------- /Resources/Private/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all -------------------------------------------------------------------------------- /Resources/Private/Language/FlexForms.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | General 8 | 9 | 10 | Map Provider 11 | 12 | 13 | Which marking should be shown? If there is a marking defined in website uri, that one has priority. 14 | 15 | 16 | Show all markings of given categories. This will only work, if there is no marking in website uri nor if a marking is selected above. 17 | 18 | 19 | Append a fixed string to search value. Maybe a cityname. That way the user has only to insert a streetname. 20 | 21 | 22 | Map width 23 | 24 | 25 | Map height 26 | 27 | 28 | 29 | Map Options 30 | 31 | 32 | Default zoom 33 | 34 | 35 | Set a fix Zoomlevel if more than one POI will be displayed. Default: automatic zoomlevel to display all POIs. 36 | 37 | 38 | Show Zoom Control 39 | 40 | 41 | Show full screen Control 42 | 43 | 44 | 45 | Google Maps 46 | 47 | 48 | Default map view 49 | 50 | 51 | Hybrid 52 | 53 | 54 | Road Map 55 | 56 | 57 | Satellite 58 | 59 | 60 | Terrain 61 | 62 | 63 | Show Map Type Control 64 | 65 | 66 | Show Scale Control 67 | 68 | 69 | Show StreetView Control 70 | 71 | 72 | Activate zoom with mouse scroll wheel 73 | 74 | 75 | Map Style. Have a look at https://snazzymaps.com to copy some cool styles for you map 76 | 77 | 78 | 79 | Open Street Map 80 | 81 | 82 | Map Tile URI: Define another external provider to show map with another layout 83 | 84 | 85 | Map Tile Attribution: Each map needs to show the author attribution. Please check which Attribution has to be used for defined map tile above 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Resources/Private/Language/locallang.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | Google Maps 8 | 9 | 10 | The protection of your data is important for us. 11 | 12 | 13 | Click on "Activate" to allow us requesting google servers to show Google Maps. 14 | 15 | 16 | Activate 17 | 18 | 19 | Open Street Map 20 | 21 | 22 | The protection of your data is important for us. 23 | 24 | 25 | Click on "Activate" to allow us requesting Open Street Map servers to show map. 26 | 27 | 28 | Activate 29 | 30 | 31 | Insert address to search for 32 | 33 | 34 | 35 | latitude 36 | 37 | 38 | longitude 39 | 40 | 41 | Marking 42 | 43 | 44 | Title 45 | 46 | 47 | 48 | Address 49 | 50 | 51 | Radius 52 | 53 | 54 | Search 55 | 56 | 57 | 58 | Search for street 59 | 60 | 61 | 62 | No positions found 63 | 64 | 65 | %1$s can't find any position. Please check your input and try again 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Resources/Private/Layouts/Default.html: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /Resources/Private/Partials/InfoWindowContent.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 |
8 | 9 | 10 | 16 | 17 | 18 |
19 |
20 | 21 |
{poiCollection.title}
22 | 23 |
24 | 25 | 26 | 27 |
{address}
28 |
29 |
30 |
31 |
32 | 33 | 34 |
35 |
{poiCollection.info_window_content -> f:transform.html()}
36 |
37 | 38 | -------------------------------------------------------------------------------- /Resources/Private/Partials/LoadAssets.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ; 12 | 17 | 22 | 23 | 24 | 25 | 29 | 34 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Resources/Private/Partials/Maps2/EditPoiCollection.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | {environment.contentRecord.uid} 11 | 12 | 14 | 16 | 17 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /Resources/Private/Partials/Maps2/Overlay.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 |

{f:translate(key: 'LLL:EXT:maps2/Resources/Private/Language/locallang.xlf:{mapProvider}.map')}

8 |

9 | {f:translate(key: 'LLL:EXT:maps2/Resources/Private/Language/locallang.xlf:{mapProvider}.protectData')}
10 | {f:translate(key: 'LLL:EXT:maps2/Resources/Private/Language/locallang.xlf:{mapProvider}.explainActivation')} 11 |

12 |

13 | 14 | {f:translate(key: 'LLL:EXT:maps2/Resources/Private/Language/locallang.xlf:{mapProvider}.activate')} 15 | 16 |

17 |
18 | 19 | -------------------------------------------------------------------------------- /Resources/Private/Partials/Maps2/PoiCollection.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
21 |
22 | 23 | {environment.settings.mapProvider} 24 | {environment.contentRecord.uid} 25 | 26 | 27 |
28 |
29 |
30 | 31 | -------------------------------------------------------------------------------- /Resources/Private/Templates/CityMap/Search.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | 20 |
21 | 22 | 25 | 26 | 27 |
32 |
33 | -------------------------------------------------------------------------------- /Resources/Private/Templates/CityMap/Show.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | 16 |
17 | 18 | 19 |
21 |
22 | -------------------------------------------------------------------------------- /Resources/Private/Templates/InfoWindowContent.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | {m:cache.getCache(poiCollection: poiCollection)} 9 | 10 | 11 | 12 | 13 | 14 | 15 | {content -> f:format.raw()} 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Resources/Private/Templates/InfoWindowContentNoCache.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | {content -> f:format.raw()} 17 | 18 | -------------------------------------------------------------------------------- /Resources/Private/Templates/PluginPreview/Maps2.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
ConfigValue
Plugin{pluginName}
POI collection{poiCollectionRecord.title} ({poiCollectionRecord.uid})
Categories{pi_flexform_transformed.settings.categories}
Size{pi_flexform_transformed.settings.mapWidth} * {pi_flexform_transformed.settings.mapHeight}
Zoom{pi_flexform_transformed.settings.zoom}
Storages{pages}
50 | 51 | -------------------------------------------------------------------------------- /Resources/Private/Templates/PoiCollection/ListRadius.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
18 |
19 | 20 |
Sorry, there are no results within your given radius
21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /Resources/Private/Templates/PoiCollection/Overlay.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | {settings.mapProvider} 8 | {data.uid} 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Resources/Private/Templates/PoiCollection/Search.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 18 |
19 |
20 | 21 | 25 |
26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /Resources/Private/Templates/PoiCollection/Show.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
16 |
17 | 18 | -------------------------------------------------------------------------------- /Resources/Private/Templates/Tca/GoogleMaps.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 |
9 |
10 |
11 | Place ID
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /Resources/Private/Templates/Tca/OpenStreetMap.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 6 |
7 |
8 |
9 | 10 |
12 | -------------------------------------------------------------------------------- /Resources/Public/Css/GoogleMapsModule.css: -------------------------------------------------------------------------------- 1 | .controls { 2 | background-color: #fff; 3 | border-radius: 2px; 4 | border: 1px solid transparent; 5 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); 6 | box-sizing: border-box; 7 | font-family: Roboto, Verdana, sans-serif; 8 | font-size: 15px; 9 | font-weight: 300; 10 | height: 29px; 11 | margin-left: 17px; 12 | margin-top: 10px; 13 | outline: none; 14 | padding: 0 11px 0 13px; 15 | text-overflow: ellipsis; 16 | width: 400px; 17 | } 18 | 19 | .controls:focus { 20 | border-color: #4d90fe; 21 | } 22 | .title { 23 | font-weight: bold; 24 | } 25 | #infowindow-content { 26 | display: none; 27 | } 28 | #maps2ConfigurationMap #infowindow-content { 29 | display: inline; 30 | } 31 | -------------------------------------------------------------------------------- /Resources/Public/Css/Leaflet/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Css/Leaflet/images/layers-2x.png -------------------------------------------------------------------------------- /Resources/Public/Css/Leaflet/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Css/Leaflet/images/layers.png -------------------------------------------------------------------------------- /Resources/Public/Css/Leaflet/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Css/Leaflet/images/marker-icon-2x.png -------------------------------------------------------------------------------- /Resources/Public/Css/Leaflet/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Css/Leaflet/images/marker-icon.png -------------------------------------------------------------------------------- /Resources/Public/Css/Leaflet/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Css/Leaflet/images/marker-shadow.png -------------------------------------------------------------------------------- /Resources/Public/Icons/Extension.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Resources/Public/Icons/MarkerClusterer/m1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/MarkerClusterer/m1.png -------------------------------------------------------------------------------- /Resources/Public/Icons/MarkerClusterer/m2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/MarkerClusterer/m2.png -------------------------------------------------------------------------------- /Resources/Public/Icons/MarkerClusterer/m3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/MarkerClusterer/m3.png -------------------------------------------------------------------------------- /Resources/Public/Icons/MarkerClusterer/m4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/MarkerClusterer/m4.png -------------------------------------------------------------------------------- /Resources/Public/Icons/MarkerClusterer/m5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/MarkerClusterer/m5.png -------------------------------------------------------------------------------- /Resources/Public/Icons/RecordTypeArea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/RecordTypeArea.png -------------------------------------------------------------------------------- /Resources/Public/Icons/RecordTypePoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/RecordTypePoint.png -------------------------------------------------------------------------------- /Resources/Public/Icons/RecordTypeRadius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/RecordTypeRadius.png -------------------------------------------------------------------------------- /Resources/Public/Icons/RecordTypeRoute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/RecordTypeRoute.png -------------------------------------------------------------------------------- /Resources/Public/Icons/TypeSelectArea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/TypeSelectArea.png -------------------------------------------------------------------------------- /Resources/Public/Icons/TypeSelectPoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/TypeSelectPoint.png -------------------------------------------------------------------------------- /Resources/Public/Icons/TypeSelectRadius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/TypeSelectRadius.png -------------------------------------------------------------------------------- /Resources/Public/Icons/TypeSelectRoute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/TypeSelectRoute.png -------------------------------------------------------------------------------- /Resources/Public/Icons/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/marker.png -------------------------------------------------------------------------------- /Resources/Public/Icons/marker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Resources/Public/Icons/plugin_wizard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Resources/Public/Icons/relation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/relation.gif -------------------------------------------------------------------------------- /Resources/Public/Icons/tx_maps2_domain_model_poi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweiland-net/maps2/ba4cd77780f5e50c9070a26ad45f1e787868061e/Resources/Public/Icons/tx_maps2_domain_model_poi.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jweiland/maps2", 3 | "description": "Create maps with Marker, Area, Routes or Radius based on Google Maps or OpenStreetMap", 4 | "license": "GPL-2.0-or-later", 5 | "type": "typo3-cms-extension", 6 | "keywords": [ 7 | "typo3", 8 | "TYPO3 CMS", 9 | "google maps", 10 | "osm", 11 | "open street map", 12 | "openstreetmap", 13 | "maps2" 14 | ], 15 | "authors": [ 16 | { 17 | "name": "Stefan Froemken", 18 | "email": "sfroemken@jweiland.net", 19 | "role": "Lead Developer" 20 | } 21 | ], 22 | "homepage": "https://jweiland.net/", 23 | "support": { 24 | "email": "projects@jweiland.net", 25 | "issues": "https://github.com/jweiland-net/maps2/issues", 26 | "source": "https://github.com/jweiland-net/maps2", 27 | "docs": "https://docs.typo3.org/p/jweiland/maps2/main/en-us/" 28 | }, 29 | "require": { 30 | "ext-json": "*", 31 | "typo3/cms-core": "^13.4.0" 32 | }, 33 | "require-dev": { 34 | "ergebnis/composer-normalize": "^2.44", 35 | "sjbr/static-info-tables": "^13.4", 36 | "typo3/coding-standards": "^0.8", 37 | "typo3/testing-framework": "^9.0.1" 38 | }, 39 | "suggest": { 40 | "sjbr/static-info-tables": "Install this package, if you want to choose from contained countries instead of typing them" 41 | }, 42 | "autoload": { 43 | "psr-4": { 44 | "JWeiland\\Maps2\\": "Classes" 45 | } 46 | }, 47 | "autoload-dev": { 48 | "psr-4": { 49 | "JWeiland\\Maps2\\Tests\\": "Tests" 50 | } 51 | }, 52 | "config": { 53 | "allow-plugins": { 54 | "ergebnis/composer-normalize": true, 55 | "typo3/class-alias-loader": true, 56 | "typo3/cms-composer-installers": true 57 | }, 58 | "bin-dir": ".Build/bin", 59 | "vendor-dir": ".Build/vendor" 60 | }, 61 | "extra": { 62 | "typo3/cms": { 63 | "app-dir": ".Build", 64 | "extension-key": "maps2", 65 | "web-dir": ".Build/Web" 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ext_conf_template.txt: -------------------------------------------------------------------------------- 1 | # cat=basic; type=options[LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:mapProvider.both=both,Google=gm,Open Street Map=osm]; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:mapProvider 2 | mapProvider = both 3 | # cat=basic; type=options[Google=gm,OpenStreetMap=osm]; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:defaultMapProvider 4 | defaultMapProvider = gm 5 | # cat=basic; type=options[Empty=Empty,Point=Point,Radius=Radius,Area=Area,Route=Route]; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:defaultMapType 6 | defaultMapType = Empty 7 | # cat=basic; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:defaultCountry 8 | defaultCountry = 9 | # cat=basic; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:defaultLatitude 10 | defaultLatitude = 11 | # cat=basic; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:defaultLongitude 12 | defaultLongitude = 13 | # cat=basic; type=int+; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:defaultRadius 14 | defaultRadius = 250 15 | # cat=basic; type=boolean; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:explicitAllowMapProviderRequests 16 | explicitAllowMapProviderRequests = 0 17 | # cat=basic; type=boolean; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:explicitAllowMapProviderRequestsBySessionOnly 18 | explicitAllowMapProviderRequestsBySessionOnly = 0 19 | 20 | # cat=gm; type=wrap; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:googleMapsLibrary 21 | googleMapsLibrary = https://maps.googleapis.com/maps/api/js?key=|&libraries=places 22 | # cat=gm; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:googleMapsGeocodeUri 23 | googleMapsGeocodeUri = https://maps.googleapis.com/maps/api/geocode/json?address=%s&key=%s 24 | # cat=gm; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:googleMapsApiKey 25 | googleMapsJavaScriptApiKey = 26 | # cat=gm; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:googleGeocodeApiKey 27 | googleMapsGeocodeApiKey = 28 | 29 | # cat=osm; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:openStreetMapGeocodeUri 30 | openStreetMapGeocodeUri = https://nominatim.openstreetmap.org/search?q=%s&format=json&addressdetails=1 31 | 32 | # cat=design/color; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:strokeColor 33 | strokeColor = #FF0000 34 | # cat=design/color; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:strokeOpacity 35 | strokeOpacity = 0.8 36 | # cat=design/color; type=int+; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:strokeWeight 37 | strokeWeight = 2 38 | # cat=design/color; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:fillColor 39 | fillColor = #FF0000 40 | # cat=design/color; type=string; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:fillOpacity 41 | fillOpacity = 0.35 42 | # cat=design; type=int+; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:markerIconWidth 43 | markerIconWidth = 25 44 | # cat=design; type=int+; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:markerIconHeight 45 | markerIconHeight = 40 46 | # cat=design; type=int+; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:markerIconAnchorPosX 47 | markerIconAnchorPosX = 13 48 | # cat=design; type=int+; label=LLL:EXT:maps2/Resources/Private/Language/ExtConf.xlf:markerIconAnchorPosY 49 | markerIconAnchorPosY = 40 50 | -------------------------------------------------------------------------------- /ext_emconf.php: -------------------------------------------------------------------------------- 1 | 'Maps2', 12 | 'description' => 'Create maps with Marker, Area, Routes or Radius based on Google Maps or OpenStreetMap', 13 | 'version' => '12.0.8', 14 | 'category' => 'plugin', 15 | 'state' => 'stable', 16 | 'author' => 'Stefan Froemken', 17 | 'author_email' => 'projects@jweiland.net', 18 | 'author_company' => 'jweiland.net', 19 | 'constraints' => [ 20 | 'depends' => [ 21 | 'typo3' => '13.4.0-13.4.99', 22 | ], 23 | 'conflicts' => [ 24 | ], 25 | 'suggests' => [ 26 | 'static_info_tables' => '13.4.0-13.99.99', 27 | ], 28 | ], 29 | ]; 30 | -------------------------------------------------------------------------------- /ext_localconf.php: -------------------------------------------------------------------------------- 1 | 'show', 28 | ], 29 | [], 30 | ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT, 31 | ); 32 | 33 | ExtensionUtility::configurePlugin( 34 | 'Maps2', 35 | 'Overlay', 36 | [ 37 | PoiCollectionController::class => 'overlay', 38 | ], 39 | [ 40 | PoiCollectionController::class => 'overlay', 41 | ], 42 | ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT, 43 | ); 44 | 45 | ExtensionUtility::configurePlugin( 46 | 'Maps2', 47 | 'SearchWithinRadius', 48 | [ 49 | PoiCollectionController::class => 'search, listRadius', 50 | ], 51 | [ 52 | PoiCollectionController::class => 'listRadius', 53 | ], 54 | ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT, 55 | ); 56 | 57 | ExtensionUtility::configurePlugin( 58 | 'Maps2', 59 | 'CityMap', 60 | [ 61 | CityMapController::class => 'show, search', 62 | ], 63 | [ 64 | CityMapController::class => 'search', 65 | ], 66 | ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT, 67 | ); 68 | 69 | // Activate caching for info window content 70 | if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['maps2_cachedhtml'])) { 71 | $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['maps2_cachedhtml'] = [ 72 | 'groups' => ['pages', 'all'], 73 | ]; 74 | } 75 | 76 | // This is a solution to build GET forms. 77 | $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters']['maps2'] = 'tx_maps2_citymap[street]'; 78 | 79 | // Create maps2 records while saving foreign records 80 | $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['createMaps2Record'] 81 | = CreateMaps2RecordHook::class; 82 | 83 | $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1530778687] = [ 84 | 'nodeName' => 'maps2InfoWindowContent', 85 | 'priority' => 40, 86 | 'class' => InfoWindowContent::class, 87 | ]; 88 | $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1633612058] = [ 89 | 'nodeName' => 'maps2ReadOnlyInputText', 90 | 'priority' => 40, 91 | 'class' => ReadOnlyInputTextElement::class, 92 | ]; 93 | $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeResolver'][1551448205] = [ 94 | 'nodeName' => 'maps2MapProvider', 95 | 'priority' => 40, 96 | 'class' => MapProviderResolver::class, 97 | ]; 98 | }); 99 | -------------------------------------------------------------------------------- /ext_tables.sql: -------------------------------------------------------------------------------- 1 | # 2 | # Table structure for table 'tx_maps2_domain_model_poicollection' 3 | # 4 | CREATE TABLE tx_maps2_domain_model_poicollection 5 | ( 6 | configuration_map text, 7 | latitude numeric(11, 6) DEFAULT '0.000000' NOT NULL, 8 | longitude numeric(11, 6) DEFAULT '0.000000' NOT NULL, 9 | ); 10 | --------------------------------------------------------------------------------