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