starts with the title of the item
- link.text(marker.options.title);
-
- // Clicking the link should take us to the map
- link.bind('click', {}, function (event) {
- link.toggleClass('current');
-
- if (that.clusterGroup) {
- that.clusterGroup.zoomToShowLayer(marker, function () {
- marker.fire('click');
- });
+ // this.locations holds points and shapes in load order, so the list
+ // interleaves them as they were added rather than grouping by type.
+ jQuery.each(this.locations, function (index, layer) {
+ that._buildListItem(list, layer._geolocationTitle, function () {
+ if (layer instanceof L.Marker) {
+ if (that.clusterGroup) {
+ that.clusterGroup.zoomToShowLayer(layer, function () {
+ layer.fire('click');
+ });
+ } else {
+ that.map.once('moveend', function () {
+ layer.fire('click');
+ });
+ that.map.flyTo(layer.getLatLng());
+ }
} else {
that.map.once('moveend', function () {
- marker.fire('click');
+ layer.openPopup();
});
- that.map.flyTo(marker.getLatLng());
+ that.map.fitBounds(layer.getBounds());
}
});
+ });
+ },
- link.appendTo(listElement);
- listElement.appendTo(list);
+ _buildListItem: function (list, title, onClick) {
+ var link = jQuery('')
+ .addClass('item-link')
+ .attr('href', 'javascript:void(0);')
+ .attr('role', 'button')
+ .text(title);
+ link.bind('click', {}, function () {
+ link.toggleClass('current');
+ onClick();
});
+ jQuery('
').append(link).appendTo(list);
}
};
@@ -245,12 +283,12 @@ function OmekaMapSingle(mapDivId, center, options) {
var omekaMap = new OmekaMap(mapDivId, center, options);
jQuery.extend(true, this, omekaMap);
this.initMap();
- if (options.points && options.points.length) {
- for (var i = 0; i < options.points.length; i++) {
- var pt = options.points[i];
- this.addMarker([pt.latitude, pt.longitude], {title: pt.label, alt: pt.label}, pt.markerHtml);
+ if (options.locations && options.locations.length) {
+ for (var i = 0; i < options.locations.length; i++) {
+ var pt = options.locations[i];
+ this.addLayerFromGeometry(JSON.parse(pt.geometry_json), {title: pt.label, alt: pt.label}, pt.popupHtml);
}
- this.fitMarkers();
+ this.fitLocations();
}
}
@@ -266,13 +304,18 @@ function OmekaMapForm(mapDivId, center, options) {
this.drawnItems = new L.FeatureGroup();
this.map.addLayer(this.drawnItems);
+ L.drawLocal.edit.toolbar.buttons.edit = options.strings.editLocations;
+ L.drawLocal.edit.toolbar.buttons.editDisabled = options.strings.noLocationsToEdit;
+ L.drawLocal.edit.toolbar.buttons.remove = options.strings.deleteLocations;
+ L.drawLocal.edit.toolbar.buttons.removeDisabled = options.strings.noLocationsToDelete;
+
var drawControl = new L.Control.Draw({
position: 'topleft',
draw: {
marker: true,
- polyline: false,
- polygon: false,
- rectangle: false,
+ polyline: true,
+ polygon: true,
+ rectangle: true,
circle: false,
circlemarker: false,
},
@@ -285,16 +328,24 @@ function OmekaMapForm(mapDivId, center, options) {
this.map.addControl(drawControl);
this.map.on(L.Draw.Event.CREATED, function (event) {
- var latlng = event.layer.getLatLng();
- var marker = that.addLocation(latlng.lat, latlng.lng, that.map.getZoom(), null, '', '');
- marker.openPopup();
+ var isMarker = event.layerType === 'marker';
+ var layer = that.addLocation({
+ geometry_json: JSON.stringify(event.layer.toGeoJSON().geometry),
+ zoom_level: isMarker ? that.map.getZoom() : 0
+ });
+ if (isMarker) {
+ layer.openPopup();
+ }
});
this.map.on(L.Draw.Event.EDITED, function (event) {
event.layers.eachLayer(function (layer) {
- var latlng = layer.getLatLng();
- layer._locationData.latitude = latlng.lat;
- layer._locationData.longitude = latlng.lng;
+ layer._locationData.geometry_json = JSON.stringify(layer.toGeoJSON().geometry);
+ if (layer instanceof L.Marker) {
+ var latlng = layer.getLatLng();
+ layer._locationData.latitude = latlng.lat;
+ layer._locationData.longitude = latlng.lng;
+ }
});
});
@@ -316,25 +367,51 @@ function OmekaMapForm(mapDivId, center, options) {
OmekaMapForm.prototype = {
- addLocation: function (lat, lng, zoom, id, address, label) {
- var marker = L.marker([lat, lng]);
- this.drawnItems.addLayer(marker);
- this.markers.push(marker);
- this.markerBounds.extend([lat, lng]);
+ // Adds an editable layer (point marker or shape) from a location object and
+ // records its _locationData for form submission. locationData needs only a
+ // geometry_json string; id/zoom_level/address/label default sensibly.
+ addLocation: function (locationData) {
+ var geometry = JSON.parse(locationData.geometry_json);
+ var layer = L.GeoJSON.geometryToLayer(geometry);
+ this.drawnItems.addLayer(layer);
+ this.locations.push(layer);
+
+ // A point is represented by its own position; a shape by its bounding
+ // box, with the box center standing in as its point (matching how
+ // Location::beforeSave derives lat/lng server-side). `extent` is the
+ // shape we grow the map's overall bounds by.
+ var center, extent;
+ if (geometry.type === 'Point') {
+ extent = center = layer.getLatLng();
+ } else {
+ extent = layer.getBounds();
+ center = extent.getCenter();
+ }
+ this.locationBounds.extend(extent);
- marker._locationData = {id: id, latitude: lat, longitude: lng, zoom_level: zoom, address: address, label: label};
+ layer._locationData = {
+ id: locationData.id || null,
+ latitude: center.lat,
+ longitude: center.lng,
+ zoom_level: locationData.zoom_level || 0,
+ address: locationData.address || '',
+ label: locationData.label || '',
+ geometry_json: locationData.geometry_json
+ };
- var labelInput = jQuery('').val(label);
- var popupContent = jQuery('')
- .append(jQuery('').text(this.options.strings.label + ': ').append(labelInput));
+ this._bindLabelPopup(layer, layer._locationData.label);
- marker.bindPopup(popupContent[0], {autoPanPadding: [50, 50]});
+ return layer;
+ },
+ _bindLabelPopup: function (layer, initialLabel) {
+ var labelInput = jQuery('').val(initialLabel);
+ var popupContent = jQuery('')
+ .append(jQuery('').text(this.options.strings.label + ': ').append(labelInput));
+ layer.bindPopup(popupContent[0], {autoPanPadding: [50, 50]});
labelInput.on('input', function () {
- marker._locationData.label = jQuery(this).val();
+ layer._locationData.label = jQuery(this).val();
});
-
- return marker;
},
getLocationCount: function () {
diff --git a/views/shared/map/browse-json.php b/views/shared/map/browse-json.php
index 174a43c..394fd9c 100644
--- a/views/shared/map/browse-json.php
+++ b/views/shared/map/browse-json.php
@@ -2,12 +2,11 @@
$output = [];
foreach (loop('item') as $item):
$itemLocations = $locations[$item->id] ?? [];
- $rawTitle = metadata($item, 'display_title', ['no_escape' => true]);
+ $title = metadata($item, 'display_title', ['no_escape' => true]);
$thumbnailUrl = metadata($item, 'has thumbnail') ? record_image_url($item, 'thumbnail') : '';
$snippet = (string) metadata($item, ['Dublin Core', 'Description'], ['snippet' => 150]);
$itemUrl = record_url($item, 'show', true);
foreach ($itemLocations as $location):
- $displayTitle = $location->label ? "$rawTitle — {$location->label}" : $rawTitle;
$output[] = [
'id' => (int) $location->id,
'latitude' => (float) $location->latitude,
@@ -15,7 +14,8 @@
'zoom_level' => (int) $location->zoom_level,
'address' => $location->address,
'label' => $location->label,
- 'title' => $displayTitle,
+ 'geometry_json' => $location->geometry_json,
+ 'title' => $title,
'thumbnailUrl' => $thumbnailUrl,
'snippet' => $snippet,
'itemId' => (int) $item->id,
diff --git a/views/shared/map/input-partial.php b/views/shared/map/input-partial.php
index b745b30..6dca998 100644
--- a/views/shared/map/input-partial.php
+++ b/views/shared/map/input-partial.php
@@ -25,7 +25,7 @@