Merge pull request #1478 from umap-project/preview-map-on-click
Preview map only on click in user’s dashboard
This commit is contained in:
commit
ab82fd975f
11 changed files with 198 additions and 88 deletions
|
@ -11,6 +11,7 @@ from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .managers import PublicManager
|
from .managers import PublicManager
|
||||||
|
from .utils import _urls_for_js
|
||||||
|
|
||||||
|
|
||||||
# Did not find a clean way to do this in Django
|
# Did not find a clean way to do this in Django
|
||||||
|
@ -193,6 +194,34 @@ class Map(NamedModel):
|
||||||
objects = models.Manager()
|
objects = models.Manager()
|
||||||
public = PublicManager()
|
public = PublicManager()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def preview_settings(self):
|
||||||
|
layers = self.datalayer_set.all()
|
||||||
|
datalayer_data = [c.metadata() for c in layers]
|
||||||
|
map_settings = self.settings
|
||||||
|
if "properties" not in map_settings:
|
||||||
|
map_settings["properties"] = {}
|
||||||
|
map_settings["properties"].update(
|
||||||
|
{
|
||||||
|
"tilelayers": [TileLayer.get_default().json],
|
||||||
|
"datalayers": datalayer_data,
|
||||||
|
"urls": _urls_for_js(),
|
||||||
|
"STATIC_URL": settings.STATIC_URL,
|
||||||
|
"editMode": "disabled",
|
||||||
|
"hash": False,
|
||||||
|
"attributionControl": False,
|
||||||
|
"scrollWheelZoom": False,
|
||||||
|
"umapAttributionControl": False,
|
||||||
|
"noControl": True,
|
||||||
|
"umap_id": self.pk,
|
||||||
|
"onLoadPanel": "none",
|
||||||
|
"captionBar": False,
|
||||||
|
"default_iconUrl": "%sumap/img/marker.png" % settings.STATIC_URL,
|
||||||
|
"slideshow": {},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return map_settings
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("map", kwargs={"slug": self.slug or "map", "map_id": self.pk})
|
return reverse("map", kwargs={"slug": self.slug or "map", "map_id": self.pk})
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,9 @@ h2.section {
|
||||||
padding-top: 28px;
|
padding-top: 28px;
|
||||||
}
|
}
|
||||||
h2.tabs a {
|
h2.tabs a {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
h2.tabs a:not(.selected) {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
@ -296,9 +299,9 @@ table.maps {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
table.maps .map_fragment {
|
table.maps .map_fragment {
|
||||||
height: 100px;
|
display: block;
|
||||||
|
height: 80vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 200px;
|
|
||||||
}
|
}
|
||||||
table.maps tbody tr:nth-child(odd) {
|
table.maps tbody tr:nth-child(odd) {
|
||||||
background-color: #f4f4f4;
|
background-color: #f4f4f4;
|
||||||
|
@ -309,6 +312,42 @@ table.maps td {
|
||||||
table.maps thead tr {
|
table.maps thead tr {
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
}
|
}
|
||||||
|
table.maps .button {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
padding:4px 6px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************** */
|
||||||
|
/* Dialog */
|
||||||
|
/* **************************** */
|
||||||
|
dialog {
|
||||||
|
width: 90vw;
|
||||||
|
height: 90vh;
|
||||||
|
}
|
||||||
|
dialog::backdrop {
|
||||||
|
background: #fff5;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
.close-dialog {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ********************************* */
|
||||||
|
/* Pagination */
|
||||||
|
/* ********************************* */
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin: 1rem;
|
||||||
|
border-top: 1px solid gray;
|
||||||
|
}
|
||||||
|
.pagination > * {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ************************************************* */
|
/* ************************************************* */
|
||||||
|
|
|
@ -64,8 +64,10 @@ L.U.UI = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
closePanel: function () {
|
closePanel: function () {
|
||||||
|
if (L.DomUtil.hasClass(this.parent, 'umap-ui')) {
|
||||||
L.DomUtil.removeClass(this.parent, 'umap-ui')
|
L.DomUtil.removeClass(this.parent, 'umap-ui')
|
||||||
this.fire('panel:closed')
|
this.fire('panel:closed')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
alert: function (e) {
|
alert: function (e) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
<div class="col wide">
|
<div class="col wide">
|
||||||
<h2 class="section tabs">
|
<h2 class="section tabs">
|
||||||
<a href="{% url "user_dashboard" %}">{% trans "My Dashboard" %}</a> | {% trans "My Profile" %}
|
<a href="{% url "user_dashboard" %}">{% trans "My Dashboard" %}</a> | <a class="selected" href="{% url 'user_profile' %}">{% trans "My Profile" %}</a>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
const container = this.parentNode
|
const container = this.parentNode
|
||||||
container.innerHTML = data
|
container.innerHTML = data
|
||||||
Array.prototype.forEach.call(
|
Array.prototype.forEach.call(
|
||||||
container.querySelectorAll('script'),
|
container.querySelectorAll('script:not([type="application/json"])'),
|
||||||
function (item) {
|
function (item) {
|
||||||
eval(item.firstChild.textContent)
|
eval(item.firstChild.textContent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load umap_tags umap_tags i18n %}
|
{% load umap_tags i18n %}
|
||||||
{% for map_inst in maps %}
|
{% for map_inst in maps %}
|
||||||
<hr />
|
<hr />
|
||||||
<div class="col wide">
|
<div class="col wide">
|
||||||
|
|
|
@ -1,24 +1,34 @@
|
||||||
{% load umap_tags umap_tags i18n %}
|
{% load umap_tags i18n %}
|
||||||
<table class="maps">
|
<table class="maps">
|
||||||
{% if not is_ajax %}
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% blocktrans %}Map{% endblocktrans %}</th>
|
|
||||||
<th>{% blocktrans %}Name{% endblocktrans %}</th>
|
<th>{% blocktrans %}Name{% endblocktrans %}</th>
|
||||||
|
<th>{% blocktrans %}Preview{% endblocktrans %}</th>
|
||||||
<th>{% blocktrans %}Who can see / edit{% endblocktrans %}</th>
|
<th>{% blocktrans %}Who can see / edit{% endblocktrans %}</th>
|
||||||
<th>{% blocktrans %}Last save{% endblocktrans %}</th>
|
<th>{% blocktrans %}Last save{% endblocktrans %}</th>
|
||||||
<th>{% blocktrans %}Owner{% endblocktrans %}</th>
|
<th>{% blocktrans %}Owner{% endblocktrans %}</th>
|
||||||
<th>{% blocktrans %}Actions{% endblocktrans %}</th>
|
<th>{% blocktrans %}Actions{% endblocktrans %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
{% endif %}
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for map_inst in maps %}
|
{% for map_inst in maps %}
|
||||||
|
{% with unique_id="map_"|addstr:map_inst.pk %}
|
||||||
|
{{ map_inst.preview_settings|json_script:unique_id }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% map_fragment map_inst prefix=prefix page=request.GET.p %}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ map_inst.get_absolute_url }}">{{ map_inst.name }}</a>
|
<a href="{{ map_inst.get_absolute_url }}">{{ map_inst.name }}</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="button map-opener neutral" data-map-id="{{ unique_id }}">{% blocktranslate %}Open preview{% endblocktranslate %}</button>
|
||||||
|
<dialog>
|
||||||
|
<form method="dialog">
|
||||||
|
<div id="{{ unique_id }}_target" class="map_fragment"></div>
|
||||||
|
<p class="close-dialog">
|
||||||
|
<button class="button" type="submit">Close</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
</td>
|
||||||
<td>{{ map_inst.get_share_status_display }} / {{ map_inst.get_edit_status_display }}</td>
|
<td>{{ map_inst.get_share_status_display }} / {{ map_inst.get_edit_status_display }}</td>
|
||||||
<td>{{ map_inst.modified_at }}</td>
|
<td>{{ map_inst.modified_at }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -30,12 +40,34 @@
|
||||||
<a href="{% url 'map_download' map_inst.pk %}">{% translate "Download" %}</a>
|
<a href="{% url 'map_download' map_inst.pk %}">{% translate "Download" %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endwith %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% if maps.has_next %}
|
<div class="pagination">
|
||||||
<div class="col wide">
|
{% if maps.has_previous %}
|
||||||
<a href="?{% paginate_querystring maps.next_page_number %}"
|
<a href="?p=1{% if q %}&q={{ q }}{% endif %}">« {% translate "first" %}</a>
|
||||||
class="button more_button neutral">{% trans "More" %}</a>
|
<a href="?p={{ maps.previous_page_number }}{% if q %}&q={{ q }}{% endif %}">‹ {% translate "previous" %}</a>
|
||||||
</div>
|
{% else %}
|
||||||
|
{# djlint:off #}
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
{# djlint:on #}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<span class="current">
|
||||||
|
{% blocktranslate with maps_number=maps.number num_pages=maps.paginator.num_pages %}
|
||||||
|
Page {{ maps_number }} of {{ num_pages }}
|
||||||
|
{% endblocktranslate %}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if maps.has_next %}
|
||||||
|
<a href="?p={{ maps.next_page_number }}{% if q %}&q={{ q }}{% endif %}">{% translate "next" %} ›</a>
|
||||||
|
<a href="?p={{ maps.paginator.num_pages }}{% if q %}&q={{ q }}{% endif %}">{% translate "last" %} »</a>
|
||||||
|
{% else %}
|
||||||
|
{# djlint:off #}
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
{# djlint:on #}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{% trans "Search my maps" as placeholder %}
|
{% trans "Search my maps" as placeholder %}
|
||||||
<div class="col wide">
|
<div class="col wide">
|
||||||
<h2 class="section tabs">
|
<h2 class="section tabs">
|
||||||
{% trans "My Dashboard" %} | <a href="{% url 'user_profile' %}">{% trans "My profile" %}</a>
|
<a class="selected" href="{% url 'user_dashboard' %}">{% trans "My Dashboard" %}</a> | <a href="{% url 'user_profile' %}">{% trans "My profile" %}</a>
|
||||||
</h2>
|
</h2>
|
||||||
{% include "umap/search_bar.html" with action=request.get_full_path placeholder=placeholder %}
|
{% include "umap/search_bar.html" with action=request.get_full_path placeholder=placeholder %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,3 +23,25 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock maincontent %}
|
{% endblock maincontent %}
|
||||||
|
|
||||||
|
{% block bottom_js %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script type="text/javascript">
|
||||||
|
!(function () {
|
||||||
|
const CACHE = {}
|
||||||
|
for (const mapOpener of document.querySelectorAll("button.map-opener")) {
|
||||||
|
mapOpener.addEventListener('click', (event) => {
|
||||||
|
event.target.nextElementSibling.showModal()
|
||||||
|
const mapId = event.target.dataset.mapId
|
||||||
|
if (!document.querySelector(`#${mapId}_target`).hasChildNodes()) {
|
||||||
|
const previewSettings = JSON.parse(document.getElementById(mapId).textContent)
|
||||||
|
const map = new L.U.Map(`${mapId}_target`, previewSettings)
|
||||||
|
CACHE[mapId] = map
|
||||||
|
} else {
|
||||||
|
CACHE[mapId].invalidateSize()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
</script>
|
||||||
|
{% endblock bottom_js %}
|
||||||
|
|
|
@ -4,9 +4,6 @@ from copy import copy
|
||||||
from django import template
|
from django import template
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ..models import DataLayer, TileLayer
|
|
||||||
from ..views import _urls_for_js
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,30 +19,7 @@ def umap_js(locale=None):
|
||||||
|
|
||||||
@register.inclusion_tag("umap/map_fragment.html")
|
@register.inclusion_tag("umap/map_fragment.html")
|
||||||
def map_fragment(map_instance, **kwargs):
|
def map_fragment(map_instance, **kwargs):
|
||||||
layers = DataLayer.objects.filter(map=map_instance)
|
map_settings = map_instance.preview_settings
|
||||||
datalayer_data = [c.metadata() for c in layers]
|
|
||||||
map_settings = map_instance.settings
|
|
||||||
if "properties" not in map_settings:
|
|
||||||
map_settings["properties"] = {}
|
|
||||||
map_settings["properties"].update(
|
|
||||||
{
|
|
||||||
"tilelayers": [TileLayer.get_default().json],
|
|
||||||
"datalayers": datalayer_data,
|
|
||||||
"urls": _urls_for_js(),
|
|
||||||
"STATIC_URL": settings.STATIC_URL,
|
|
||||||
"editMode": "disabled",
|
|
||||||
"hash": False,
|
|
||||||
"attributionControl": False,
|
|
||||||
"scrollWheelZoom": False,
|
|
||||||
"umapAttributionControl": False,
|
|
||||||
"noControl": True,
|
|
||||||
"umap_id": map_instance.pk,
|
|
||||||
"onLoadPanel": "none",
|
|
||||||
"captionBar": False,
|
|
||||||
"default_iconUrl": "%sumap/img/marker.png" % settings.STATIC_URL,
|
|
||||||
"slideshow": {},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
map_settings["properties"].update(kwargs)
|
map_settings["properties"].update(kwargs)
|
||||||
prefix = kwargs.pop("prefix", None) or "map"
|
prefix = kwargs.pop("prefix", None) or "map"
|
||||||
page = kwargs.pop("page", None) or ""
|
page = kwargs.pop("page", None) or ""
|
||||||
|
@ -86,3 +60,9 @@ def ipdb(what):
|
||||||
|
|
||||||
ipdb.set_trace()
|
ipdb.set_trace()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def addstr(arg1, arg2):
|
||||||
|
# Necessity: https://stackoverflow.com/a/23783666
|
||||||
|
return str(arg1) + str(arg2)
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
import gzip
|
import gzip
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.urls import URLPattern, URLResolver, get_resolver
|
from django.urls import URLPattern, URLResolver, get_resolver
|
||||||
|
|
||||||
|
|
||||||
|
def _urls_for_js(urls=None):
|
||||||
|
"""
|
||||||
|
Return templated URLs prepared for javascript.
|
||||||
|
"""
|
||||||
|
if urls is None:
|
||||||
|
# prevent circular import
|
||||||
|
from .urls import i18n_urls, urlpatterns
|
||||||
|
|
||||||
|
urls = [
|
||||||
|
url.name for url in urlpatterns + i18n_urls if getattr(url, "name", None)
|
||||||
|
]
|
||||||
|
urls = dict(zip(urls, [get_uri_template(url) for url in urls]))
|
||||||
|
urls.update(getattr(settings, "UMAP_EXTRA_URLS", {}))
|
||||||
|
return urls
|
||||||
|
|
||||||
|
|
||||||
def get_uri_template(urlname, args=None, prefix=""):
|
def get_uri_template(urlname, args=None, prefix=""):
|
||||||
"""
|
"""
|
||||||
Utility function to return an URI Template from a named URL in django
|
Utility function to return an URI Template from a named URL in django
|
||||||
|
|
|
@ -62,7 +62,7 @@ from .forms import (
|
||||||
UserProfileForm,
|
UserProfileForm,
|
||||||
)
|
)
|
||||||
from .models import DataLayer, Licence, Map, Pictogram, Star, TileLayer
|
from .models import DataLayer, Licence, Map, Pictogram, Star, TileLayer
|
||||||
from .utils import ConflictError, get_uri_template, gzip_file, is_ajax, merge_features
|
from .utils import ConflictError, _urls_for_js, gzip_file, is_ajax, merge_features
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
@ -270,7 +270,12 @@ class UserDashboard(PaginatorMixin, DetailView, SearchMixin):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs.update(
|
kwargs.update(
|
||||||
{"maps": self.paginate(self.get_maps(), settings.UMAP_MAPS_PER_PAGE_OWNER)}
|
{
|
||||||
|
"q": self.request.GET.get("q"),
|
||||||
|
"maps": self.paginate(
|
||||||
|
self.get_maps(), settings.UMAP_MAPS_PER_PAGE_OWNER
|
||||||
|
),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
@ -390,22 +395,6 @@ ajax_proxy = AjaxProxy.as_view()
|
||||||
# ############## #
|
# ############## #
|
||||||
|
|
||||||
|
|
||||||
def _urls_for_js(urls=None):
|
|
||||||
"""
|
|
||||||
Return templated URLs prepared for javascript.
|
|
||||||
"""
|
|
||||||
if urls is None:
|
|
||||||
# prevent circular import
|
|
||||||
from .urls import i18n_urls, urlpatterns
|
|
||||||
|
|
||||||
urls = [
|
|
||||||
url.name for url in urlpatterns + i18n_urls if getattr(url, "name", None)
|
|
||||||
]
|
|
||||||
urls = dict(zip(urls, [get_uri_template(url) for url in urls]))
|
|
||||||
urls.update(getattr(settings, "UMAP_EXTRA_URLS", {}))
|
|
||||||
return urls
|
|
||||||
|
|
||||||
|
|
||||||
def simple_json_response(**kwargs):
|
def simple_json_response(**kwargs):
|
||||||
return HttpResponse(json.dumps(kwargs), content_type="application/json")
|
return HttpResponse(json.dumps(kwargs), content_type="application/json")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue