diff --git a/umap/migrations/0009_star.py b/umap/migrations/0009_star.py new file mode 100644 index 00000000..7f2fec0e --- /dev/null +++ b/umap/migrations/0009_star.py @@ -0,0 +1,25 @@ +# Generated by Django 4.1.7 on 2023-05-05 18:02 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('umap', '0008_alter_map_settings'), + ] + + operations = [ + migrations.CreateModel( + name='Star', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('at', models.DateTimeField(auto_now=True)), + ('by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stars', to=settings.AUTH_USER_MODEL)), + ('map', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='umap.map')), + ], + ), + ] diff --git a/umap/models.py b/umap/models.py index 2e317abc..de3071f8 100644 --- a/umap/models.py +++ b/umap/models.py @@ -349,3 +349,9 @@ class DataLayer(NamedModel): self.geojson.storage.delete(path) except FileNotFoundError: pass + + +class Star(models.Model): + at = models.DateTimeField(auto_now=True) + map = models.ForeignKey(Map, on_delete=models.CASCADE) + by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="stars", on_delete=models.CASCADE) diff --git a/umap/static/umap/img/24-white.png b/umap/static/umap/img/24-white.png index 95edf1d6..e3a43024 100644 Binary files a/umap/static/umap/img/24-white.png and b/umap/static/umap/img/24-white.png differ diff --git a/umap/static/umap/img/24-white.svg b/umap/static/umap/img/24-white.svg index 28c7fc4d..861e45f5 100644 --- a/umap/static/umap/img/24-white.svg +++ b/umap/static/umap/img/24-white.svg @@ -13,7 +13,7 @@ height="200" id="svg2" version="1.1" - inkscape:version="0.92.2 2405546, 2018-03-11" + inkscape:version="0.92.4 5da689c313, 2019-01-14" sodipodi:docname="24-white.svg" inkscape:export-filename="/home/ybon/Code/py/umap/umap/static/umap/img/24-white.png" inkscape:export-xdpi="96" @@ -27,9 +27,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="22.4" - inkscape:cx="124.98783" - inkscape:cy="45.00337" + inkscape:zoom="16" + inkscape:cx="119.65216" + inkscape:cy="34.240239" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" diff --git a/umap/static/umap/img/24.png b/umap/static/umap/img/24.png index c4a9bddf..d6c038fb 100644 Binary files a/umap/static/umap/img/24.png and b/umap/static/umap/img/24.png differ diff --git a/umap/static/umap/img/24.svg b/umap/static/umap/img/24.svg index 5835faf0..4cf1ac8d 100644 --- a/umap/static/umap/img/24.svg +++ b/umap/static/umap/img/24.svg @@ -2,22 +2,22 @@ + inkscape:export-ydpi="89.996864" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:guide-bbox="true" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1"> + + diff --git a/umap/static/umap/js/umap.controls.js b/umap/static/umap/js/umap.controls.js index 695b3de9..e9bb9dc5 100644 --- a/umap/static/umap/js/umap.controls.js +++ b/umap/static/umap/js/umap.controls.js @@ -1018,6 +1018,28 @@ L.U.AttributionControl = L.Control.Attribution.extend({ }, }) +L.U.StarControl = L.Control.extend({ + options: { + position: 'topleft', + }, + + onAdd: function (map) { + var status = map.options.starred ? ' starred' : '' + var container = L.DomUtil.create( + 'div', + 'leaflet-control-star umap-control' + status + ), + link = L.DomUtil.create('a', '', container) + link.href = '#' + link.title = L._('Star this map') + L.DomEvent.on(link, 'click', L.DomEvent.stop) + .on(link, 'click', map.star, map) + .on(link, 'dblclick', L.DomEvent.stopPropagation) + + return container + }, +}) + L.U.Search = L.PhotonSearch.extend({ initialize: function (map, input, options) { L.PhotonSearch.prototype.initialize.call(this, map, input, options) diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index eef555ce..7e7b7a06 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -1060,6 +1060,10 @@ L.U.FormBuilder = L.FormBuilder.extend({ handler: 'DataLayersControl', label: L._('Display the data layers control'), }, + starControl: { + handler: 'ControlChoice', + label: L._('Display the star map button'), + }, }, initialize: function (obj, fields, options) { diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index d9479f0e..b5a520e6 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -60,6 +60,7 @@ L.U.Map.include({ 'tilelayers', 'editinosm', 'datalayers', + 'star', ], initialize: function (el, geojson) { @@ -309,6 +310,7 @@ L.U.Map.include({ this._controls.search = new L.U.SearchControl() this._controls.embed = new L.Control.Embed(this, this.options.embedOptions) this._controls.tilelayers = new L.U.TileLayerControl(this) + this._controls.star = new L.U.StarControl(this) this._controls.editinosm = new L.Control.EditInOSM({ position: 'topleft', widgetOptions: { @@ -1283,6 +1285,7 @@ L.U.Map.include({ 'embedControl', 'measureControl', 'tilelayersControl', + 'starControl', 'easing', ], @@ -1369,6 +1372,28 @@ L.U.Map.include({ return (this.options.umap_id && this.getEditUrl()) || this.getCreateUrl() }, + star: function () { + if (!this.options.umap_id) + return this.ui.alert({ + content: L._('Please save the map first'), + level: 'error', + }) + let url = L.Util.template(this.options.urls.map_star, { + map_id: this.options.umap_id, + }) + this.post(url, { + context: this, + callback: function (data) { + this.options.starred = data.starred + let msg = data.starred + ? L._('Map has been starred') + : L._('Map has been unstarred') + this.ui.alert({ content: msg, level: 'info' }) + this.renderControls() + }, + }) + }, + geometry: function () { /* Return a GeoJSON geometry Object */ var latlng = this.latLng(this.options.center || this.getCenter()) diff --git a/umap/static/umap/map.css b/umap/static/umap/map.css index 91371c83..525027d8 100644 --- a/umap/static/umap/map.css +++ b/umap/static/umap/map.css @@ -88,6 +88,12 @@ a.umap-control-less { background-position: -80px -161px; box-shadow: 0 0 4px 0 black inset; } +.leaflet-control-star a { + background-position: -118px -160px; +} +.leaflet-control-star.starred a { + background-position: -158px -160px; +} .leaflet-control-search a { background-position: -41px -121px; display: block; diff --git a/umap/templates/auth/user_stars.html b/umap/templates/auth/user_stars.html new file mode 100644 index 00000000..47c3e569 --- /dev/null +++ b/umap/templates/auth/user_stars.html @@ -0,0 +1,20 @@ +{% extends "umap/content.html" %} + +{% load i18n %} + +{% block maincontent %} +
+

{% blocktrans %}Browse {{ current_user }}'s starred maps{% endblocktrans %}

+
+
+
+ {% if maps %} + {% include "umap/map_list.html" %} + {% else %} +
+ {% blocktrans %}{{ current_user }} has no starred maps yet.{% endblocktrans %} +
+ {% endif %} +
+
+{% endblock maincontent %} diff --git a/umap/templates/umap/navigation.html b/umap/templates/umap/navigation.html index 3282bc0b..acde349a 100644 --- a/umap/templates/umap/navigation.html +++ b/umap/templates/umap/navigation.html @@ -8,6 +8,7 @@