xref: /webtrees/resources/views/admin/location-edit.phtml (revision afa67798854828b1edc33dd077960ec2b18e6140)
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    <input type="hidden" name="parent_id" value="<?= e($location->parent()->id()) ?>">
37
38    <div class="form-group row">
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="form-group row">
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="form-group row">
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="form-group row">
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 minZoom   = 2;
98        const provider  = <?= json_encode($provider) ?>;
99        const add_place = <?= json_encode($location->id() === null) ?>;
100
101        let map = null;
102        // map components
103
104        // postcss_image_inliner breaks the autodetection of image paths.
105        L.Icon.Default.imagePath = <?= json_encode(asset('css/images/')) ?>;
106
107        // draggable marker
108        let marker = L.marker(<?= json_encode($marker_position) ?>, {
109            draggable: true,
110        })
111            .on('dragend', function () {
112                let coords = marker.getLatLng();
113                map.panTo(coords);
114                $('#new_place_lati').val(Number(coords.lat).toFixed(5));
115                $('#new_place_long').val(Number(coords.lng).toFixed(5));
116            });
117
118        //reset map to initial state
119        let resetControl = L.Control.extend({
120            options: {
121                position: 'topleft'
122            },
123            onAdd: function (map) {
124                let container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
125                container.onclick = function () {
126                    map.fitBounds(<?= json_encode($map_bounds) ?>, {padding: [50, 30]});
127                    marker.setLatLng(<?= json_encode([$location->latitude(), $location->longitude()]) ?>);
128                    $('form').trigger('reset');
129                    return false;
130                };
131                let reset = <?= json_encode(I18N::translate('Reset to initial map state')) ?>;
132                let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container);
133                anchor.setAttribute('aria-label', reset);
134                anchor.href = '#';
135                anchor.title = reset;
136                anchor.role = 'button';
137                let image = L.DomUtil.create('i', 'fas fa-redo', anchor);
138                image.alt = reset;
139
140                return container;
141            }
142        });
143
144        // zoom control with localised text
145        let zoomCtl = new L.control.zoom({
146            zoomInTitle:  <?= json_encode(I18N::translate('Zoom in')) ?>,
147            zoomOutTitle: <?= json_encode(I18N::translate('Zoom out')) ?>,
148        });
149
150        // Geocoder (place lookup)
151        let geocoder = new L.Control.geocoder({
152            defaultMarkGeocode: false,
153            expand: 'click',
154            showResultIcons: true,
155            query: <?= json_encode($location->locationName()) ?>,
156            placeholder: <?= json_encode(I18N::translate('Place')) ?>,
157            errorMessage: <?= json_encode(I18N::translate('Nothing found.')) ?>,
158            iconLabel: <?= json_encode(I18N::translate('Search')) ?>
159        })
160            .on('markgeocode', function (result) {
161                let coords = result.geocode.center;
162                let place = result.geocode.name.split(',', 1).toString();
163                marker.setLatLng(coords);
164                map.panTo(coords);
165                if (add_place) {
166                    $('#new_place_name').val(place);
167                }
168                $('#new_place_lati').val(Number(coords.lat).toFixed(5));
169                $('#new_place_long').val(Number(coords.lng).toFixed(5));
170            });
171
172        /**
173         *
174         * @private
175         */
176        $(function () {
177            // geocoder button tooltip
178            $('.leaflet-control-geocoder-icon')
179                .attr('title', <?= json_encode(I18N::translate('Search')) ?>);
180
181            $('.editable').on('change', function () {
182                let lat = $('#new_place_lati').val();
183                let lng = $('#new_place_long').val();
184                marker.setLatLng([lat, lng]);
185                map.panTo([lat, lng]);
186            });
187        });
188
189        // Create the map with all controls and layers
190        map = L.map('osm-map', {
191            minZoom: minZoom, // maxZoom set by leaflet-providers.js
192            zoomControl: false,   // remove default
193        })
194            .addControl(new resetControl())
195            .addControl(zoomCtl)
196            .addControl(geocoder)
197            .addLayer(marker)
198            .addLayer(L.tileLayer(provider.url, provider.options))
199            .fitBounds(<?= json_encode($map_bounds) ?>, {padding: [50, 30]})
200            .on('zoomend', function () {
201              if (!map.getBounds().contains(marker.getLatLng())) {
202                map.panTo(marker.getLatLng());
203              }
204            });
205
206        return 'Leaflet map interface for webtrees-2';
207    })();
208</script>
209<?php View::endpush() ?>
210