1<?php 2 3declare(strict_types=1); 4 5use Fisharebest\Webtrees\Http\RequestHandlers\MapDataList; 6use Fisharebest\Webtrees\Http\RequestHandlers\MapDataSave; 7use Fisharebest\Webtrees\I18N; 8use Fisharebest\Webtrees\PlaceLocation; 9use Fisharebest\Webtrees\View; 10 11/** 12 * @var array<string,string> $breadcrumbs 13 * @var string $latitude 14 * @var object $leaflet_config 15 * @var string $longitude 16 * @var PlaceLocation $location 17 * @var array<array<float>> $map_bounds 18 * @var array<float> $marker_position 19 * @var PlaceLocation $parent 20 * @var string $title 21 */ 22 23?> 24 25<?= view('components/breadcrumbs', ['links' => $breadcrumbs]) ?> 26 27<h1><?= $title ?></h1> 28 29<div id="wt-map" class="wt-ajax-load mb-3 border wt-location-edit-map" dir="ltr"></div> 30 31<form method="post" action="<?= e(route(MapDataSave::class)) ?>"> 32 <input type="hidden" name="parent_id" value="<?= e($parent->id()) ?>"> 33 <input type="hidden" name="place_id" value="<?= e($location->id()) ?>"> 34 35 <div class="row mb-3"> 36 <label class="col-form-label col-sm-1" for="new_place_name"> 37 <?= I18N::translate('Place') ?> 38 </label> 39 <div class="col-sm-3"> 40 <input type="text" id="new_place_name" name="new_place_name" value="<?= e($location->locationName()) ?>" class="form-control" required="required" maxlength="120" pattern="[^,]+" dir="auto"> 41 </div> 42 </div> 43 44 <div class="row mb-3"> 45 <label class="col-form-label col-sm-1" for="new_place_lati"> 46 <?= I18N::translate('Latitude') ?> 47 </label> 48 <div class="col-sm-3"> 49 <div class="input-group"> 50 <input type="text" dir="ltr" id="new_place_lati" class="editable form-control" name="new_place_lati" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($latitude) ?>"> 51 </div> 52 </div> 53 </div> 54 55 <div class="row mb-3"> 56 <label class="col-form-label col-sm-1" for="new_place_long"> 57 <?= I18N::translate('Longitude') ?> 58 </label> 59 <div class="col-sm-3"> 60 <div class="input-group"> 61 <input type="text" dir="ltr" id="new_place_long" class="editable form-control" name="new_place_long" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($longitude) ?>"> 62 </div> 63 </div> 64 </div> 65 66 <div class="row mb-3"> 67 <div class="col-sm-10 offset-sm-1"> 68 <button class="btn btn-primary" type="submit"> 69 <?= /* I18N: A button label. */ 70 I18N::translate('save') 71 ?> 72 </button> 73 <a class="btn btn-secondary" href="<?= e(route(MapDataList::class, ['parent_id' => $parent->id()])) ?>"> 74 <?= I18N::translate('cancel') ?> 75 </a> 76 </div> 77 </div> 78 79 <?= csrf_field() ?> 80</form> 81 82<?php View::push('javascript') ?> 83<script> 84 'use strict'; 85 86 (function () { 87 const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>; 88 const add_place = <?= json_encode($location->id() === null, JSON_THROW_ON_ERROR) ?>; 89 90 let new_place_lati = document.getElementById('new_place_lati'); 91 let new_place_long = document.getElementById('new_place_long'); 92 93 // postcss_image_inliner breaks the autodetection of image paths. 94 L.Icon.Default.imagePath = <?= json_encode(asset('css/images/'), JSON_THROW_ON_ERROR) ?>; 95 96 // draggable marker 97 let marker = L.marker(<?= json_encode($marker_position, JSON_THROW_ON_ERROR) ?>, { 98 draggable: true, 99 }) 100 .on('dragend', function () { 101 let coords = marker.getLatLng(); 102 map.panTo(coords); 103 new_place_lati.value = Number(coords.lat).toFixed(5); 104 new_place_long.value = Number(coords.lng).toFixed(5); 105 }); 106 107 /** 108 * Passed to resetControl to 109 * perform necessary reset actions on map 110 * 111 * @param {Event} event 112 */ 113 let resetCallback = function (event) { 114 event.preventDefault(); 115 map.fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]}); 116 marker.setLatLng(<?= json_encode($marker_position, JSON_THROW_ON_ERROR) ?>); 117 document.querySelector('form').reset(); 118 } 119 120 // Geocoder (place lookup) 121 let geocoder = new L.Control.geocoder({ 122 position: 'bottomleft', 123 defaultMarkGeocode: false, 124 expand: 'click', 125 showResultIcons: true, 126 query: <?= json_encode($location->locationName(), JSON_THROW_ON_ERROR) ?>, 127 placeholder: <?= json_encode(I18N::translate('Place'), JSON_THROW_ON_ERROR) ?>, 128 errorMessage: <?= json_encode(I18N::translate('Nothing found.'), JSON_THROW_ON_ERROR) ?>, 129 iconLabel: <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?> 130 }) 131 .on('markgeocode', function (result) { 132 let coords = result.geocode.center; 133 let place = result.geocode.name.split(',', 1).toString(); 134 marker.setLatLng(coords); 135 map.panTo(coords); 136 if (add_place) { 137 document.getElementById('new_place_name').value = place 138 } 139 new_place_lati.value = Number(coords.lat).toFixed(5); 140 new_place_long.value = Number(coords.lng).toFixed(5); 141 }); 142 143 const map = webtrees.buildLeafletJsMap('wt-map', config, resetCallback) 144 .addControl(geocoder) 145 .addLayer(marker) 146 .fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]}) 147 .on('zoomend', function () { 148 if (!map.getBounds().contains(marker.getLatLng())) { 149 map.panTo(marker.getLatLng()); 150 } 151 }); 152 153 document.querySelectorAll('.editable').forEach((element) => { 154 element.addEventListener('change', () => { 155 let lat = new_place_lati.value; 156 let lng = new_place_long.value; 157 marker.setLatLng([lat, lng]); 158 map.panTo([lat, lng]); 159 }); 160 }); 161 162 window.onload = function() { 163 let icon = document.querySelector('.leaflet-control-geocoder-icon'); 164 icon.setAttribute('title', <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?>); 165 } 166 })(); 167</script> 168<?php View::endpush() ?> 169