xref: /webtrees/resources/views/admin/location-edit.phtml (revision b56fa9dd6a5e9075de5337fd34748412e9e559a7)
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