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