misc: use a popup to display markers at same position (#76894) #260
|
@ -13,7 +13,7 @@ from unittest import mock
|
|||
import pytest
|
||||
import responses
|
||||
from django.utils.encoding import force_bytes, force_str
|
||||
from webtest import Hidden, Radio, Upload
|
||||
from webtest import Hidden, Upload
|
||||
|
||||
from wcs import fields
|
||||
from wcs.admin.settings import UserFieldsFormDef
|
||||
|
@ -9577,19 +9577,21 @@ def test_form_item_map_data_source(pub, http_requests):
|
|||
resp_geojson = app.get('/api/geojson/foobar')
|
||||
assert http_requests.count() == 1 # cache was used
|
||||
assert len(resp_geojson.json['features']) == 2
|
||||
# simulate qommon.map.js that will create radio inputs
|
||||
resp.form.fields['f1$marker_id'] = [Radio(form=resp.form, tag='input', name='f1$marker_id', pos=5)]
|
||||
resp.form.fields['f1$marker_id'][0].options.append(('1', False, None))
|
||||
resp.form.fields['f1$marker_id'][0].options.append(('2', False, None))
|
||||
resp.form.fields['f1$marker_id'][0].optionPositions.append(5)
|
||||
resp.form.fields['f1$marker_id'][0].optionPositions.append(6)
|
||||
resp.form.field_order.append(('f1$marker_id', resp.form.fields['f1$marker_id'][0]))
|
||||
# simulate qommon.map.js that will fill the hidden inputs
|
||||
resp.form['f1$marker_id'].value = '1' # click on marker
|
||||
resp.form['f1$latlng'] = '1;2' # set via js
|
||||
resp = resp.form.submit('submit')
|
||||
assert 'Check values then click submit.' in resp
|
||||
# selected option is displayed as readonly:
|
||||
assert resp.pyquery('input[type=text][value=foo][readonly]')
|
||||
|
||||
# check going back keeps item selected
|
||||
resp = resp.form.submit('previous')
|
||||
assert resp.pyquery('.qommon-map').attr('data-markers-initial-id') == '1'
|
||||
resp.form['f1$marker_id'].value = '1' # click on marker
|
||||
resp.form['f1$latlng'] = '1;2' # set via js
|
||||
resp = resp.form.submit('submit') # to validation page again
|
||||
|
||||
resp = resp.form.submit('submit')
|
||||
resp = resp.follow()
|
||||
assert 'The form has been recorded' in resp
|
||||
|
|
|
@ -3442,6 +3442,7 @@ class MapMarkerSelectionWidget(MapWidget):
|
|||
def __init__(self, name, value=None, **kwargs):
|
||||
CompositeWidget.__init__(self, name, value, **kwargs)
|
||||
self.add(HiddenWidget, 'marker_id', value=value)
|
||||
self.marker_id_widget = self.get_widget('marker_id')
|
||||
self.readonly = kwargs.pop('readonly', False)
|
||||
|
||||
self.init_map_attributes(value, **kwargs)
|
||||
|
@ -3459,7 +3460,8 @@ class MapMarkerSelectionWidget(MapWidget):
|
|||
self.value = self.get('marker_id')
|
||||
|
||||
def set_value(self, value):
|
||||
CompositeWidget.set_value(self, value)
|
||||
self.value = value
|
||||
self.marker_id_widget.set_value(value)
|
||||
|
||||
|
||||
class HiddenErrorWidget(HiddenWidget):
|
||||
|
|
|
@ -73,11 +73,21 @@ $(window).on('wcs:maps-init', function() {
|
|||
}
|
||||
if ($map_widget.data('markers-url')) {
|
||||
var radio_name = $map_widget.data('markers-radio-name');
|
||||
$map_widget.on('change', 'input[name="' + radio_name + '"]', function() {
|
||||
var markers_by_position = new Object();
|
||||
var hidden_marker_id = $('input[type=hidden][name="' + radio_name + '"]');
|
||||
|
||||
function turn_marker_on(marker_id, lat, lng, position_key) {
|
||||
hidden.val(lat + ';' + lng);
|
||||
hidden_marker_id.val(marker_id);
|
||||
hidden.trigger('change');
|
||||
$map_widget.find('.marker-icon[data-position-key]').removeClass('marker-icon-on');
|
||||
$map_widget.find('.marker-icon[data-position-key="' + position_key + '"]').addClass('marker-icon-on');
|
||||
}
|
||||
|
||||
$map_widget.on('change', 'input.marker-selector', function(ev) {
|
||||
var $radio = $(this);
|
||||
if ($radio.is(':checked')) {
|
||||
hidden.val($radio.data('lat') + ';' + $radio.data('lng'));
|
||||
hidden.trigger('change');
|
||||
turn_marker_on($radio.val(), $radio.data('lat'), $radio.data('lng'), $radio.data('parent-position-key'));
|
||||
}
|
||||
});
|
||||
$.getJSON($map_widget.data('markers-url')).done(
|
||||
|
@ -86,28 +96,70 @@ $(window).on('wcs:maps-init', function() {
|
|||
var checked_lng = null;
|
||||
var geo_json = L.geoJson(data, {
|
||||
pointToLayer: function (feature, latlng) {
|
||||
var $label = $('<label>', {
|
||||
title: feature.properties._text
|
||||
});
|
||||
var $radio = $('<input>', {
|
||||
value: feature.properties._id,
|
||||
name: radio_name,
|
||||
type: 'radio',
|
||||
'data-lat': latlng.lat,
|
||||
'data-lng': latlng.lng
|
||||
});
|
||||
if (typeof initial_marker_id !== 'undefined' && feature.properties._id == initial_marker_id) {
|
||||
checked_lat = latlng.lat;
|
||||
checked_lng = latlng.lng;
|
||||
$radio.attr('checked', 'checked');
|
||||
var position_key = latlng.lat.toFixed(6) + ';' + latlng.lng.toFixed(6);
|
||||
var marker = markers_by_position[position_key];
|
||||
var marker_on = (typeof initial_marker_id !== 'undefined' && feature.properties._id == initial_marker_id);
|
||||
if (typeof marker === 'undefined') {
|
||||
var $div_content = $('<div></div>', {
|
||||
title: feature.properties._text,
|
||||
'data-marker-id': feature.properties._id,
|
||||
'data-lat': latlng.lat,
|
||||
'data-lng': latlng.lng
|
||||
});
|
||||
var $marker_icon = $('<span></span>', {
|
||||
'class': 'marker-icon',
|
||||
'data-marker-id': feature.properties._id,
|
||||
'data-position-key': position_key
|
||||
});
|
||||
if (marker_on) {
|
||||
$marker_icon.addClass('marker-icon-on');
|
||||
}
|
||||
$marker_icon.appendTo($div_content);
|
||||
div_marker = L.divIcon({
|
||||
className: 'item-marker',
|
||||
html: $div_content.prop('outerHTML'),
|
||||
iconSize: [25, 41]
|
||||
});
|
||||
marker = L.marker(latlng, {icon: div_marker});
|
||||
|
||||
// keep a list of all features at the same location
|
||||
marker.radio_array = Array();
|
||||
marker.radio_array.push({id: feature.properties._id, text: feature.properties._text});
|
||||
markers_by_position[position_key] = marker;
|
||||
|
||||
// add a popup with feature text
|
||||
var popup = L.popup().setContent($('<div></div>', {text: feature.properties._text}).prop('outerHTML'));
|
||||
popup.marker = {id: feature.properties._id, lat: latlng.lat, lng: latlng.lng, position_key: position_key};
|
||||
marker.bindPopup(popup, {offset: [0, -20]});
|
||||
return marker;
|
||||
} else {
|
||||
marker.radio_array.push({id: feature.properties._id, text: feature.properties._text});
|
||||
var $ul_radios = $('<ul class="multi-marker-selection"></ul>');
|
||||
$(marker.radio_array).each(function(i, feature_data) {
|
||||
var $radio = $('<input>', {
|
||||
value: feature_data.id,
|
||||
name: 'radio-' + radio_name,
|
||||
'class': 'marker-selector',
|
||||
type: 'radio',
|
||||
'data-lat': latlng.lat,
|
||||
'data-lng': latlng.lng,
|
||||
'data-parent-position-key': position_key
|
||||
});
|
||||
var $label = $('<label></label>');
|
||||
$label.append($radio);
|
||||
$label.append(feature_data.text);
|
||||
var $li = $('<li></li>');
|
||||
$label.appendTo($li);
|
||||
$li.appendTo($ul_radios);
|
||||
});
|
||||
marker.unbindPopup().bindPopup($ul_radios.prop('outerHTML'), {offset: [0, -20]});
|
||||
if (marker_on) {
|
||||
var marker_icon = marker.getIcon();
|
||||
var marker_html = $(marker_icon.options.html);
|
||||
marker_html.find('.marker-icon').addClass('marker-icon-on');
|
||||
marker_icon.options.html = marker_html.prop('outerHTML');
|
||||
}
|
||||
}
|
||||
$label.append($radio);
|
||||
$label.append($('<span></span>'));
|
||||
var div_marker = L.divIcon({
|
||||
className: 'item-marker',
|
||||
html: '<div>' + $label.prop('outerHTML') + '</div>'
|
||||
});
|
||||
return L.marker(latlng, {icon: div_marker});
|
||||
}
|
||||
});
|
||||
if (checked_lat !== null) {
|
||||
|
@ -119,6 +171,19 @@ $(window).on('wcs:maps-init', function() {
|
|||
map.fitBounds(geo_json.getBounds());
|
||||
}
|
||||
geo_json.addTo(map);
|
||||
|
||||
map.on('popupopen', function(e) {
|
||||
var popup = e.popup;
|
||||
if (popup.marker) {
|
||||
// if popup is bound to a single marker, turn this on
|
||||
turn_marker_on(popup.marker.id, popup.marker.lat, popup.marker.lng, popup.marker.position_key);
|
||||
} else {
|
||||
// turn radio on
|
||||
var current_value = hidden_marker_id.val();
|
||||
$('input[type=radio][name="radio-' + radio_name + '"][value="' + current_value + '"]').prop('checked', true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
} else if ($map_widget.data('readonly') && initial_marker_id) {
|
||||
|
|
|
@ -11,20 +11,19 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block widget-control %}
|
||||
<input type="hidden" name="{{widget.name}}$marker_id" {% if widget.value %}value="{{widget.value}}"{% endif %}>
|
||||
{{ block.super }}
|
||||
|
||||
<style>
|
||||
.item-marker input + span {
|
||||
.item-marker span.marker-icon {
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
margin-top: -55px;
|
||||
margin-left: -5px;
|
||||
display: block;
|
||||
width: 25px;
|
||||
height: 41px;
|
||||
background: url(/static/images/blank-marker-icon.png);
|
||||
}
|
||||
.item-marker input:checked + span {
|
||||
.item-marker span.marker-icon.marker-icon-on {
|
||||
background: url(/static/xstatic/images/marker-icon.png);
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue