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