xref: /webtrees/resources/views/admin/location-edit.phtml (revision 6f59525087dd4ee1d17c7375524d95ace7942861)
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 object               $leaflet_config
13 * @var string               $longitude
14 * @var PlaceLocation        $location
15 * @var array<array<float>>  $map_bounds
16 * @var array<float>         $marker_position
17 * @var PlaceLocation        $parent
18 * @var string               $title
19 */
20
21?>
22
23<?= view('components/breadcrumbs', ['links' => $breadcrumbs]) ?>
24
25<h1><?= $title ?></h1>
26
27<div id="wt-map" class="wt-ajax-load mb-3 border wt-location-edit-map" dir="ltr"></div>
28
29<form method="post" action="<?= e(route(MapDataSave::class)) ?>">
30    <?= csrf_field() ?>
31    <input type="hidden" name="parent_id" value="<?= e($parent->id()) ?>">
32    <input type="hidden" name="place_id" value="<?= e($location->id()) ?>">
33
34    <div class="row form-group mb-3">
35        <label class="col-form-label col-sm-1" for="new_place_name">
36            <?= I18N::translate('Place') ?>
37        </label>
38        <div class="col-sm-3">
39            <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">
40        </div>
41    </div>
42
43    <div class="row form-group mb-3">
44        <label class="col-form-label col-sm-1" for="new_place_lati">
45            <?= I18N::translate('Latitude') ?>
46        </label>
47        <div class="col-sm-3">
48            <div class="input-group">
49                <input type="text" dir="ltr" id="new_place_lati" class="editable form-control" name="new_place_lati" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($latitude) ?>">
50            </div>
51        </div>
52    </div>
53
54    <div class="row form-group mb-3">
55        <label class="col-form-label col-sm-1" for="new_place_long">
56            <?= I18N::translate('Longitude') ?>
57        </label>
58        <div class="col-sm-3">
59            <div class="input-group">
60                <input type="text" dir="ltr" id="new_place_long" class="editable form-control" name="new_place_long" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($longitude) ?>">
61            </div>
62        </div>
63    </div>
64
65    <div class="row form-group mb-3">
66        <div class="col-sm-10 offset-sm-1">
67            <button class="btn btn-primary" type="submit">
68                <?= /* I18N: A button label. */
69                I18N::translate('save')
70                ?>
71            </button>
72            <a class="btn btn-secondary" href="<?= e(route(MapDataList::class, ['parent_id' => $parent->id()])) ?>">
73                <?= I18N::translate('cancel') ?>
74            </a>
75        </div>
76    </div>
77</form>
78
79<?php View::push('javascript') ?>
80<script>
81  'use strict';
82
83  (function () {
84    const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>;
85    const add_place = <?= json_encode($location->id() === null, JSON_THROW_ON_ERROR) ?>;
86
87    let new_place_lati = document.getElementById('new_place_lati');
88    let new_place_long = document.getElementById('new_place_long');
89
90    // postcss_image_inliner breaks the autodetection of image paths.
91    L.Icon.Default.imagePath = <?= json_encode(asset('css/images/'), JSON_THROW_ON_ERROR) ?>;
92
93    // draggable marker
94    let marker = L.marker(<?= json_encode($marker_position, JSON_THROW_ON_ERROR) ?>, {
95      draggable: true,
96    })
97    .on('dragend', function () {
98      let coords = marker.getLatLng();
99      map.panTo(coords);
100      new_place_lati.value = Number(coords.lat).toFixed(5);
101      new_place_long.value = Number(coords.lng).toFixed(5);
102    });
103
104    //reset map to initial state
105    let resetControl = L.Control.extend({
106      options: {
107          position: 'topleft'
108      },
109      onAdd: function (map) {
110        let container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
111        container.onclick = function () {
112          map.fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]});
113          marker.setLatLng(<?= json_encode([$location->latitude(), $location->longitude()], JSON_THROW_ON_ERROR) ?>);
114          document.querySelector('form').reset();
115
116          return false;
117        };
118        let reset = config.i18n.reset;
119        let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container);
120        anchor.setAttribute('aria-label', reset);
121        anchor.href = '#';
122        anchor.title = reset;
123        anchor.role = 'button';
124        let image = L.DomUtil.create('i', 'fas fa-redo', anchor);
125        image.alt = reset;
126
127        return container;
128      }
129    });
130
131    // Geocoder (place lookup)
132    let geocoder = new L.Control.geocoder({
133      position: 'bottomleft',
134      defaultMarkGeocode: false,
135      expand: 'click',
136      showResultIcons: true,
137      query: <?= json_encode($location->locationName(), JSON_THROW_ON_ERROR) ?>,
138      placeholder: <?= json_encode(I18N::translate('Place'), JSON_THROW_ON_ERROR) ?>,
139      errorMessage: <?= json_encode(I18N::translate('Nothing found.'), JSON_THROW_ON_ERROR) ?>,
140      iconLabel: <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?>
141    })
142    .on('markgeocode', function (result) {
143      let coords = result.geocode.center;
144      let place = result.geocode.name.split(',', 1).toString();
145      marker.setLatLng(coords);
146      map.panTo(coords);
147      if (add_place) {
148        document.getElementById('new_place_name').value = place
149      }
150      new_place_lati.value = Number(coords.lat).toFixed(5);
151      new_place_long.value = Number(coords.lng).toFixed(5);
152    });
153
154    const map = webtrees.buildLeafletJsMap('wt-map', config)
155      .addControl(new resetControl())
156      .addControl(geocoder)
157      .addLayer(marker)
158      .fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]})
159      .on('zoomend', function () {
160        if (!map.getBounds().contains(marker.getLatLng())) {
161          map.panTo(marker.getLatLng());
162        }
163    });
164
165    document.querySelectorAll('.editable').forEach((element) => {
166      element.addEventListener('change', () => {
167        let lat = new_place_lati.value;
168        let lng = new_place_long.value;
169        marker.setLatLng([lat, lng]);
170        map.panTo([lat, lng]);
171      });
172    });
173
174    window.onload = function() {
175      let icon = document.querySelector('.leaflet-control-geocoder-icon');
176      icon.setAttribute('title', <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?>);
177    }
178  })();
179</script>
180<?php View::endpush() ?>
181