Merge pull request #1821 from umap-project/caption-module
fix: display all layers in caption
This commit is contained in:
commit
754c895dde
7 changed files with 146 additions and 113 deletions
108
umap/static/umap/js/modules/caption.js
Normal file
108
umap/static/umap/js/modules/caption.js
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { translate } from './i18n.js'
|
||||||
|
import * as Utils from './utils.js'
|
||||||
|
|
||||||
|
export default class Caption {
|
||||||
|
constructor(map) {
|
||||||
|
this.map = map
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
const container = DomUtil.create('div', 'umap-caption')
|
||||||
|
DomUtil.createTitle(container, this.map.options.name, 'icon-caption')
|
||||||
|
this.map.permissions.addOwnerLink('h5', container)
|
||||||
|
if (this.map.options.description) {
|
||||||
|
const description = DomUtil.element({
|
||||||
|
tagName: 'div',
|
||||||
|
className: 'umap-map-description',
|
||||||
|
safeHTML: Utils.toHTML(this.map.options.description),
|
||||||
|
parent: container,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const datalayerContainer = DomUtil.create('div', 'datalayer-container', container)
|
||||||
|
this.map.eachDataLayer((datalayer) => this.addDataLayer(datalayer, datalayerContainer))
|
||||||
|
const creditsContainer = DomUtil.create('div', 'credits-container', container)
|
||||||
|
this.addCredits(creditsContainer)
|
||||||
|
this.map.panel.open({ content: container })
|
||||||
|
}
|
||||||
|
|
||||||
|
addDataLayer(datalayer, container) {
|
||||||
|
if (!datalayer.options.inCaption) return
|
||||||
|
const p = DomUtil.create('p', 'datalayer-legend', container),
|
||||||
|
legend = DomUtil.create('span', '', p),
|
||||||
|
headline = DomUtil.create('strong', '', p)
|
||||||
|
datalayer.onceLoaded(() => {
|
||||||
|
datalayer.renderLegend(legend)
|
||||||
|
if (datalayer.options.description) {
|
||||||
|
DomUtil.element({
|
||||||
|
tagName: 'span',
|
||||||
|
parent: p,
|
||||||
|
safeHTML: Utils.toHTML(datalayer.options.description),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
datalayer.renderToolbox(headline)
|
||||||
|
DomUtil.add('span', '', headline, `${datalayer.options.name} `)
|
||||||
|
}
|
||||||
|
|
||||||
|
addCredits(container) {
|
||||||
|
const credits = DomUtil.createFieldset(container, translate('Credits'))
|
||||||
|
let title = DomUtil.add('h5', '', credits, translate('User content credits'))
|
||||||
|
if (this.map.options.shortCredit || this.map.options.longCredit) {
|
||||||
|
DomUtil.element({
|
||||||
|
tagName: 'p',
|
||||||
|
parent: credits,
|
||||||
|
safeHTML: Utils.toHTML(
|
||||||
|
this.map.options.longCredit || this.map.options.shortCredit
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.map.options.licence) {
|
||||||
|
const licence = DomUtil.add(
|
||||||
|
'p',
|
||||||
|
'',
|
||||||
|
credits,
|
||||||
|
`${translate('Map user content has been published under licence')} `
|
||||||
|
)
|
||||||
|
DomUtil.createLink(
|
||||||
|
'',
|
||||||
|
licence,
|
||||||
|
this.map.options.licence.name,
|
||||||
|
this.map.options.licence.url
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
DomUtil.add('p', '', credits, translate('No licence has been set'))
|
||||||
|
}
|
||||||
|
title = DomUtil.create('h5', '', credits)
|
||||||
|
title.textContent = translate('Map background credits')
|
||||||
|
const tilelayerCredit = DomUtil.create('p', '', credits)
|
||||||
|
DomUtil.element({
|
||||||
|
tagName: 'strong',
|
||||||
|
parent: tilelayerCredit,
|
||||||
|
textContent: `${this.map.selected_tilelayer.options.name} `,
|
||||||
|
})
|
||||||
|
DomUtil.element({
|
||||||
|
tagName: 'span',
|
||||||
|
parent: tilelayerCredit,
|
||||||
|
safeHTML: this.map.selected_tilelayer.getAttribution(),
|
||||||
|
})
|
||||||
|
const urls = {
|
||||||
|
leaflet: 'http://leafletjs.com',
|
||||||
|
django: 'https://www.djangoproject.com',
|
||||||
|
umap: 'https://umap-project.org/',
|
||||||
|
changelog: 'https://docs.umap-project.org/en/master/changelog/',
|
||||||
|
version: this.map.options.umap_version,
|
||||||
|
}
|
||||||
|
const creditHTML = translate(
|
||||||
|
`
|
||||||
|
Powered by <a href="{leaflet}">Leaflet</a> and
|
||||||
|
<a href="{django}">Django</a>,
|
||||||
|
glued by <a href="{umap}">uMap project</a>
|
||||||
|
(version <a href="{changelog}">{version}</a>).
|
||||||
|
`,
|
||||||
|
urls
|
||||||
|
)
|
||||||
|
DomUtil.element({ tagName: 'p', innerHTML: creditHTML, parent: credits })
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import URLs from './urls.js'
|
import URLs from './urls.js'
|
||||||
import Browser from './browser.js'
|
import Browser from './browser.js'
|
||||||
import Facets from './facets.js'
|
import Facets from './facets.js'
|
||||||
|
import Caption from './caption.js'
|
||||||
import { Panel, EditPanel, FullPanel } from './panel.js'
|
import { Panel, EditPanel, FullPanel } from './panel.js'
|
||||||
import * as Utils from './utils.js'
|
import * as Utils from './utils.js'
|
||||||
import { SCHEMA } from './schema.js'
|
import { SCHEMA } from './schema.js'
|
||||||
|
@ -25,4 +26,5 @@ window.U = {
|
||||||
Utils,
|
Utils,
|
||||||
SCHEMA,
|
SCHEMA,
|
||||||
Orderable,
|
Orderable,
|
||||||
|
Caption,
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,7 +530,7 @@ U.CaptionControl = L.Control.Button.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
this.map.displayCaption()
|
this.map.openCaption()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -671,96 +671,6 @@ const ControlsMixin = {
|
||||||
'tilelayers',
|
'tilelayers',
|
||||||
],
|
],
|
||||||
|
|
||||||
displayCaption: function () {
|
|
||||||
const container = L.DomUtil.create('div', 'umap-caption')
|
|
||||||
L.DomUtil.createTitle(container, this.options.name, 'icon-caption')
|
|
||||||
this.permissions.addOwnerLink('h5', container)
|
|
||||||
if (this.options.description) {
|
|
||||||
const description = L.DomUtil.element({
|
|
||||||
tagName: 'div',
|
|
||||||
className: 'umap-map-description',
|
|
||||||
safeHTML: U.Utils.toHTML(this.options.description),
|
|
||||||
parent: container,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const datalayerContainer = L.DomUtil.create('div', 'datalayer-container', container)
|
|
||||||
this.eachVisibleDataLayer((datalayer) => {
|
|
||||||
if (!datalayer.options.inCaption) return
|
|
||||||
const p = L.DomUtil.create('p', 'datalayer-legend', datalayerContainer),
|
|
||||||
legend = L.DomUtil.create('span', '', p),
|
|
||||||
headline = L.DomUtil.create('strong', '', p)
|
|
||||||
datalayer.onceLoaded(function () {
|
|
||||||
datalayer.renderLegend(legend)
|
|
||||||
if (datalayer.options.description) {
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'span',
|
|
||||||
parent: p,
|
|
||||||
safeHTML: U.Utils.toHTML(datalayer.options.description),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
datalayer.renderToolbox(headline)
|
|
||||||
L.DomUtil.add('span', '', headline, `${datalayer.options.name} `)
|
|
||||||
})
|
|
||||||
const creditsContainer = L.DomUtil.create('div', 'credits-container', container),
|
|
||||||
credits = L.DomUtil.createFieldset(creditsContainer, L._('Credits'))
|
|
||||||
title = L.DomUtil.add('h5', '', credits, L._('User content credits'))
|
|
||||||
if (this.options.shortCredit || this.options.longCredit) {
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'p',
|
|
||||||
parent: credits,
|
|
||||||
safeHTML: U.Utils.toHTML(this.options.longCredit || this.options.shortCredit),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (this.options.licence) {
|
|
||||||
const licence = L.DomUtil.add(
|
|
||||||
'p',
|
|
||||||
'',
|
|
||||||
credits,
|
|
||||||
`${L._('Map user content has been published under licence')} `
|
|
||||||
)
|
|
||||||
L.DomUtil.createLink(
|
|
||||||
'',
|
|
||||||
licence,
|
|
||||||
this.options.licence.name,
|
|
||||||
this.options.licence.url
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
L.DomUtil.add('p', '', credits, L._('No licence has been set'))
|
|
||||||
}
|
|
||||||
title = L.DomUtil.create('h5', '', credits)
|
|
||||||
title.textContent = L._('Map background credits')
|
|
||||||
const tilelayerCredit = L.DomUtil.create('p', '', credits)
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'strong',
|
|
||||||
parent: tilelayerCredit,
|
|
||||||
textContent: `${this.selected_tilelayer.options.name} `,
|
|
||||||
})
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'span',
|
|
||||||
parent: tilelayerCredit,
|
|
||||||
safeHTML: this.selected_tilelayer.getAttribution(),
|
|
||||||
})
|
|
||||||
const urls = {
|
|
||||||
leaflet: 'http://leafletjs.com',
|
|
||||||
django: 'https://www.djangoproject.com',
|
|
||||||
umap: 'http://wiki.openstreetmap.org/wiki/UMap',
|
|
||||||
changelog: 'https://umap-project.readthedocs.io/en/master/changelog/',
|
|
||||||
version: this.options.umap_version,
|
|
||||||
}
|
|
||||||
const creditHTML = L._(
|
|
||||||
`
|
|
||||||
Powered by <a href="{leaflet}">Leaflet</a> and
|
|
||||||
<a href="{django}">Django</a>,
|
|
||||||
glued by <a href="{umap}">uMap project</a>
|
|
||||||
(version <a href="{changelog}">{version}</a>).
|
|
||||||
`,
|
|
||||||
urls
|
|
||||||
)
|
|
||||||
L.DomUtil.element({ tagName: 'p', innerHTML: creditHTML, parent: credits })
|
|
||||||
this.panel.open({ content: container })
|
|
||||||
},
|
|
||||||
|
|
||||||
renderEditToolbar: function () {
|
renderEditToolbar: function () {
|
||||||
const container = L.DomUtil.create(
|
const container = L.DomUtil.create(
|
||||||
'div',
|
'div',
|
||||||
|
@ -1077,7 +987,7 @@ U.AttributionControl = L.Control.Attribution.extend({
|
||||||
if (captionMenus) {
|
if (captionMenus) {
|
||||||
const link = L.DomUtil.add('a', '', container, ` — ${L._('About')}`)
|
const link = L.DomUtil.add('a', '', container, ` — ${L._('About')}`)
|
||||||
L.DomEvent.on(link, 'click', L.DomEvent.stop)
|
L.DomEvent.on(link, 'click', L.DomEvent.stop)
|
||||||
.on(link, 'click', this._map.displayCaption, this._map)
|
.on(link, 'click', this._map.openCaption, this._map)
|
||||||
.on(link, 'dblclick', L.DomEvent.stop)
|
.on(link, 'dblclick', L.DomEvent.stop)
|
||||||
}
|
}
|
||||||
if (window.top === window.self && captionMenus) {
|
if (window.top === window.self && captionMenus) {
|
||||||
|
|
|
@ -222,7 +222,7 @@ U.Map = L.Map.extend({
|
||||||
this.openBrowser('filters')
|
this.openBrowser('filters')
|
||||||
} else if (this.options.onLoadPanel === 'caption') {
|
} else if (this.options.onLoadPanel === 'caption') {
|
||||||
this.panel.mode = 'condensed'
|
this.panel.mode = 'condensed'
|
||||||
this.displayCaption()
|
this.openCaption()
|
||||||
}
|
}
|
||||||
if (L.Util.queryString('edit')) {
|
if (L.Util.queryString('edit')) {
|
||||||
if (this.hasEditMode()) this.enableEdit()
|
if (this.hasEditMode()) this.enableEdit()
|
||||||
|
@ -382,6 +382,7 @@ U.Map = L.Map.extend({
|
||||||
else this.scrollWheelZoom.disable()
|
else this.scrollWheelZoom.disable()
|
||||||
this.browser = new U.Browser(this)
|
this.browser = new U.Browser(this)
|
||||||
this.facets = new U.Facets(this)
|
this.facets = new U.Facets(this)
|
||||||
|
this.caption = new U.Caption(this)
|
||||||
this.importer = new U.Importer(this)
|
this.importer = new U.Importer(this)
|
||||||
this.drop = new U.DropControl(this)
|
this.drop = new U.DropControl(this)
|
||||||
this.share = new U.Share(this)
|
this.share = new U.Share(this)
|
||||||
|
@ -911,9 +912,11 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
openBrowser: function (mode) {
|
openBrowser: function (mode) {
|
||||||
this.onceDatalayersLoaded(function () {
|
this.onceDatalayersLoaded(() => this.browser.open(mode))
|
||||||
this.browser.open(mode)
|
},
|
||||||
})
|
|
||||||
|
openCaption: function () {
|
||||||
|
this.onceDatalayersLoaded(() => this.caption.open())
|
||||||
},
|
},
|
||||||
|
|
||||||
eachDataLayer: function (method, context) {
|
eachDataLayer: function (method, context) {
|
||||||
|
@ -1591,7 +1594,7 @@ U.Map = L.Map.extend({
|
||||||
'umap-about-link flat',
|
'umap-about-link flat',
|
||||||
container,
|
container,
|
||||||
L._('About'),
|
L._('About'),
|
||||||
this.displayCaption,
|
this.openCaption,
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
L.DomUtil.createButton(
|
L.DomUtil.createButton(
|
||||||
|
@ -1758,7 +1761,7 @@ U.Map = L.Map.extend({
|
||||||
items.push(
|
items.push(
|
||||||
{
|
{
|
||||||
text: L._('About'),
|
text: L._('About'),
|
||||||
callback: this.displayCaption,
|
callback: this.openCaption,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: this.help.displayLabel('SEARCH'),
|
text: this.help.displayLabel('SEARCH'),
|
||||||
|
|
|
@ -125,6 +125,7 @@ class DataLayerFactory(factory.django.DjangoModelFactory):
|
||||||
**kwargs["settings"],
|
**kwargs["settings"],
|
||||||
}
|
}
|
||||||
data.setdefault("_umap_options", {})
|
data.setdefault("_umap_options", {})
|
||||||
|
kwargs["settings"]["name"] = kwargs["name"]
|
||||||
data["_umap_options"]["name"] = kwargs["name"]
|
data["_umap_options"]["name"] = kwargs["name"]
|
||||||
kwargs["geojson"] = ContentFile(json.dumps(data), "foo.json")
|
kwargs["geojson"] = ContentFile(json.dumps(data), "foo.json")
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
24
umap/tests/integration/test_caption.py
Normal file
24
umap/tests/integration/test_caption.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import pytest
|
||||||
|
from playwright.sync_api import expect
|
||||||
|
|
||||||
|
from ..base import DataLayerFactory
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
def test_caption(live_server, page, map):
|
||||||
|
map.settings["properties"]["onLoadPanel"] = "caption"
|
||||||
|
map.save()
|
||||||
|
basic = DataLayerFactory(map=map, name="Basic layer")
|
||||||
|
non_loaded = DataLayerFactory(
|
||||||
|
map=map, name="Non loaded", settings={"displayOnLoad": False}
|
||||||
|
)
|
||||||
|
hidden = DataLayerFactory(map=map, name="Hidden", settings={"inCaption": False})
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||||
|
panel = page.locator(".umap-caption")
|
||||||
|
expect(panel).to_be_visible()
|
||||||
|
expect(panel.locator(".datalayer-legend").get_by_text(basic.name)).to_be_visible()
|
||||||
|
expect(
|
||||||
|
panel.locator(".datalayer-legend .off").get_by_text(non_loaded.name)
|
||||||
|
).to_be_visible()
|
||||||
|
expect(panel.locator(".datalayer-legend").get_by_text(hidden.name)).to_be_hidden()
|
|
@ -188,21 +188,6 @@ def test_remote_layer_should_not_be_used_as_datalayer_for_created_features(
|
||||||
expect(layers).to_have_count(2)
|
expect(layers).to_have_count(2)
|
||||||
|
|
||||||
|
|
||||||
def test_can_hide_datalayer_from_caption(openmap, live_server, datalayer, page):
|
|
||||||
# Add another DataLayer
|
|
||||||
other = DataLayerFactory(map=openmap, name="Hidden", settings={"inCaption": False})
|
|
||||||
page.goto(f"{live_server.url}{openmap.get_absolute_url()}")
|
|
||||||
toggle = page.get_by_text("About").first
|
|
||||||
expect(toggle).to_be_visible()
|
|
||||||
toggle.click()
|
|
||||||
layers = page.locator(".umap-caption .datalayer-legend")
|
|
||||||
expect(layers).to_have_count(1)
|
|
||||||
found = page.locator(".panel.left.on").get_by_text(datalayer.name)
|
|
||||||
expect(found).to_be_visible()
|
|
||||||
hidden = page.locator(".panel.left.on").get_by_text(other.name)
|
|
||||||
expect(hidden).to_be_hidden()
|
|
||||||
|
|
||||||
|
|
||||||
def test_minimap_on_load(map, live_server, datalayer, page):
|
def test_minimap_on_load(map, live_server, datalayer, page):
|
||||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||||
expect(page.locator(".leaflet-control-minimap")).to_be_hidden()
|
expect(page.locator(".leaflet-control-minimap")).to_be_hidden()
|
||||||
|
|
Loading…
Reference in a new issue