xref: /webtrees/resources/views/admin/location-edit.phtml (revision 84df6051daf6e0d91b745b7adc42f92ae7be49ab)
1d70512abSGreg Roach<?php
2d70512abSGreg Roach
394e35917SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MapDataList;
490949315SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MapDataSave;
5d70512abSGreg Roachuse Fisharebest\Webtrees\I18N;
69a9dfcf7SGreg Roachuse Fisharebest\Webtrees\PlaceLocation;
7d70512abSGreg Roachuse Fisharebest\Webtrees\View;
8d70512abSGreg Roach
99a9dfcf7SGreg Roach/**
109a9dfcf7SGreg Roach * @var array<string,string> $breadcrumbs
119a9dfcf7SGreg Roach * @var string               $latitude
12c9c6f2ecSGreg Roach * @var object               $leaflet_config
139a9dfcf7SGreg Roach * @var string               $longitude
149a9dfcf7SGreg Roach * @var PlaceLocation        $location
159a9dfcf7SGreg Roach * @var array<array<float>>  $map_bounds
1690949315SGreg Roach * @var array<float>         $marker_position
179a9dfcf7SGreg Roach * @var PlaceLocation        $parent
189a9dfcf7SGreg Roach * @var string               $title
199a9dfcf7SGreg Roach */
209a9dfcf7SGreg Roach
21d70512abSGreg Roach?>
22dd6b2bfcSGreg Roach
23dd6b2bfcSGreg Roach<?= view('components/breadcrumbs', ['links' => $breadcrumbs]) ?>
24dd6b2bfcSGreg Roach
25dd6b2bfcSGreg Roach<h1><?= $title ?></h1>
26dd6b2bfcSGreg Roach
27*84df6051SGreg Roach<div id="wt-map" class="wt-ajax-load mb-3 border wt-location-edit-map" dir="ltr"></div>
28dd6b2bfcSGreg Roach
292a93faa6SGreg Roach<form method="post" action="<?= e(route(MapDataSave::class)) ?>">
30dd6b2bfcSGreg Roach    <?= csrf_field() ?>
312a93faa6SGreg Roach    <input type="hidden" name="parent_id" value="<?= e($parent->id()) ?>">
322a93faa6SGreg Roach    <input type="hidden" name="place_id" value="<?= e($location->id()) ?>">
33dd6b2bfcSGreg Roach
34afc2d190SGreg Roach    <div class="row form-group mb-3">
35dd6b2bfcSGreg Roach        <label class="col-form-label col-sm-1" for="new_place_name">
36dd6b2bfcSGreg Roach            <?= I18N::translate('Place') ?>
37dd6b2bfcSGreg Roach        </label>
38e340fe65SGreg Roach        <div class="col-sm-3">
397dca5265SGreg Roach            <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">
40dd6b2bfcSGreg Roach        </div>
41dd6b2bfcSGreg Roach    </div>
42dd6b2bfcSGreg Roach
43afc2d190SGreg Roach    <div class="row form-group mb-3">
4456a34df1SGreg Roach        <label class="col-form-label col-sm-1" for="new_place_lati">
45dd6b2bfcSGreg Roach            <?= I18N::translate('Latitude') ?>
46dd6b2bfcSGreg Roach        </label>
47dd6b2bfcSGreg Roach        <div class="col-sm-3">
48dd6b2bfcSGreg Roach            <div class="input-group">
4990949315SGreg Roach                <input type="text" dir="ltr" id="new_place_lati" class="editable form-control" name="new_place_lati" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($latitude) ?>">
50dd6b2bfcSGreg Roach            </div>
51dd6b2bfcSGreg Roach        </div>
52e340fe65SGreg Roach    </div>
53dd6b2bfcSGreg Roach
54afc2d190SGreg Roach    <div class="row form-group mb-3">
5556a34df1SGreg Roach        <label class="col-form-label col-sm-1" for="new_place_long">
56dd6b2bfcSGreg Roach            <?= I18N::translate('Longitude') ?>
57dd6b2bfcSGreg Roach        </label>
58dd6b2bfcSGreg Roach        <div class="col-sm-3">
59dd6b2bfcSGreg Roach            <div class="input-group">
6090949315SGreg Roach                <input type="text" dir="ltr" id="new_place_long" class="editable form-control" name="new_place_long" placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($longitude) ?>">
61dd6b2bfcSGreg Roach            </div>
62dd6b2bfcSGreg Roach        </div>
63dd6b2bfcSGreg Roach    </div>
64dd6b2bfcSGreg Roach
65afc2d190SGreg Roach    <div class="row form-group mb-3">
66dd6b2bfcSGreg Roach        <div class="col-sm-10 offset-sm-1">
67dd6b2bfcSGreg Roach            <button class="btn btn-primary" type="submit">
68dd6b2bfcSGreg Roach                <?= /* I18N: A button label. */
69dd6b2bfcSGreg Roach                I18N::translate('save')
70dd6b2bfcSGreg Roach                ?>
71dd6b2bfcSGreg Roach            </button>
7294e35917SGreg Roach            <a class="btn btn-secondary" href="<?= e(route(MapDataList::class, ['parent_id' => $parent->id()])) ?>">
73dd6b2bfcSGreg Roach                <?= I18N::translate('cancel') ?>
74dd6b2bfcSGreg Roach            </a>
75dd6b2bfcSGreg Roach        </div>
76dd6b2bfcSGreg Roach    </div>
77dd6b2bfcSGreg Roach</form>
78dd6b2bfcSGreg Roach
79dd6b2bfcSGreg Roach<?php View::push('javascript') ?>
8074b9ba3fSGreg Roach<script>
81caa53803SDavid Drury  'use strict';
82dd6b2bfcSGreg Roach
8304a72e8fSDavid Drury  (function () {
84728c8c27SGreg Roach    const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>;
85728c8c27SGreg Roach    const add_place = <?= json_encode($location->id() === null, JSON_THROW_ON_ERROR) ?>;
862cbb0620SDavid Drury
8704a72e8fSDavid Drury    let new_place_lati = document.getElementById('new_place_lati');
8804a72e8fSDavid Drury    let new_place_long = document.getElementById('new_place_long');
8904a72e8fSDavid Drury
9075e7614aSGreg Roach    // postcss_image_inliner breaks the autodetection of image paths.
91728c8c27SGreg Roach    L.Icon.Default.imagePath = <?= json_encode(asset('css/images/'), JSON_THROW_ON_ERROR) ?>;
9275e7614aSGreg Roach
93caa53803SDavid Drury    // draggable marker
94728c8c27SGreg Roach    let marker = L.marker(<?= json_encode($marker_position, JSON_THROW_ON_ERROR) ?>, {
95caa53803SDavid Drury      draggable: true,
96caa53803SDavid Drury    })
979a9dfcf7SGreg Roach    .on('dragend', function () {
98dd6b2bfcSGreg Roach      let coords = marker.getLatLng();
99dd6b2bfcSGreg Roach      map.panTo(coords);
10004a72e8fSDavid Drury      new_place_lati.value = Number(coords.lat).toFixed(5);
10104a72e8fSDavid Drury      new_place_long.value = Number(coords.lng).toFixed(5);
102dd6b2bfcSGreg Roach    });
103dd6b2bfcSGreg Roach
104caa53803SDavid Drury    //reset map to initial state
105caa53803SDavid Drury    let resetControl = L.Control.extend({
106caa53803SDavid Drury      options: {
107caa53803SDavid Drury          position: 'topleft'
108caa53803SDavid Drury      },
109caa53803SDavid Drury      onAdd: function (map) {
110caa53803SDavid Drury        let container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
111caa53803SDavid Drury        container.onclick = function () {
112728c8c27SGreg Roach          map.fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]});
113728c8c27SGreg Roach          marker.setLatLng(<?= json_encode([$location->latitude(), $location->longitude()], JSON_THROW_ON_ERROR) ?>);
11404a72e8fSDavid Drury          document.querySelector('form').reset();
11504a72e8fSDavid Drury
116caa53803SDavid Drury          return false;
117caa53803SDavid Drury        };
118c9c6f2ecSGreg Roach        let reset = config.i18n.reset;
119caa53803SDavid Drury        let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container);
120caa53803SDavid Drury        anchor.setAttribute('aria-label', reset);
121caa53803SDavid Drury        anchor.href = '#';
122caa53803SDavid Drury        anchor.title = reset;
123caa53803SDavid Drury        anchor.role = 'button';
124caa53803SDavid Drury        let image = L.DomUtil.create('i', 'fas fa-redo', anchor);
125caa53803SDavid Drury        image.alt = reset;
126dd6b2bfcSGreg Roach
127caa53803SDavid Drury        return container;
128caa53803SDavid Drury      }
129caa53803SDavid Drury    });
130dd6b2bfcSGreg Roach
131caa53803SDavid Drury    // Geocoder (place lookup)
132caa53803SDavid Drury    let geocoder = new L.Control.geocoder({
133c9c6f2ecSGreg Roach      position: 'bottomleft',
134caa53803SDavid Drury      defaultMarkGeocode: false,
13522b076ddSGreg Roach      expand: 'click',
136caa53803SDavid Drury      showResultIcons: true,
137728c8c27SGreg Roach      query: <?= json_encode($location->locationName(), JSON_THROW_ON_ERROR) ?>,
138728c8c27SGreg Roach      placeholder: <?= json_encode(I18N::translate('Place'), JSON_THROW_ON_ERROR) ?>,
139728c8c27SGreg Roach      errorMessage: <?= json_encode(I18N::translate('Nothing found.'), JSON_THROW_ON_ERROR) ?>,
140728c8c27SGreg Roach      iconLabel: <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?>
141caa53803SDavid Drury    })
142caa53803SDavid Drury    .on('markgeocode', function (result) {
143caa53803SDavid Drury      let coords = result.geocode.center;
144164ab4fbSDavid Drury      let place = result.geocode.name.split(',', 1).toString();
145caa53803SDavid Drury      marker.setLatLng(coords);
146caa53803SDavid Drury      map.panTo(coords);
14762be603fSGreg Roach      if (add_place) {
14804a72e8fSDavid Drury        document.getElementById('new_place_name').value = place
149caa53803SDavid Drury      }
15004a72e8fSDavid Drury      new_place_lati.value = Number(coords.lat).toFixed(5);
15104a72e8fSDavid Drury      new_place_long.value = Number(coords.lng).toFixed(5);
15262be603fSGreg Roach    });
153caa53803SDavid Drury
15404a72e8fSDavid Drury    const map = webtrees.buildLeafletJsMap('wt-map', config)
155caa53803SDavid Drury      .addControl(new resetControl())
156caa53803SDavid Drury      .addControl(geocoder)
157caa53803SDavid Drury      .addLayer(marker)
158728c8c27SGreg Roach      .fitBounds(<?= json_encode($map_bounds, JSON_THROW_ON_ERROR) ?>, {padding: [50, 30]})
1599a9dfcf7SGreg Roach      .on('zoomend', function () {
160d3a6a36aSGreg Roach        if (!map.getBounds().contains(marker.getLatLng())) {
161d3a6a36aSGreg Roach          map.panTo(marker.getLatLng());
162d3a6a36aSGreg Roach        }
163caa53803SDavid Drury    });
164dd6b2bfcSGreg Roach
16504a72e8fSDavid Drury    document.querySelectorAll('.editable').forEach((element) => {
16604a72e8fSDavid Drury      element.addEventListener('change', () => {
16704a72e8fSDavid Drury        let lat = new_place_lati.value;
16804a72e8fSDavid Drury        let lng = new_place_long.value;
16904a72e8fSDavid Drury        marker.setLatLng([lat, lng]);
17004a72e8fSDavid Drury        map.panTo([lat, lng]);
17104a72e8fSDavid Drury      });
17204a72e8fSDavid Drury    });
17304a72e8fSDavid Drury
17404a72e8fSDavid Drury    window.onload = function() {
17504a72e8fSDavid Drury      let icon = document.querySelector('.leaflet-control-geocoder-icon');
17604a72e8fSDavid Drury      icon.setAttribute('title', <?= json_encode(I18N::translate('Search'), JSON_THROW_ON_ERROR) ?>);
17704a72e8fSDavid Drury    }
178dd6b2bfcSGreg Roach  })();
179dd6b2bfcSGreg Roach</script>
180dd6b2bfcSGreg Roach<?php View::endpush() ?>
181