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