xref: /webtrees/resources/views/admin/location-edit.phtml (revision 77d0194e2990079106916d44571d7f807d2e850d)
1<?php
2
3declare(strict_types=1);
4
5use Fisharebest\Webtrees\Http\RequestHandlers\MapDataList;
6use Fisharebest\Webtrees\Http\RequestHandlers\MapDataSave;
7use Fisharebest\Webtrees\I18N;
8use Fisharebest\Webtrees\PlaceLocation;
9use Fisharebest\Webtrees\View;
10
11/**
12 * @var array<string,string> $breadcrumbs
13 * @var string               $latitude
14 * @var object               $leaflet_config
15 * @var string               $longitude
16 * @var PlaceLocation        $location
17 * @var array<array<float>>  $map_bounds
18 * @var array<float>         $marker_position
19 * @var PlaceLocation        $parent
20 * @var string               $title
21 * @var string               $url
22 */
23
24?>
25
26<?= view('components/breadcrumbs', ['links' => $breadcrumbs]) ?>
27
28<h1><?= $title ?></h1>
29
30<div id="wt-map" class="wt-ajax-load mb-3 border wt-location-edit-map" dir="ltr"></div>
31
32<form method="post" action="<?= e(route(MapDataSave::class)) ?>">
33    <input type="hidden" name="parent_id" value="<?= $parent->id() ?>">
34    <input type="hidden" name="place_id" value="<?= $location->id() ?>">
35    <input type="hidden" name="url" value="<?= e($url) ?>">
36
37    <div class="row mb-3">
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="required" maxlength="120" pattern="[^,]+" dir="auto">
43        </div>
44    </div>
45
46    <div class="row mb-3">
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="row mb-3">
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="row mb-3">
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($url) ?>">
76                <?= I18N::translate('cancel') ?>
77            </a>
78        </div>
79    </div>
80
81    <?= csrf_field() ?>
82</form>
83
84<?php View::push('javascript') ?>
85<script>
86  'use strict';
87
88  (function () {
89    const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>;
90    const add_place = <?= json_encode($location->id() === null, JSON_THROW_ON_ERROR) ?>;
91
92    let new_place_lati = document.getElementById('new_place_lati');
93    let new_place_long = document.getElementById('new_place_long');
94
95    // postcss_image_inliner breaks the autodetection of image paths.
96    L.Icon.Default.imagePath = <?= json_encode(asset('css/images/'), JSON_THROW_ON_ERROR) ?>;
97
98    // draggable marker
99    let marker = L.marker(<?= json_encode($marker_position, JSON_THROW_ON_ERROR) ?>, {
100      draggable: true,
101    })
102    .on('dragend', function () {
103      let coords = marker.getLatLng();
104      map.panTo(coords);
105      new_place_lati.value = Number(coords.lat).toFixed(5);
106      new_place_long.value = Number(coords.lng).toFixed(5);
107    });
108
109    /**
110     * Passed to resetControl to
111     * perform necessary reset actions on map
112     *
113     * @param {Event} event
114     */
115    let resetCallback = function (event) {
116      event.preventDefault();
117      map.fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]});
118      marker.setLatLng(<?= json_encode($marker_position, JSON_THROW_ON_ERROR) ?>);
119      document.querySelector('form').reset();
120    }
121
122    // Geocoder (place lookup)
123    let geocoder = new L.Control.geocoder({
124      position: 'bottomleft',
125      defaultMarkGeocode: false,
126      expand: 'click',
127      showResultIcons: true,
128      query: <?= json_encode($location->locationName(), JSON_THROW_ON_ERROR) ?>,
129      placeholder: <?= json_encode(I18N::translate('Place'), JSON_THROW_ON_ERROR) ?>,
130      errorMessage: <?= json_encode(I18N::translate('Nothing found.'), JSON_THROW_ON_ERROR) ?>,
131      iconLabel: <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?>
132    })
133    .on('markgeocode', function (result) {
134      let coords = result.geocode.center;
135      let place = result.geocode.name.split(',', 1).toString();
136      marker.setLatLng(coords);
137      map.panTo(coords);
138      if (add_place) {
139        document.getElementById('new_place_name').value = place
140      }
141      new_place_lati.value = Number(coords.lat).toFixed(5);
142      new_place_long.value = Number(coords.lng).toFixed(5);
143    });
144
145    const map = webtrees.buildLeafletJsMap('wt-map', config, resetCallback)
146      .addControl(geocoder)
147      .addLayer(marker)
148      .fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]})
149      .on('zoomend', function () {
150        if (!map.getBounds().contains(marker.getLatLng())) {
151          map.panTo(marker.getLatLng());
152        }
153    });
154
155    document.querySelectorAll('.editable').forEach((element) => {
156      element.addEventListener('change', () => {
157        let lat = new_place_lati.value;
158        let lng = new_place_long.value;
159        marker.setLatLng([lat, lng]);
160        map.panTo([lat, lng]);
161      });
162    });
163
164    window.onload = function() {
165      let icon = document.querySelector('.leaflet-control-geocoder-icon');
166      icon.setAttribute('title', <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?>);
167    }
168  })();
169</script>
170<?php View::endpush() ?>
171