xref: /webtrees/resources/views/admin/location-edit.phtml (revision a00bcc6367b57a659a7d6d69e7e1d00f79db8d9f)
1<?php use Fisharebest\Webtrees\I18N;
2use Fisharebest\Webtrees\View; ?>
3<?php ?>
4
5<?= view('components/breadcrumbs', ['links' => $breadcrumbs]) ?>
6
7<h1><?= $title ?></h1>
8
9<div class="form-group row">
10    <div class="col-sm-10 offset-sm-1">
11        <div id="osm-map" class="wt-ajax-load col-sm-12 osm-admin-map"></div>
12    </div>
13</div>
14
15<form method="post">
16    <?= csrf_field() ?>
17    <input type="hidden" name="place_id" value="<?= e($place_id) ?>">
18    <input type="hidden" name="level" value="<?= count($hierarchy) ?>">
19    <input type="hidden" name="place_long" value="<?= e($lng) ?>">
20    <input type="hidden" name="place_lati" value="<?= e($lat) ?>">
21
22    <div class="form-group row">
23        <label class="col-form-label col-sm-1" for="new_place_name">
24            <?= I18N::translate('Place') ?>
25        </label>
26        <div class="col-sm-5">
27            <input type="text" id="new_place_name" name="new_place_name" value="<?= e($location->locationName()) ?>"
28            class="form-control" required>
29        </div>
30        <label class="col-form-label col-sm-1" for="icon">
31            <?= I18N::translate('Flag') ?>
32        </label>
33        <div class="col-sm-4">
34            <div class="input-group" dir="ltr">
35                <input type="text" name="icon" id="icon" class="form-control" value="<?= e($location->icon()) ?>">
36            </div>
37        </div>
38    </div>
39
40    <div class="form-group row">
41        <label class="col-form-label col-sm-1" for="new_place_lati">
42            <?= I18N::translate('Latitude') ?>
43        </label>
44        <div class="col-sm-3">
45            <div class="input-group">
46                <input type="text" dir="ltr" id="new_place_lati" class="editable form-control" name="new_place_lati" required
47                placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($lat) ?>"
48                >
49            </div>
50        </div>
51
52        <label class="col-form-label col-sm-1" for="new_place_long">
53            <?= I18N::translate('Longitude') ?>
54        </label>
55        <div class="col-sm-3">
56            <div class="input-group">
57                <input type="text" dir="ltr" id="new_place_long" class="editable form-control" name="new_place_long" required
58                placeholder="<?= I18N::translate('degrees') ?>" value="<?= e($lng) ?>"
59                >
60            </div>
61        </div>
62        <label class="col-form-label col-sm-1" for="new_zoom_factor">
63            <?= I18N::translate('Zoom') ?>
64        </label>
65        <div class="col-sm-2">
66            <input type="text" id="new_zoom_factor" name="new_zoom_factor" value="<?= e($location->zoom()) ?>"
67            class="form-control" required readonly>
68        </div>
69    </div>
70
71    <div class="form-group row">
72        <div class="col-sm-10 offset-sm-1">
73            <button class="btn btn-primary" type="submit">
74                <?= /* I18N: A button label. */
75                I18N::translate('save')
76                ?>
77            </button>
78            <a class="btn btn-secondary" href="<?= e(route('map-data', ['parent_id' => $parent_id])) ?>">
79                <?= I18N::translate('cancel') ?>
80            </a>
81        </div>
82    </div>
83</form>
84
85<?php View::push('styles') ?>
86<style>
87    .osm-wrapper, .osm-user-map {
88        height: 45vh
89    }
90
91    .osm-admin-map {
92        height: 55vh;
93        border: 1px solid darkGrey
94    }
95
96    .osm-sidebar {
97        height: 100%;
98        overflow-y: auto;
99        padding: 0;
100        margin: 0;
101        border: 0;
102        display: none;
103        font-size: small;
104    }
105
106    .osm-sidebar .gchart {
107        margin: 1px;
108        padding: 2px
109    }
110
111    .osm-sidebar .gchart img {
112        height: 15px;
113        width: 25px
114    }
115
116    .osm-sidebar .border-danger:hover {
117        cursor: not-allowed
118    }
119</style>
120<?php View::endpush() ?>
121
122<?php View::push('javascript') ?>
123<script type="application/javascript">
124    "use strict";
125
126    window.WT_OSM_ADMIN = (function () {
127        let baseData = {
128            minZoom:         2,
129            providerName:    "OpenStreetMap.Mapnik",
130            providerOptions: [],
131            I18N:            {
132                zoomInTitle: <?= json_encode(I18N::translate('Zoom in')) ?>,
133                zoomOutTitle: <?= json_encode(I18N::translate('Zoom out')) ?>,
134                reset: <?= json_encode(I18N::translate('Reset to initial map state')) ?>,
135                noData: <?= json_encode(I18N::translate('No mappable items')) ?>,
136                error: <?= json_encode(I18N::translate('An unknown error occurred')) ?>
137            },
138        };
139
140        let map      = null;
141        let marker   = L.marker([0, 0], {
142            draggable: true,
143        });
144        /**
145         *
146         * @private
147         */
148        let _drawMap = function () {
149            map = L.map("osm-map", {
150                    center:      [0, 0],
151                    minZoom:     baseData.minZoom, // maxZoom set by leaflet-providers.js
152                    zoomControl: false, // remove default
153                },
154            );
155            L.tileLayer.provider(baseData.providerName, baseData.providerOptions).addTo(map);
156            L.control.zoom({ // Add zoom with localised text
157                zoomInTitle:  baseData.I18N.zoomInTitle,
158                zoomOutTitle: baseData.I18N.zoomOutTitle,
159            }).addTo(map);
160
161            // postcss_image_inliner breaks the autodetection of image paths.
162            L.Icon.Default.imagePath = <?= json_encode(asset('css/images/')) ?>;
163
164            marker
165                .on("dragend", function (e) {
166                    let coords = marker.getLatLng();
167                    map.panTo(coords);
168                    _update_Controls({
169                        place:  "",
170                        coords: coords,
171                        zoom:   map.getZoom(),
172                    });
173                })
174                .addTo(map);
175            let searchControl = new window.GeoSearch.GeoSearchControl({
176                provider:        new window.GeoSearch.OpenStreetMapProvider(),
177                retainZoomLevel: true,
178                autoClose:       true,
179                showMarker:      false,
180            });
181
182            map
183                .addControl(searchControl)
184                .on("geosearch/showlocation", function (result) {
185                    let lat   = result.location.y;
186                    let lng   = result.location.x;
187                    let place = result.location.label.split(",", 1);
188
189                    marker.setLatLng([lat, lng]);
190                    map.panTo([lat, lng]);
191
192                    _update_Controls({
193                        place:  place.shift(),
194                        coords: {
195                            "lat": lat,
196                            "lng": lng,
197                        },
198                        zoom:   map.getZoom(),
199                    });
200                })
201                .on("zoomend", function (e) {
202                    $("#new_zoom_factor").val(map.getZoom());
203                    map.panTo(marker.getLatLng());
204                });
205        };
206
207        let data = <?= json_encode($data) ?>;
208
209        /**
210         *
211         * @param newData
212         * @private
213         */
214        let _update_Controls = function (newData) {
215            let placeEl = $("#new_place_name");
216            if (!placeEl.val().length && newData.place.length) {
217                placeEl.val(newData.place);
218            }
219            $("#new_place_lati").val(Number(newData.coords.lat).toFixed(5)); // 5 decimal places (about 1 metre accuracy)
220            $("#new_place_long").val(Number(newData.coords.lng).toFixed(5));
221            $("#new_zoom_factor").val(Number(newData.zoom));
222        };
223
224        $(function () {
225            $(".editable").on("change", function (e) {
226                let lat = $("#new_place_lati").val();
227                let lng = $("#new_place_long").val();
228                marker.setLatLng([lat, lng]);
229                map.panTo([lat, lng]);
230            });
231        });
232
233        /**
234         *
235         * @param id
236         */
237        let initialize = function (id) {
238            _drawMap();
239
240            marker.setLatLng(data.coordinates);
241
242            if (data.coordinates[0] === 0 && data.coordinates[1] === 0) {
243                map.fitWorld();
244            } else {
245                map.setView(data.coordinates, data.zoom);
246            }
247        };
248
249        return {
250            /**
251             *
252             * @param id
253             */
254            drawMap: function (id) {
255                initialize(id);
256            },
257        };
258    })();
259
260    WT_OSM_ADMIN.drawMap(<?= json_encode($ref) ?>);
261</script>
262<?php View::endpush() ?>
263