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