wip: move default options to schema

This commit also introduce a new settings UMAP_SCHEMA, that could
be used to easily override schema default, like the default color, the
default path weigth and so on. I'm not documenting yet, because I'm
not yet totally sure we want this.
This commit is contained in:
Yohan Boniface 2024-02-29 13:21:14 +01:00
parent da945cf733
commit a7a854dd74
11 changed files with 73 additions and 56 deletions

View file

@ -9,6 +9,7 @@ from django.core.files.base import File
from django.core.signing import Signer
from django.template.defaultfilters import slugify
from django.urls import reverse
from django.utils.functional import classproperty
from django.utils.translation import gettext_lazy as _
from .managers import PublicManager
@ -217,7 +218,7 @@ class Map(NamedModel):
"umap_id": self.pk,
"onLoadPanel": "none",
"captionBar": False,
"default_iconUrl": "%sumap/img/marker.svg" % settings.STATIC_URL,
"schema": self.schema,
"slideshow": {},
}
)
@ -328,6 +329,17 @@ class Map(NamedModel):
datalayer.clone(map_inst=new)
return new
@classproperty
def schema(self):
schema = settings.UMAP_SCHEMA
schema.setdefault(
"iconUrl",
{
"default": "%sumap/img/marker.svg" % settings.STATIC_URL,
},
)
return schema
class Pictogram(NamedModel):
"""

View file

@ -256,6 +256,7 @@ UMAP_DEFAULT_SHARE_STATUS = None
UMAP_DEFAULT_EDIT_STATUS = None
UMAP_DEFAULT_FEATURES_HAVE_OWNERS = False
UMAP_HOME_FEED = "latest"
UMAP_SCHEMA = {}
UMAP_READONLY = env("UMAP_READONLY", default=False)
UMAP_GZIP = True

View file

@ -30,7 +30,7 @@ export default class Browser {
title.textContent = feature.getDisplayName() || '—'
const bgcolor = feature.getDynamicOption('color')
colorBox.style.backgroundColor = bgcolor
if (symbol && symbol !== this.map.options.default_iconUrl) {
if (symbol && symbol !== U.SCHEMA.iconUrl.default) {
const icon = U.Icon.makeIconElement(symbol, colorBox)
U.Icon.setIconContrast(icon, colorBox, symbol, bgcolor)
}
@ -131,7 +131,7 @@ export default class Browser {
'h3',
'umap-browse-title',
container,
this.map.options.name
this.map.getOption('name')
)
const formContainer = DomUtil.create('div', '', container)

View file

@ -11,18 +11,22 @@ export const SCHEMA = {
scaleControl: {
type: Boolean,
label: translate('Do you want to display the scale control?'),
default: true,
},
moreControl: {
type: Boolean,
label: translate('Do you want to display the «more» control?'),
default: true,
},
miniMap: {
type: Boolean,
label: translate('Do you want to display a minimap?'),
default: false,
},
displayPopupFooter: {
type: Boolean,
label: translate('Do you want to display popup footer?'),
default: false,
},
onLoadPanel: {
type: String,
@ -74,6 +78,7 @@ export const SCHEMA = {
label: translate('color'),
helpEntries: 'colorValue',
inheritable: true,
default: 'DarkBlue',
},
iconClass: {
type: String,
@ -85,6 +90,7 @@ export const SCHEMA = {
['Drop', translate('Drop')],
['Ball', translate('Ball')],
],
default: 'Default',
},
iconUrl: {
type: String,
@ -101,6 +107,7 @@ export const SCHEMA = {
label: translate('Simplify'),
helpEntries: 'smoothFactor',
inheritable: true,
default: 1.0,
},
iconOpacity: {
type: Number,
@ -109,6 +116,7 @@ export const SCHEMA = {
step: 0.1,
label: translate('icon opacity'),
inheritable: true,
default: 1,
},
opacity: {
type: Number,
@ -117,6 +125,7 @@ export const SCHEMA = {
step: 0.1,
label: translate('opacity'),
inheritable: true,
default: 0.5,
},
weight: {
type: Number,
@ -125,12 +134,14 @@ export const SCHEMA = {
step: 1,
label: translate('weight'),
inheritable: true,
default: 3,
},
fill: {
type: Boolean,
label: translate('fill'),
helpEntries: 'fill',
inheritable: true,
default: true,
},
fillColor: {
type: String,
@ -146,6 +157,7 @@ export const SCHEMA = {
step: 0.1,
label: translate('fill opacity'),
inheritable: true,
default: 0.3,
},
dashArray: {
type: String,
@ -183,6 +195,7 @@ export const SCHEMA = {
helpEntries: ['dynamicProperties', 'textFormatting'],
placeholder: '# {name}',
inheritable: true,
default: '# {name}\n{description}',
},
zoomTo: {
type: Number,
@ -194,10 +207,12 @@ export const SCHEMA = {
captionBar: {
type: Boolean,
label: translate('Do you want to display a caption bar?'),
default: false,
},
captionMenus: {
type: Boolean,
label: translate('Do you want to display caption menus?'),
default: true,
},
slideshow: {
type: Object,
@ -239,6 +254,7 @@ export const SCHEMA = {
['top', translate('On the top')],
['bottom', translate('On the bottom')],
],
default: 'auto',
},
labelInteractive: {
type: Boolean,
@ -274,22 +290,26 @@ export const SCHEMA = {
permanentCreditBackground: {
type: Boolean,
label: translate('Permanent credits background'),
default: true,
},
zoomControl: {
type: Boolean,
nullable: true,
label: translate('Display the zoom control'),
default: true,
},
datalayersControl: {
type: Boolean,
nullable: true,
handler: 'DataLayersControl',
label: translate('Display the data layers control'),
default: true,
},
searchControl: {
type: Boolean,
nullable: true,
label: translate('Display the search control'),
default: true,
},
locateControl: {
type: Boolean,
@ -300,16 +320,19 @@ export const SCHEMA = {
type: Boolean,
nullable: true,
label: translate('Display the fullscreen control'),
default: true,
},
editinosmControl: {
type: Boolean,
nullable: true,
label: translate('Display the control to open OpenStreetMap editor'),
default: null,
},
embedControl: {
type: Boolean,
nullable: true,
label: translate('Display the embed control'),
default: true,
},
measureControl: {
type: Boolean,
@ -328,12 +351,14 @@ export const SCHEMA = {
},
easing: {
type: Boolean,
default: false,
},
interactive: {
type: Boolean,
label: translate('Allow interactions'),
helpEntries: 'interactive',
inheritable: true,
default: true,
},
fromZoom: {
type: Number,
@ -350,6 +375,7 @@ export const SCHEMA = {
label: translate('stroke'),
helpEntries: 'stroke',
inheritable: true,
default: true,
},
outlink: {
label: translate('Link to…'),

View file

@ -1184,25 +1184,22 @@ U.AttributionControl = L.Control.Attribution.extend({
this._container,
credits
)
if (this._map.options.shortCredit) {
L.DomUtil.add(
'span',
'',
container,
`${L.Util.toHTML(this._map.options.shortCredit)}`
)
const shortCredit = this._map.getOption('shortCredit'),
captionMenus = this._map.getOption('captionMenus')
if (shortCredit) {
L.DomUtil.add('span', '', container, `${L.Util.toHTML(shortCredit)}`)
}
if (this._map.options.captionMenus) {
if (captionMenus) {
const link = L.DomUtil.add('a', '', container, `${L._('About')}`)
L.DomEvent.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', this._map.displayCaption, this._map)
.on(link, 'dblclick', L.DomEvent.stop)
}
if (window.top === window.self && this._map.options.captionMenus) {
if (window.top === window.self && captionMenus) {
// We are not in iframe mode
L.DomUtil.createLink('', container, `${L._('Home')}`, '/')
}
if (this._map.options.captionMenus) {
if (captionMenus) {
L.DomUtil.createLink(
'',
container,

View file

@ -53,7 +53,7 @@ U.FeatureMixin = {
},
getSlug: function () {
return this.properties[this.map.options.slugKey || 'name'] || ''
return this.properties[this.map.getOption('slugKey') || 'name'] || ''
},
getPermalink: function () {
@ -209,7 +209,7 @@ U.FeatureMixin = {
if (L.Browser.ielt9) return false
if (this.datalayer.isRemoteLayer() && this.datalayer.options.remoteData.dynamic)
return false
return this.map.options.displayPopupFooter
return this.map.getOption('displayPopupFooter')
},
getPopupClass: function () {
@ -309,7 +309,7 @@ U.FeatureMixin = {
zoomTo: function (e) {
e = e || {}
const easing = e.easing !== undefined ? e.easing : this.map.options.easing
const easing = e.easing !== undefined ? e.easing : this.map.getOption('easing')
if (easing) {
this.map.flyTo(this.getCenter(), this.getBestZoom())
} else {
@ -975,7 +975,7 @@ U.PathMixin = {
zoomTo: function (e) {
// Use bounds instead of centroid for paths.
e = e || {}
const easing = e.easing !== undefined ? e.easing : this.map.options.easing
const easing = e.easing !== undefined ? e.easing : this.map.getOption('easing')
if (easing) {
this.map.flyToBounds(this.getBounds(), this.getBestZoom())
} else {

View file

@ -653,7 +653,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
},
isDefault: function () {
return !this.value() || this.value() === U.DEFAULT_ICON_URL
return !this.value() || this.value() === U.SCHEMA.iconUrl.default
},
addGrid: function (onSearch) {

View file

@ -19,7 +19,7 @@ U.Icon = L.DivIcon.extend({
_setRecent: function (url) {
if (L.Util.hasVar(url)) return
if (url === U.DEFAULT_ICON_URL) return
if (url === U.SCHEMA.iconUrl.default) return
if (U.Icon.RECENT.indexOf(url) === -1) {
U.Icon.RECENT.push(url)
}
@ -236,7 +236,7 @@ U.Icon.setIconContrast = function (icon, parent, src, bgcolor) {
if (L.DomUtil.contrastedColor(parent, bgcolor)) {
// Decide whether to switch svg to white or not, but do it
// only for internal SVG, as invert could do weird things
if (L.Util.isPath(src) && src.endsWith('.svg') && src !== U.DEFAULT_ICON_URL) {
if (L.Util.isPath(src) && src.endsWith('.svg') && src !== U.SCHEMA.iconUrl.default) {
// Must be called after icon container is added to the DOM
// An image
icon.style.filter = 'invert(1)'

View file

@ -2,33 +2,12 @@ L.Map.mergeOptions({
overlay: null,
datalayers: [],
hash: true,
default_color: 'DarkBlue',
default_smoothFactor: 1.0,
default_opacity: 0.5,
default_fillOpacity: 0.3,
default_stroke: true,
default_fill: true,
default_weight: 3,
default_iconOpacity: 1,
default_iconClass: 'Default',
default_popupContentTemplate: '# {name}\n{description}',
default_interactive: true,
default_labelDirection: 'auto',
maxZoomLimit: 24,
attributionControl: false,
editMode: 'advanced',
embedControl: true,
zoomControl: true,
datalayersControl: true,
searchControl: true,
editInOSMControl: false,
editInOSMControlOptions: false,
scaleControl: true,
noControl: false, // Do not render any control.
miniMap: false,
name: '',
description: '',
displayPopupFooter: false,
// When a TileLayer is in TMS mode, it needs -y instead of y.
// This is usually handled by the TileLayer instance itself, but
// we cannot rely on this because of the y is overriden by Leaflet
@ -44,14 +23,9 @@ L.Map.mergeOptions({
importPresets: [
// {url: 'http://localhost:8019/en/datalayer/1502/', label: 'Simplified World Countries', format: 'geojson'}
],
moreControl: true,
captionBar: false,
captionMenus: true,
slideshow: {},
clickable: true,
easing: false,
permissions: {},
permanentCreditBackground: true,
featuresHaveOwner: false,
})
@ -75,7 +49,8 @@ U.Map = L.Map.extend({
geojson.properties.fullscreenControl = false
L.Map.prototype.initialize.call(this, el, geojson.properties)
U.DEFAULT_ICON_URL = this.options.default_iconUrl
if (geojson.properties.schema) this.overrideSchema(geojson.properties.schema)
// After calling parent initialize, as we are doing initCenter our-selves
if (geojson.geometry) this.options.center = this.latLng(geojson.geometry)
@ -292,6 +267,12 @@ U.Map = L.Map.extend({
}
},
overrideSchema: function (schema) {
for (const [key, extra] of Object.entries(schema)) {
U.SCHEMA[key] = L.extend({}, U.SCHEMA[key], extra)
}
},
initControls: function () {
this.helpMenuActions = {}
this._controls = {}
@ -333,7 +314,7 @@ U.Map = L.Map.extend({
title: { false: L._('View Fullscreen'), true: L._('Exit Fullscreen') },
})
this._controls.search = new U.SearchControl()
this._controls.embed = new L.Control.Embed(this, this.options.embedOptions)
this._controls.embed = new L.Control.Embed(this)
this._controls.tilelayersChooser = new U.TileLayerChooser(this)
if (this.options.user) this._controls.star = new U.StarControl(this)
this._controls.editinosm = new L.Control.EditInOSM({
@ -399,7 +380,7 @@ U.Map = L.Map.extend({
let name, status, control
for (let i = 0; i < this.HIDDABLE_CONTROLS.length; i++) {
name = this.HIDDABLE_CONTROLS[i]
status = this.options[`${name}Control`]
status = this.getOption(`${name}Control`)
if (status === false) continue
control = this._controls[name]
if (!control) continue
@ -408,9 +389,9 @@ U.Map = L.Map.extend({
L.DomUtil.addClass(control._container, 'display-on-more')
else L.DomUtil.removeClass(control._container, 'display-on-more')
}
if (this.options.permanentCredit) this._controls.permanentCredit.addTo(this)
if (this.options.moreControl) this._controls.more.addTo(this)
if (this.options.scaleControl) this._controls.scale.addTo(this)
if (this.getOption('permanentCredit')) this._controls.permanentCredit.addTo(this)
if (this.getOption('moreControl')) this._controls.more.addTo(this)
if (this.getOption('scaleControl')) this._controls.scale.addTo(this)
},
initDataLayers: async function (datalayers) {
@ -760,7 +741,7 @@ U.Map = L.Map.extend({
},
getDefaultOption: function (option) {
return this.options[`default_${option}`]
return U.SCHEMA[option] && U.SCHEMA[option].default
},
getOption: function (option) {
@ -1607,7 +1588,7 @@ U.Map = L.Map.extend({
name = L.DomUtil.create('h3', '', container)
L.DomEvent.disableClickPropagation(container)
this.permissions.addOwnerLink('span', container)
if (this.options.captionMenus) {
if (this.getOption('captionMenus')) {
L.DomUtil.createButton(
'umap-about-link flat',
container,

View file

@ -215,7 +215,7 @@ U.IframeExporter = L.Evented.extend({
this.map = map
this.baseUrl = L.Util.getBaseUrl()
// Use map default, not generic default
this.queryString.onLoadPanel = this.map.options.onLoadPanel
this.queryString.onLoadPanel = this.map.getOption('onLoadPanel')
},
getMap: function () {

View file

@ -488,7 +488,7 @@ class MapDetailMixin:
"urls": _urls_for_js(),
"tilelayers": TileLayer.get_list(),
"editMode": self.edit_mode,
"default_iconUrl": "%sumap/img/marker.svg" % settings.STATIC_URL, # noqa
"schema": Map.schema,
"umap_id": self.get_umap_id(),
"starred": self.is_starred(),
"licences": dict((l.name, l.json) for l in Licence.objects.all()),