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 string $longitude 13 * @var PlaceLocation $location 14 * @var array<array<float>> $map_bounds 15 * @var array<float> $marker_position 16 * @var PlaceLocation $parent 17 * @var mixed $provider 18 * @var string $title 19 */ 20 21?> 22 23<?= view('components/breadcrumbs', ['links' => $breadcrumbs]) ?> 24 25<h1><?= $title ?></h1> 26 27<div class="form-group row"> 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="place_id" value="<?= e($location->id()) ?>"> 36 37 <div class="form-group row"> 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 maxlength="120" pattern="[^,]+" dir="auto"> 43 </div> 44 </div> 45 46 <div class="form-group row"> 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="form-group row"> 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="form-group row"> 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(route(MapDataList::class, ['parent_id' => $parent->id()])) ?>"> 76 <?= I18N::translate('cancel') ?> 77 </a> 78 </div> 79 </div> 80</form> 81 82<?php View::push('styles') ?> 83<style> 84 .osm-admin-map { 85 height: 55vh; 86 border: 1px solid darkGrey 87 } 88</style> 89<?php View::endpush() ?> 90 91<?php View::push('javascript') ?> 92<script> 93 'use strict'; 94 95 window.WT_OSM_ADMIN = (function () { 96 const minZoom = 2; 97 98 let provider = <?= json_encode($provider) ?>; 99 let map = null; 100 let add_place = <?= json_encode($location->id() === null) ?>; 101 console.log(add_place); 102 103 // map components 104 105 // postcss_image_inliner breaks the autodetection of image paths. 106 L.Icon.Default.imagePath = <?= json_encode(asset('css/images/')) ?>; 107 108 // draggable marker 109 let marker = L.marker(<?= json_encode($marker_position) ?>, { 110 draggable: true, 111 }) 112 .on('dragend', function () { 113 let coords = marker.getLatLng(); 114 map.panTo(coords); 115 $('#new_place_lati').val(Number(coords.lat).toFixed(5)); 116 $('#new_place_long').val(Number(coords.lng).toFixed(5)); 117 $('#new_zoom_factor').val(Number(map.getZoom())); 118 }); 119 120 //reset map to initial state 121 let resetControl = L.Control.extend({ 122 options: { 123 position: 'topleft' 124 }, 125 onAdd: function (map) { 126 let container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom'); 127 container.onclick = function () { 128 map.fitBounds(<?= json_encode($map_bounds) ?>, {padding: [50, 30]}); 129 marker.setLatLng(<?= json_encode([$location->latitude(), $location->longitude()]) ?>); 130 $('form').trigger('reset'); 131 return false; 132 }; 133 let reset = <?= json_encode(I18N::translate('Reset to initial map state')) ?>; 134 let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container); 135 anchor.setAttribute('aria-label', reset); 136 anchor.href = '#'; 137 anchor.title = reset; 138 anchor.role = 'button'; 139 let image = L.DomUtil.create('i', 'fas fa-redo', anchor); 140 image.alt = reset; 141 142 return container; 143 } 144 }); 145 146 // zoom control with localised text 147 let zoomCtl = new L.control.zoom({ 148 zoomInTitle: <?= json_encode(I18N::translate('Zoom in')) ?>, 149 zoomOutTitle: <?= json_encode(I18N::translate('Zoom out')) ?>, 150 }); 151 152 // Geocoder (place lookup) 153 let geocoder = new L.Control.geocoder({ 154 defaultMarkGeocode: false, 155 expand: 'click', 156 showResultIcons: true, 157 query: <?= json_encode($location->locationName()) ?>, 158 placeholder: <?= json_encode(I18N::translate('Place')) ?>, 159 errorMessage: <?= json_encode(I18N::translate('Nothing found.')) ?>, 160 iconLabel: <?= json_encode(I18N::translate('Search')) ?> 161 }) 162 .on('markgeocode', function (result) { 163 let coords = result.geocode.center; 164 let place = result.geocode.name.split(',', 1); 165 marker.setLatLng(coords); 166 map.panTo(coords); 167 if (add_place) { 168 $('#new_place_name').val(place.shift()); 169 } 170 $('#new_place_lati').val(Number(coords.lat).toFixed(5)); 171 $('#new_place_long').val(Number(coords.lng).toFixed(5)); 172 $('#new_zoom_factor').val(Number(map.getZoom())); 173 }); 174 175 /** 176 * 177 * @private 178 */ 179 $(function () { 180 // geocoder button tooltip 181 $('.leaflet-control-geocoder-icon') 182 .attr('title', <?= json_encode(I18N::translate('Search')) ?>); 183 184 $('.editable').on('change', function () { 185 let lat = $('#new_place_lati').val(); 186 let lng = $('#new_place_long').val(); 187 marker.setLatLng([lat, lng]); 188 map.panTo([lat, lng]); 189 }); 190 }); 191 192 // Create the map with all controls and layers 193 map = L.map('osm-map', { 194 minZoom: minZoom, // maxZoom set by leaflet-providers.js 195 zoomControl: false, // remove default 196 }) 197 .addControl(new resetControl()) 198 .addControl(zoomCtl) 199 .addControl(geocoder) 200 .addLayer(marker) 201 .addLayer(L.tileLayer(provider.url, provider.options)) 202 .fitBounds(<?= json_encode($map_bounds) ?>, {padding: [50, 30]}) 203 .on('zoomend', function () { 204 $('#new_zoom_factor').val(map.getZoom()); 205 }); 206 207 return 'Leaflet map interface for webtrees-2'; 208 })(); 209</script> 210<?php View::endpush() ?> 211