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 class="row form-group"> 28 <div class="col-sm-12"> 29 <div id="osm-map" class="wt-ajax-load col-sm-12 osm-admin-map" dir="ltr"></div> 30 </div> 31</div> 32 33<form method="post" action="<?= e(route(MapDataSave::class)) ?>"> 34 <?= csrf_field() ?> 35 <input type="hidden" name="parent_id" value="<?= e($parent->id()) ?>"> 36 <input type="hidden" name="place_id" value="<?= e($location->id()) ?>"> 37 38 <div class="row form-group"> 39 <label class="col-form-label col-sm-1" for="new_place_name"> 40 <?= I18N::translate('Place') ?> 41 </label> 42 <div class="col-sm-3"> 43 <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"> 44 </div> 45 </div> 46 47 <div class="row form-group"> 48 <label class="col-form-label col-sm-1" for="new_place_lati"> 49 <?= I18N::translate('Latitude') ?> 50 </label> 51 <div class="col-sm-3"> 52 <div class="input-group"> 53 <input type="text" dir="ltr" id="new_place_lati" class="editable form-control" name="new_place_lati" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($latitude) ?>"> 54 </div> 55 </div> 56 </div> 57 58 <div class="row form-group"> 59 <label class="col-form-label col-sm-1" for="new_place_long"> 60 <?= I18N::translate('Longitude') ?> 61 </label> 62 <div class="col-sm-3"> 63 <div class="input-group"> 64 <input type="text" dir="ltr" id="new_place_long" class="editable form-control" name="new_place_long" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($longitude) ?>"> 65 </div> 66 </div> 67 </div> 68 69 <div class="row form-group"> 70 <div class="col-sm-10 offset-sm-1"> 71 <button class="btn btn-primary" type="submit"> 72 <?= /* I18N: A button label. */ 73 I18N::translate('save') 74 ?> 75 </button> 76 <a class="btn btn-secondary" href="<?= e(route(MapDataList::class, ['parent_id' => $parent->id()])) ?>"> 77 <?= I18N::translate('cancel') ?> 78 </a> 79 </div> 80 </div> 81</form> 82 83<?php View::push('styles') ?> 84<style> 85 .osm-admin-map { 86 height: 55vh; 87 border: 1px solid darkGrey 88 } 89</style> 90<?php View::endpush() ?> 91 92<?php View::push('javascript') ?> 93<script> 94 'use strict'; 95 96 window.WT_OSM_ADMIN = (function () { 97 const config = <?= json_encode($leaflet_config) ?>; 98 const add_place = <?= json_encode($location->id() === null) ?>; 99 100 // postcss_image_inliner breaks the autodetection of image paths. 101 L.Icon.Default.imagePath = <?= json_encode(asset('css/images/')) ?>; 102 103 // draggable marker 104 let marker = L.marker(<?= json_encode($marker_position) ?>, { 105 draggable: true, 106 }) 107 .on('dragend', function () { 108 let coords = marker.getLatLng(); 109 map.panTo(coords); 110 $('#new_place_lati').val(Number(coords.lat).toFixed(5)); 111 $('#new_place_long').val(Number(coords.lng).toFixed(5)); 112 }); 113 114 //reset map to initial state 115 let resetControl = L.Control.extend({ 116 options: { 117 position: 'topleft' 118 }, 119 onAdd: function (map) { 120 let container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom'); 121 container.onclick = function () { 122 map.fitBounds(<?= json_encode($map_bounds) ?>, {padding: [50, 30]}); 123 marker.setLatLng(<?= json_encode([$location->latitude(), $location->longitude()]) ?>); 124 $('form').trigger('reset'); 125 return false; 126 }; 127 let reset = config.i18n.reset; 128 let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container); 129 anchor.setAttribute('aria-label', reset); 130 anchor.href = '#'; 131 anchor.title = reset; 132 anchor.role = 'button'; 133 let image = L.DomUtil.create('i', 'fas fa-redo', anchor); 134 image.alt = reset; 135 136 return container; 137 } 138 }); 139 140 // Geocoder (place lookup) 141 let geocoder = new L.Control.geocoder({ 142 position: 'bottomleft', 143 defaultMarkGeocode: false, 144 expand: 'click', 145 showResultIcons: true, 146 query: <?= json_encode($location->locationName()) ?>, 147 placeholder: <?= json_encode(I18N::translate('Place')) ?>, 148 errorMessage: <?= json_encode(I18N::translate('Nothing found.')) ?>, 149 iconLabel: <?= json_encode(I18N::translate('Search')) ?> 150 }) 151 .on('markgeocode', function (result) { 152 let coords = result.geocode.center; 153 let place = result.geocode.name.split(',', 1).toString(); 154 marker.setLatLng(coords); 155 map.panTo(coords); 156 if (add_place) { 157 $('#new_place_name').val(place); 158 } 159 $('#new_place_lati').val(Number(coords.lat).toFixed(5)); 160 $('#new_place_long').val(Number(coords.lng).toFixed(5)); 161 }); 162 163 /** 164 * @private 165 */ 166 $(function () { 167 // geocoder button tooltip 168 $('.leaflet-control-geocoder-icon') 169 .attr('title', <?= json_encode(I18N::translate('Search')) ?>); 170 171 $('.editable').on('change', function () { 172 let lat = $('#new_place_lati').val(); 173 let lng = $('#new_place_long').val(); 174 marker.setLatLng([lat, lng]); 175 map.panTo([lat, lng]); 176 }); 177 }); 178 179 const map = webtrees.buildLeafletJsMap('osm-map', config) 180 .addControl(new resetControl()) 181 .addControl(geocoder) 182 .addLayer(marker) 183 .fitBounds(<?= json_encode($map_bounds) ?>, {padding: [50, 30]}) 184 .on('zoomend', function () { 185 if (!map.getBounds().contains(marker.getLatLng())) { 186 map.panTo(marker.getLatLng()); 187 } 188 }); 189 190 return 'Leaflet map interface for webtrees-2'; 191 })(); 192</script> 193<?php View::endpush() ?> 194