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