Refactor the spatial query widget

Instead of expanding the sidebar map, open a new map in a modal window,
to make it easier to integrate with existing themes. Cleaned up the
code.

TODO:
* activate the draw control when opening the popup
* Boostrap 5 (CKAN 2.10)
This commit is contained in:
amercader 2022-12-14 15:50:08 +01:00
parent 734a1c7e4a
commit 917110f155
3 changed files with 194 additions and 145 deletions

View File

@ -1,5 +1,6 @@
.module-narrow #dataset-map-container {
height: 200px;
font-size: 14px;
}
.module-content #dataset-map-container {
height: 250px;
@ -47,46 +48,11 @@
.leaflet-draw-actions li {
display: none;
}
.dataset-map-expanded #dataset-map {
position: absolute;
width: 940px;
#draw-map-container {
width: 870px;
height: 384px;
top: -384px;
left: -1px;
background-color: white;
border: 1px solid #CCC;
margin: 0;
}
.dataset-map-expanded #dataset-map #dataset-map-container {
height: 300px;
}
.dataset-map-expanded #dataset-map #dataset-map-attribution {
*zoom: 1;
}
.dataset-map-expanded #dataset-map #dataset-map-attribution:before,
.dataset-map-expanded #dataset-map #dataset-map-attribution:after {
display: table;
content: "";
line-height: 0;
}
.dataset-map-expanded #dataset-map #dataset-map-attribution:after {
clear: both;
}
.dataset-map-expanded #dataset-map #dataset-map-attribution div {
float: left;
margin-right: 10px;
}
.dataset-map-expanded #dataset-map #dataset-map-edit-buttons {
display: block;
float: right;
padding: 10px;
}
.dataset-map-expanded #dataset-map #dataset-map-edit {
display: none;
}
.dataset-map-expanded #dataset-map .module-heading {
border-top-color: #000;
}
.dataset-map-expanded .wrapper {
margin-top: 383px;
}

View File

@ -22,7 +22,25 @@ this.ckan.module('spatial-query', function ($, _) {
'<a href="javascript:;" class="btn cancel">Cancel</a> ',
'<a href="javascript:;" class="btn apply disabled">Apply</a>',
'</div>'
].join('')
].join(''),
modal: [
'<div class="modal">',
'<div class="modal-dialog modal-lg">',
'<div class="modal-content">',
'<div class="modal-header">',
'<button type="button" class="close" data-dismiss="modal">×</button>',
'<h3 class="modal-title"></h3>',
'</div>',
'<div class="modal-body"><div id="draw-map-container"></div></div>',
'<div class="modal-footer">',
'<button class="btn btn-default btn-cancel" data-dismiss="modal"></button>',
'<button class="btn apply btn-primary disabled"></button>',
'</div>',
'</div>',
'</div>',
'</div>'
].join('\n')
},
initialize: function () {
@ -42,6 +60,80 @@ this.ckan.module('spatial-query', function ($, _) {
this.el.ready(this._onReady);
},
_createModal: function () {
if (!this.modal) {
var element = this.modal = jQuery(this.template.modal);
element.on('click', '.btn-primary', this._onApply);
element.on('click', '.btn-cancel', this._onCancel);
element.modal({show: false});
element.find('.modal-title').text(this._('Please draw the extent to query:'));
element.find('.btn-primary').text(this._('Apply'));
element.find('.btn-cancel').text(this._('Cancel'));
var module = this;
this.modal.on('shown.bs.modal', function () {
if (module.drawMap) {
module._setPreviousBBBox(map, zoom=false);
// TODO
$('a.leaflet-draw-draw-rectangle', element).trigger('click');
return
}
var container = element.find('#draw-map-container')[0];
module.drawMap = map = module._createMap(container);
// Initialize the draw control
var draw = new L.Control.Draw({
position: 'topright',
draw: {
polyline: false,
polygon: false,
circle: false,
circlemarker: false,
marker: false,
rectangle: {shapeOptions: module.options.style}
}
});
map.addControl(draw);
module._setPreviousBBBox(map, zoom=false);
map.fitBounds(module.mainMap.getBounds());
if (map.getZoom() == 0) {
map.zoomIn();
}
map.on('draw:created', function (e) {
if (module.extentLayer) {
map.removeLayer(module.extentLayer);
}
module.extentLayer = extentLayer = e.layer;
$('#ext_bbox').val(extentLayer.getBounds().toBBoxString());
map.addLayer(extentLayer);
element.find('.btn-primary').removeClass('disabled').addClass('btn-primary');
});
// Record the current map view so we can replicate it after submitting
map.on('moveend', function(e) {
$('#ext_prev_extent').val(map.getBounds().toBBoxString());
});
// TODO
$('a.leaflet-draw-draw-rectangle', element).trigger('click');
})
this.modal.on('hidden.bs.modal', function () {
module._onCancel()
});
}
return this.modal;
},
_getParameterByName: function (name) {
var match = RegExp('[?&]' + name + '=([^&]*)')
.exec(window.location.search);
@ -63,14 +155,60 @@ this.ckan.module('spatial-query', function ($, _) {
return new L.GeoJSON(geom, {style: this.options.style});
},
_onApply: function() {
$(".search-form").submit();
},
_onCancel: function() {
if (this.extentLayer) {
this.drawMap.removeLayer(this.extentLayer);
}
},
_createMap: function(container) {
map = ckan.commonLeafletMap(
container,
this.options.map_config,
{
attributionControl: false,
drawControlTooltips: false
}
);
return map;
},
// Is there an existing box from a previous search?
_setPreviousBBBox: function(map, zoom=true) {
previous_bbox = this._getParameterByName('ext_bbox');
if (previous_bbox) {
$('#ext_bbox').val(previous_bbox);
this.extentLayer = this._drawExtentFromCoords(previous_bbox.split(','))
map.addLayer(this.extentLayer);
if (zoom) {
map.fitBounds(this.extentLayer.getBounds());
}
}
},
// Is there an existing extent from a previous search?
_setPreviousExtent: function(map) {
previous_extent = this._getParameterByName('ext_prev_extent');
if (previous_extent) {
coords = previous_extent.split(',');
map.fitBounds([[coords[1], coords[0]], [coords[3], coords[2]]], {"animate": false});
} else {
if (!previous_bbox){
map.fitBounds(this.options.default_extent, {"animate": false});
}
}
},
_onReady: function() {
var module = this;
var map;
var extentLayer;
var previous_box;
var previous_extent;
var is_exanded = false;
var should_zoom = true;
var form = $("#dataset-search");
// CKAN 2.1
if (!form.length) {
@ -87,68 +225,31 @@ this.ckan.module('spatial-query', function ($, _) {
});
// OK map time
map = ckan.commonLeafletMap(
'dataset-map-container',
this.options.map_config,
{
attributionControl: false,
drawControlTooltips: false
}
);
// Initialize the draw control
map.addControl(new L.Control.Draw({
position: 'topright',
draw: {
polyline: false,
polygon: false,
circle: false,
circlemarker: false,
marker: false,
rectangle: {shapeOptions: module.options.style}
}
}));
this.mainMap = map = this._createMap('dataset-map-container');
// OK add the expander
$('a.leaflet-draw-draw-rectangle', module.el).on('click', function(e) {
if (!is_exanded) {
$('body').addClass('dataset-map-expanded');
if (should_zoom && !extentLayer) {
map.zoomIn();
}
resetMap();
is_exanded = true;
var module = this;
var expandButton = L.Control.extend({
position: 'topright',
onAdd: function(map) {
var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
var button = L.DomUtil.create('a', 'leaflet-control-custom-button', container);
button.innerHTML = '<i class="fa fa-pencil"></i>';
button.title = module._('Draw an extent');
L.DomEvent.on(button, 'click', function(e) {
module.sandbox.body.append(module._createModal());
module.modal.modal('show');
});
return container;
}
});
map.addControl(new expandButton());
// Setup the expanded buttons
buttons = $(module.template.buttons).insertBefore('#dataset-map-attribution');
// Handle the cancel expanded action
$('.cancel', buttons).on('click', function() {
$('body').removeClass('dataset-map-expanded');
if (extentLayer) {
map.removeLayer(extentLayer);
}
setPreviousExtent();
setPreviousBBBox();
resetMap();
is_exanded = false;
});
// Handle the apply expanded action
$('.apply', buttons).on('click', function() {
if (extentLayer) {
$('body').removeClass('dataset-map-expanded');
is_exanded = false;
resetMap();
// Eugh, hacky hack.
setTimeout(function() {
map.fitBounds(extentLayer.getBounds());
submitForm();
}, 200);
}
});
// When user finishes drawing the box, record it and add it to the map
map.on('draw:created', function (e) {
@ -166,52 +267,9 @@ this.ckan.module('spatial-query', function ($, _) {
$('#ext_prev_extent').val(map.getBounds().toBBoxString());
});
// Ok setup the default state for the map
var previous_bbox;
setPreviousBBBox();
setPreviousExtent();
module._setPreviousBBBox(map);
module._setPreviousExtent(map);
// OK, when we expand we shouldn't zoom then
map.on('zoomstart', function(e) {
should_zoom = false;
});
// Is there an existing box from a previous search?
function setPreviousBBBox() {
previous_bbox = module._getParameterByName('ext_bbox');
if (previous_bbox) {
$('#ext_bbox').val(previous_bbox);
extentLayer = module._drawExtentFromCoords(previous_bbox.split(','))
map.addLayer(extentLayer);
map.fitBounds(extentLayer.getBounds());
}
}
// Is there an existing extent from a previous search?
function setPreviousExtent() {
previous_extent = module._getParameterByName('ext_prev_extent');
if (previous_extent) {
coords = previous_extent.split(',');
map.fitBounds([[coords[1], coords[0]], [coords[3], coords[2]]]);
} else {
if (!previous_bbox){
map.fitBounds(module.options.default_extent);
}
}
}
// Reset map view
function resetMap() {
L.Util.requestAnimFrame(map.invalidateSize, map, !1, map._container);
}
// Add the loading class and submit the form
function submitForm() {
setTimeout(function() {
form.submit();
}, 800);
}
}
}
});

View File

@ -11,6 +11,31 @@ e.g.
{% snippet "spatial/snippets/spatial_query.html", default_extent="{ \"type\": \"Polygon\", \"coordinates\": [[[74.89, 29.39],[74.89, 38.45], [60.50, 38.45], [60.50, 29.39], [74.89, 29.39]]]}" %}
#}
<!--
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
HOLA
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
Modal -->
<section id="dataset-map" class="module module-narrow module-shallow">
<h2 class="module-heading">
<i class="icon-medium icon-globe"></i>