feat: move star button to caption

fix #2282
This commit is contained in:
Yohan Boniface 2025-01-23 11:25:09 +01:00
parent 30690bcb35
commit 48f9afdedd
13 changed files with 58 additions and 45 deletions

View file

@ -153,6 +153,12 @@ html[dir="rtl"] .icon {
.icon-share { .icon-share {
background-position: 0px calc(var(--tile) * 5); background-position: 0px calc(var(--tile) * 5);
} }
.icon-star {
background-position: var(--tile) calc(var(--tile) * 7);
}
.icon-starred {
background-position: 0 calc(var(--tile) * 7);
}
.icon-table { .icon-table {
background-position: calc(var(--tile) * 2) 0px; background-position: calc(var(--tile) * 2) 0px;
} }

View file

@ -208,5 +208,7 @@
<g id="g2-67" transform="translate(170.12 814.31)" clip-path="url(#clip0_2695_1939)"> <g id="g2-67" transform="translate(170.12 814.31)" clip-path="url(#clip0_2695_1939)">
<path id="path1-5" d="m8.8453 14.83c-0.28116 0.6439-1.1722 0.6439-1.4533 0l-0.73138-1.6751c-0.65086-1.4907-1.8224-2.6774-3.2837-3.326l-2.0131-0.89358c-0.64004-0.28408-0.64004-1.2152 0-1.4993l1.9502-0.86569c1.4989-0.66535 2.6914-1.8959 3.3312-3.4375l0.74086-1.7852c0.27491-0.66247 1.1902-0.66247 1.4652 0l0.74083 1.7852c0.63972 1.5416 1.8322 2.7722 3.3311 3.4375l1.9503 0.86569c0.64 0.2841 0.64 1.2152 0 1.4993l-2.0131 0.89358c-1.4613 0.64864-2.6328 1.8353-3.2837 3.326zm-5.0624-6.6444c1.9049 0.84555 3.4537 2.2354 4.3357 4.1478 0.88202-1.9124 2.4308-3.3022 4.3356-4.1478-1.9276-0.85565-3.4813-2.3132-4.3356-4.2596-0.85434 1.9463-2.4081 3.4039-4.3357 4.2596zm12.385 10.723 0.2057-0.4714c0.3667-0.8405 1.0271-1.5098 1.8511-1.8758l0.6336-0.2816c0.3428-0.1523 0.3428-0.6504 0-0.8026l-0.5981-0.2658c-0.8453-0.3755-1.5175-1.0695-1.8779-1.9386l-0.2112-0.5094c-0.1473-0.355-0.6381-0.355-0.7853 0l-0.2112 0.5094c-0.3603 0.8691-1.0326 1.5631-1.8778 1.9386l-0.5983 0.2658c-0.3427 0.1522-0.3427 0.6503 0 0.8026l0.6337 0.2816c0.8241 0.366 1.4844 1.0353 1.8511 1.8758l0.2057 0.4714c0.1505 0.3451 0.6283 0.3451 0.7789 0zm-0.8557-3.0358 0.4687-0.4655 0.459 0.4655-0.459 0.4524z" fill="#efefef"/> <path id="path1-5" d="m8.8453 14.83c-0.28116 0.6439-1.1722 0.6439-1.4533 0l-0.73138-1.6751c-0.65086-1.4907-1.8224-2.6774-3.2837-3.326l-2.0131-0.89358c-0.64004-0.28408-0.64004-1.2152 0-1.4993l1.9502-0.86569c1.4989-0.66535 2.6914-1.8959 3.3312-3.4375l0.74086-1.7852c0.27491-0.66247 1.1902-0.66247 1.4652 0l0.74083 1.7852c0.63972 1.5416 1.8322 2.7722 3.3311 3.4375l1.9503 0.86569c0.64 0.2841 0.64 1.2152 0 1.4993l-2.0131 0.89358c-1.4613 0.64864-2.6328 1.8353-3.2837 3.326zm-5.0624-6.6444c1.9049 0.84555 3.4537 2.2354 4.3357 4.1478 0.88202-1.9124 2.4308-3.3022 4.3356-4.1478-1.9276-0.85565-3.4813-2.3132-4.3356-4.2596-0.85434 1.9463-2.4081 3.4039-4.3357 4.2596zm12.385 10.723 0.2057-0.4714c0.3667-0.8405 1.0271-1.5098 1.8511-1.8758l0.6336-0.2816c0.3428-0.1523 0.3428-0.6504 0-0.8026l-0.5981-0.2658c-0.8453-0.3755-1.5175-1.0695-1.8779-1.9386l-0.2112-0.5094c-0.1473-0.355-0.6381-0.355-0.7853 0l-0.2112 0.5094c-0.3603 0.8691-1.0326 1.5631-1.8778 1.9386l-0.5983 0.2658c-0.3427 0.1522-0.3427 0.6503 0 0.8026l0.6337 0.2816c0.8241 0.366 1.4844 1.0353 1.8511 1.8758l0.2057 0.4714c0.1505 0.3451 0.6283 0.3451 0.7789 0zm-0.8557-3.0358 0.4687-0.4655 0.459 0.4655-0.459 0.4524z" fill="#efefef"/>
</g> </g>
<path id="star" class="sprite" d="m7.6698 998.86 1.3886-5.255-4.0585-3.2468h5.1831l1.8193-5.4949 1.8147 5.4939h5.1829l-4.0615 3.2496 1.3838 5.2564-4.3249-3.0123z" fill="#efefef"/>
<path id="starred" class="sprite" d="m31.67 998.86 1.3886-5.255-4.0585-3.2468h5.1831l1.8193-5.4949 1.8147 5.4939h5.1829l-4.0615 3.2496 1.3838 5.2565-4.3249-3.0123z" fill="none" stroke="#efefef" stroke-linecap="square" stroke-linejoin="round"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 43 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -19,7 +19,7 @@
<rect width="20" height="20" fill="#ffffff" id="rect1" x="0" y="0" /> <rect width="20" height="20" fill="#ffffff" id="rect1" x="0" y="0" />
</clipPath> </clipPath>
</defs> </defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="14.041122" inkscape:cx="165.15774" inkscape:cy="24.998002" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" inkscape:window-width="1920" inkscape:window-height="1011" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" showguides="true" inkscape:guide-bbox="true" inkscape:snap-grids="true" inkscape:snap-to-guides="true" inkscape:showpageshadow="2" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1"> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="14.412751" inkscape:cx="41.352272" inkscape:cy="165.68662" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" inkscape:window-width="1920" inkscape:window-height="1011" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" showguides="true" inkscape:guide-bbox="true" inkscape:snap-grids="true" inkscape:snap-to-guides="true" inkscape:showpageshadow="2" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1">
<inkscape:grid type="xygrid" id="grid3004" empspacing="4" visible="true" enabled="true" snapvisiblegridlinesonly="true" originx="0" originy="0" spacingy="1" spacingx="1" units="px" /> <inkscape:grid type="xygrid" id="grid3004" empspacing="4" visible="true" enabled="true" snapvisiblegridlinesonly="true" originx="0" originy="0" spacingy="1" spacingx="1" units="px" />
<inkscape:grid id="grid1" units="px" originx="0" originy="0" spacingx="24" spacingy="24" empcolor="#203fff" empopacity="0.85490196" color="#3f3fff" opacity="0.1254902" empspacing="1" enabled="true" visible="true" /> <inkscape:grid id="grid1" units="px" originx="0" originy="0" spacingx="24" spacingy="24" empcolor="#203fff" empopacity="0.85490196" color="#3f3fff" opacity="0.1254902" empspacing="1" enabled="true" visible="true" />
</sodipodi:namedview> </sodipodi:namedview>
@ -219,5 +219,7 @@
<g clip-path="url(#clip0_2695_1939)" id="g2-67" transform="translate(170.11621,814.31159)"> <g clip-path="url(#clip0_2695_1939)" id="g2-67" transform="translate(170.11621,814.31159)">
<path d="m 8.84533,14.8298 c -0.28116,0.6439 -1.1722,0.6439 -1.45333,0 l -0.73138,-1.6751 c -0.65086,-1.4907 -1.82238,-2.6774 -3.2837,-3.32604 l -2.0131,-0.89358 c -0.64004,-0.28408 -0.64004,-1.21518 0,-1.49928 l 1.95022,-0.86569 c 1.4989,-0.66535 2.69143,-1.89594 3.33118,-3.43751 l 0.74086,-1.78516 c 0.27491,-0.662471 1.19025,-0.662472 1.46517,0 l 0.74083,1.78517 c 0.63972,1.54156 1.83222,2.77215 3.33112,3.4375 l 1.9503,0.86569 c 0.64,0.2841 0.64,1.2152 0,1.49928 l -2.0131,0.89358 c -1.4613,0.64864 -2.6328,1.83534 -3.28374,3.32604 z m -5.06236,-6.64435 c 1.90486,0.84555 3.45371,2.23535 4.33568,4.14775 0.88202,-1.9124 2.43085,-3.3022 4.33565,-4.14775 -1.9276,-0.85565 -3.4813,-2.31323 -4.33564,-4.25955 -0.85434,1.94633 -2.4081,3.4039 -4.33569,4.25955 z m 12.38483,10.72295 0.2057,-0.4714 c 0.3667,-0.8405 1.0271,-1.5098 1.8511,-1.8758 l 0.6336,-0.2816 c 0.3428,-0.1523 0.3428,-0.6504 0,-0.8026 l -0.5981,-0.2658 c -0.8453,-0.3755 -1.5175,-1.0695 -1.8779,-1.9386 l -0.2112,-0.5094 c -0.1473,-0.355 -0.6381,-0.355 -0.7853,0 l -0.2112,0.5094 c -0.3603,0.8691 -1.0326,1.5631 -1.8778,1.9386 l -0.5983,0.2658 c -0.3427,0.1522 -0.3427,0.6503 0,0.8026 l 0.6337,0.2816 c 0.8241,0.366 1.4844,1.0353 1.8511,1.8758 l 0.2057,0.4714 c 0.1505,0.3451 0.6283,0.3451 0.7789,0 z m -0.8557,-3.0358 0.4687,-0.4655 0.459,0.4655 -0.459,0.4524 z" fill="#efefef" id="path1-5" /> <path d="m 8.84533,14.8298 c -0.28116,0.6439 -1.1722,0.6439 -1.45333,0 l -0.73138,-1.6751 c -0.65086,-1.4907 -1.82238,-2.6774 -3.2837,-3.32604 l -2.0131,-0.89358 c -0.64004,-0.28408 -0.64004,-1.21518 0,-1.49928 l 1.95022,-0.86569 c 1.4989,-0.66535 2.69143,-1.89594 3.33118,-3.43751 l 0.74086,-1.78516 c 0.27491,-0.662471 1.19025,-0.662472 1.46517,0 l 0.74083,1.78517 c 0.63972,1.54156 1.83222,2.77215 3.33112,3.4375 l 1.9503,0.86569 c 0.64,0.2841 0.64,1.2152 0,1.49928 l -2.0131,0.89358 c -1.4613,0.64864 -2.6328,1.83534 -3.28374,3.32604 z m -5.06236,-6.64435 c 1.90486,0.84555 3.45371,2.23535 4.33568,4.14775 0.88202,-1.9124 2.43085,-3.3022 4.33565,-4.14775 -1.9276,-0.85565 -3.4813,-2.31323 -4.33564,-4.25955 -0.85434,1.94633 -2.4081,3.4039 -4.33569,4.25955 z m 12.38483,10.72295 0.2057,-0.4714 c 0.3667,-0.8405 1.0271,-1.5098 1.8511,-1.8758 l 0.6336,-0.2816 c 0.3428,-0.1523 0.3428,-0.6504 0,-0.8026 l -0.5981,-0.2658 c -0.8453,-0.3755 -1.5175,-1.0695 -1.8779,-1.9386 l -0.2112,-0.5094 c -0.1473,-0.355 -0.6381,-0.355 -0.7853,0 l -0.2112,0.5094 c -0.3603,0.8691 -1.0326,1.5631 -1.8778,1.9386 l -0.5983,0.2658 c -0.3427,0.1522 -0.3427,0.6503 0,0.8026 l 0.6337,0.2816 c 0.8241,0.366 1.4844,1.0353 1.8511,1.8758 l 0.2057,0.4714 c 0.1505,0.3451 0.6283,0.3451 0.7789,0 z m -0.8557,-3.0358 0.4687,-0.4655 0.459,0.4655 -0.459,0.4524 z" fill="#efefef" id="path1-5" />
</g> </g>
<path style="fill:#efefef;fill-opacity:1;stroke:none;stroke-width:6.97518;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" inkscape:transform-center-x="-0.0010932573" inkscape:transform-center-y="-0.7377641" d="m 7.6698317,998.8588 1.3886278,-5.25497 -4.0584591,-3.24679 h 5.1830926 l 1.819345,-5.49493 1.81469,5.49392 h 5.182872 l -4.06154,3.24965 1.383849,5.25642 -4.324867,-3.01228 z" id="star" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccc" class="sprite" />
<path style="fill:none;fill-opacity:1;stroke:#efefef;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" inkscape:transform-center-x="-0.0010925804" inkscape:transform-center-y="-0.73776941" d="m 31.669832,998.8588 1.388628,-5.25501 -4.05846,-3.24679 h 5.183093 l 1.819345,-5.49493 1.814694,5.49392 h 5.182868 l -4.06154,3.24964 1.383849,5.25647 -4.324874,-3.01232 z" id="starred" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccc" class="sprite" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 75 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View file

@ -1,5 +1,6 @@
import { translate } from './i18n.js' import { translate } from './i18n.js'
import * as Utils from './utils.js' import * as Utils from './utils.js'
import { uMapAlert as Alert } from '../components/alerts/alert.js'
const TEMPLATE = ` const TEMPLATE = `
<div class="umap-caption"> <div class="umap-caption">
@ -7,8 +8,9 @@ const TEMPLATE = `
<i class="icon icon-16 icon-caption icon-block"></i> <i class="icon icon-16 icon-caption icon-block"></i>
<hgroup> <hgroup>
<h3><span class="map-name" data-ref="name"></span></h3> <h3><span class="map-name" data-ref="name"></span></h3>
<h4 data-ref="author"></h4>
<h5 class="dates" data-ref="dates"></h5> <h5 class="dates" data-ref="dates"></h5>
<h4 data-ref="author"></h4>
<h5><i class="icon icon-16 icon-star map-star" data-ref="star"></i><span class="map-stars"></span></h5>
</hgroup> </hgroup>
</div> </div>
<div class="umap-map-description text" data-ref="description"></div> <div class="umap-map-description text" data-ref="description"></div>
@ -35,6 +37,14 @@ export default class Caption extends Utils.WithTemplate {
this._umap = umap this._umap = umap
this._leafletMap = leafletMap this._leafletMap = leafletMap
this.loadTemplate(TEMPLATE) this.loadTemplate(TEMPLATE)
this.elements.star.addEventListener('click', async () => {
if (this._umap.properties.user?.id) {
await this._umap.star()
this.refresh()
} else {
Alert.error(translate('You must be logged in'))
}
})
} }
isOpen() { isOpen() {
@ -62,10 +72,6 @@ export default class Caption extends Utils.WithTemplate {
this.addDataLayer(datalayer, this.elements.datalayersContainer) this.addDataLayer(datalayer, this.elements.datalayersContainer)
) )
this.addCredits() this.addCredits()
this._umap.panel.open({ content: this.element }).then(() => {
// Create the legend when the panel is actually on the DOM
this._umap.eachDataLayerReverse((datalayer) => datalayer.renderLegend())
})
if (this._umap.properties.created_at) { if (this._umap.properties.created_at) {
const created_at = translate('Created at {date}', { const created_at = translate('Created at {date}', {
date: new Date(this._umap.properties.created_at).toLocaleDateString(), date: new Date(this._umap.properties.created_at).toLocaleDateString(),
@ -77,6 +83,11 @@ export default class Caption extends Utils.WithTemplate {
} else { } else {
this.elements.dates.hidden = true this.elements.dates.hidden = true
} }
this._umap.panel.open({ content: this.element }).then(() => {
// Create the legend when the panel is actually on the DOM
this._umap.eachDataLayerReverse((datalayer) => datalayer.renderLegend())
this._umap.propagate()
})
} }
addDataLayer(datalayer, parent) { addDataLayer(datalayer, parent) {

View file

@ -32,7 +32,6 @@ const ControlsMixin = {
'locate', 'locate',
'measure', 'measure',
'editinosm', 'editinosm',
'star',
'tilelayers', 'tilelayers',
], ],
@ -84,7 +83,6 @@ const ControlsMixin = {
this._controls.search = new U.SearchControl() this._controls.search = new U.SearchControl()
this._controls.embed = new Control.Embed(this._umap) this._controls.embed = new Control.Embed(this._umap)
this._controls.tilelayersChooser = new U.TileLayerChooser(this) this._controls.tilelayersChooser = new U.TileLayerChooser(this)
if (this.options.user?.id) this._controls.star = new U.StarControl(this._umap)
this._controls.editinosm = new Control.EditInOSM({ this._controls.editinosm = new Control.EditInOSM({
position: 'topleft', position: 'topleft',
widgetOptions: { widgetOptions: {

View file

@ -478,12 +478,6 @@ export const SCHEMA = {
label: translate('Sort key'), label: translate('Sort key'),
inheritable: true, inheritable: true,
}, },
starControl: {
type: Boolean,
impacts: ['ui'],
nullable: true,
label: translate('Display the star map button'),
},
stroke: { stroke: {
type: Boolean, type: Boolean,
impacts: ['data'], impacts: ['data'],

View file

@ -1360,7 +1360,11 @@ export default class Umap extends ServerStored {
}, },
'properties.starred': () => { 'properties.starred': () => {
Utils.eachElement('.map-star', (el) => { Utils.eachElement('.map-star', (el) => {
el.classList.toggle('starred', this.properties.starred) el.classList.toggle('icon-starred', this.properties.starred)
el.classList.toggle('icon-star', !this.properties.starred)
})
Utils.eachElement('.map-stars', (el) => {
el.textContent = this.properties.stars || translate('Star this map')
}) })
}, },
} }
@ -1543,6 +1547,7 @@ export default class Umap extends ServerStored {
return return
} }
this.properties.starred = data.starred this.properties.starred = data.starred
this.properties.stars = data.stars
Alert.success( Alert.success(
data.starred data.starred
? translate('Map has been starred') ? translate('Map has been starred')

View file

@ -491,18 +491,6 @@ U.CaptionControl = L.Control.Button.extend({
}, },
}) })
U.StarControl = L.Control.Button.extend({
options: {
position: 'topleft',
title: L._('Star this map'),
className: 'leaflet-control-star map-star umap-control',
},
onClick: function () {
this._umap.star()
},
})
L.Control.Embed = L.Control.Button.extend({ L.Control.Embed = L.Control.Button.extend({
options: { options: {
position: 'topleft', position: 'topleft',

View file

@ -134,12 +134,6 @@ html[dir="rtl"] .leaflet-tooltip-pane > * {
background-position: -72px -144px; background-position: -72px -144px;
box-shadow: 0 0 4px 0 black inset; box-shadow: 0 0 4px 0 black inset;
} }
.leaflet-control-star [type="button"] {
background-position: -144px -144px;
}
.leaflet-control-star.starred [type="button"] {
background-position: -108px -144px;
}
.leaflet-control-search [type="button"] { .leaflet-control-search [type="button"] {
background-position: -36px -108px; background-position: -36px -108px;
display: block; display: block;

View file

@ -8,20 +8,24 @@ from umap.models import Star
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
def test_star_control_is_visible_if_logged_in(map, live_server, page, login, user): def test_star_button_is_active_if_logged_in(map, live_server, page, login, user):
login(user) login(user)
assert not Star.objects.count() assert not Star.objects.count()
page.goto(f"{live_server.url}{map.get_absolute_url()}") page.goto(f"{live_server.url}{map.get_absolute_url()}")
page.get_by_title("More controls").click() page.get_by_title("About").click()
control = page.locator(".leaflet-control-star") button = page.locator(".icon-star")
expect(control).to_be_visible() expect(button).to_be_visible()
with page.expect_response(re.compile(".*/star/")): with page.expect_response(re.compile(".*/star/")):
control.click() button.click()
expect(button).to_be_hidden()
# Button has changed
expect(page.locator(".icon-starred")).to_be_visible()
assert Star.objects.count() == 1 assert Star.objects.count() == 1
def test_no_star_control_if_not_logged_in(map, live_server, page): def test_star_button_inctive_if_not_logged_in(map, live_server, page):
page.goto(f"{live_server.url}{map.get_absolute_url()}") page.goto(f"{live_server.url}{map.get_absolute_url()}")
page.get_by_title("More controls").click() page.get_by_title("About").click()
control = page.locator(".leaflet-control-star") button = page.locator(".icon-star")
expect(control).to_be_hidden() button.click()
expect(page.get_by_text("You must be logged in")).to_be_visible()

View file

@ -605,6 +605,7 @@ class MapDetailMixin(SessionMixin):
"schema": Map.extra_schema, "schema": Map.extra_schema,
"id": self.get_id(), "id": self.get_id(),
"starred": self.is_starred(), "starred": self.is_starred(),
"stars": self.stars(),
"licences": dict((l.name, l.json) for l in Licence.objects.all()), "licences": dict((l.name, l.json) for l in Licence.objects.all()),
"umap_version": VERSION, "umap_version": VERSION,
"featuresHaveOwner": settings.UMAP_DEFAULT_FEATURES_HAVE_OWNERS, "featuresHaveOwner": settings.UMAP_DEFAULT_FEATURES_HAVE_OWNERS,
@ -678,6 +679,9 @@ class MapDetailMixin(SessionMixin):
def is_starred(self): def is_starred(self):
return False return False
def stars(self):
return 0
def get_geojson(self): def get_geojson(self):
return { return {
"geometry": { "geometry": {
@ -780,6 +784,9 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView):
return False return False
return Star.objects.filter(by=user, map=self.object).exists() return Star.objects.filter(by=user, map=self.object).exists()
def stars(self):
return Star.objects.filter(map=self.object).count()
class MapDownload(DetailView): class MapDownload(DetailView):
model = Map model = Map
@ -1081,7 +1088,9 @@ class ToggleMapStarStatus(View):
else: else:
Star.objects.create(map=map_inst, by=self.request.user) Star.objects.create(map=map_inst, by=self.request.user)
status = True status = True
return simple_json_response(starred=status) return simple_json_response(
starred=status, stars=Star.objects.filter(map=map_inst).count()
)
class MapShortUrl(RedirectView): class MapShortUrl(RedirectView):