From a6a1959c09cbef8b59d0574cf86bbfed9132c8bd Mon Sep 17 00:00:00 2001 From: David Larlet Date: Tue, 27 Feb 2024 14:55:55 -0500 Subject: [PATCH 01/11] chore: Integrate i18n changes from Leaflet PR See https://github.com/Leaflet/Leaflet/pull/9281 --- umap/static/umap/js/modules/global.js | 2 -- umap/static/umap/js/modules/i18n.js | 35 +++++++++++++++++++ .../umap/js/modules/leaflet-configure.js | 6 ++++ umap/templates/umap/js.html | 12 ++++--- 4 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 umap/static/umap/js/modules/i18n.js create mode 100644 umap/static/umap/js/modules/leaflet-configure.js diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js index 2d579187..62f3cbbc 100644 --- a/umap/static/umap/js/modules/global.js +++ b/umap/static/umap/js/modules/global.js @@ -1,4 +1,3 @@ -import * as L from '../../vendors/leaflet/leaflet-src.esm.js' import URLs from './urls.js' import Browser from './browser.js' import * as Utils from './utils.js' @@ -8,7 +7,6 @@ import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './req // For the not yet module-compatible JS out there. // Copy the leaflet module, it's expected by leaflet plugins to be writeable. -window.L = { ...L } window.U = { URLs, Request, diff --git a/umap/static/umap/js/modules/i18n.js b/umap/static/umap/js/modules/i18n.js new file mode 100644 index 00000000..d2b6b429 --- /dev/null +++ b/umap/static/umap/js/modules/i18n.js @@ -0,0 +1,35 @@ +// Comes from https://github.com/Leaflet/Leaflet/pull/9281 +import { Util } from '../../vendors/leaflet/leaflet-src.esm.js' + +const locales = {} + +// @property locale: String +// The current locale code, that will be used when translating strings. +export let locale = null + +// @function registerLocale(code: String, locale?: Object): String +// Define localized strings for a given locale, defined by `code`. +export function registerLocale(code, locale) { + locales[code] = Util.extend({}, locales[code], locale) +} +// @function setLocale(code: String): undefined +// Define or change the locale code to be used when translating strings. +export function setLocale(code) { + locale = code +} +// @function translate(string: String, data?: Object): String +// Actually try to translate the `string`, with optionnal variable passed in `data`. +export function translate(string, data) { + if (locale && locales[locale] && locales[locale][string] !== undefined) { + string = locales[locale][string] + } + try { + // Do not fail if some data is missing + // a bad translation should not break the app + string = Util.template(string, data) + } catch (err) { + console.error(err) + } + + return string +} diff --git a/umap/static/umap/js/modules/leaflet-configure.js b/umap/static/umap/js/modules/leaflet-configure.js new file mode 100644 index 00000000..9679f3f4 --- /dev/null +++ b/umap/static/umap/js/modules/leaflet-configure.js @@ -0,0 +1,6 @@ +import * as L from '../../vendors/leaflet/leaflet-src.esm.js' +// Comes from https://github.com/Leaflet/Leaflet/pull/9281 +// TODELETE once it's merged! +import * as i18n from './i18n.js' + +window.L = { ...L, ...i18n } diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html index 95e4a675..bcc700f0 100644 --- a/umap/templates/umap/js.html +++ b/umap/templates/umap/js.html @@ -2,6 +2,12 @@ + +{% if locale %} + {% with "umap/locale/"|add:locale|add:".js" as path %} + + {% endwith %} +{% endif %} @@ -39,11 +45,7 @@ -{% if locale %} - {% with "umap/locale/"|add:locale|add:".js" as path %} - - {% endwith %} -{% endif %} + From 68f3a9686aad4171966001f8f42b022d42839790 Mon Sep 17 00:00:00 2001 From: David Larlet Date: Tue, 27 Feb 2024 14:58:19 -0500 Subject: [PATCH 02/11] chore: Extract a schema module from Map --- umap/static/umap/js/modules/global.js | 3 +- umap/static/umap/js/modules/schema.js | 62 ++++++++++++++++++++++++++ umap/static/umap/js/umap.forms.js | 3 ++ umap/static/umap/js/umap.js | 64 ++------------------------- 4 files changed, 70 insertions(+), 62 deletions(-) create mode 100644 umap/static/umap/js/modules/schema.js diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js index 62f3cbbc..90bd180f 100644 --- a/umap/static/umap/js/modules/global.js +++ b/umap/static/umap/js/modules/global.js @@ -1,12 +1,12 @@ import URLs from './urls.js' import Browser from './browser.js' import * as Utils from './utils.js' +import SCHEMA from './schema.js' import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js' // Import modules and export them to the global scope. // For the not yet module-compatible JS out there. -// Copy the leaflet module, it's expected by leaflet plugins to be writeable. window.U = { URLs, Request, @@ -16,4 +16,5 @@ window.U = { NOKError, Browser, Utils, + SCHEMA, } diff --git a/umap/static/umap/js/modules/schema.js b/umap/static/umap/js/modules/schema.js new file mode 100644 index 00000000..db3075ca --- /dev/null +++ b/umap/static/umap/js/modules/schema.js @@ -0,0 +1,62 @@ +import { translate } from './i18n.js' + +const SCHEMA = { + zoom: { type: undefined }, + scrollWheelZoom: { type: Boolean }, + scaleControl: { type: Boolean }, + moreControl: { type: Boolean }, + miniMap: { type: Boolean }, + displayPopupFooter: { type: undefined }, + onLoadPanel: { type: String }, + defaultView: { type: String }, + name: { type: String, label: translate('name') }, + description: { type: String }, + licence: { type: undefined }, + tilelayer: { type: undefined }, + overlay: { type: undefined }, + limitBounds: { type: undefined }, + color: { type: String }, + iconClass: { type: String }, + iconUrl: { type: String }, + smoothFactor: { type: undefined }, + iconOpacity: { type: undefined }, + opacity: { type: undefined }, + weight: { type: undefined }, + fill: { type: undefined }, + fillColor: { type: undefined }, + fillOpacity: { type: undefined }, + dashArray: { type: undefined }, + popupShape: { type: String }, + popupTemplate: { type: String }, + popupContentTemplate: { type: String }, + zoomTo: { type: Number }, + captionBar: { type: Boolean }, + captionMenus: { type: Boolean }, + slideshow: { type: undefined }, + sortKey: { type: undefined }, + labelKey: { type: String }, + filterKey: { type: undefined }, + facetKey: { type: undefined }, + slugKey: { type: undefined }, + showLabel: { type: 'NullableBoolean' }, + labelDirection: { type: undefined }, + labelInteractive: { type: undefined }, + outlinkTarget: { type: undefined }, + shortCredit: { type: undefined }, + longCredit: { type: undefined }, + permanentCredit: { type: undefined }, + permanentCreditBackground: { type: undefined }, + zoomControl: { type: 'NullableBoolean' }, + datalayersControl: { type: 'NullableBoolean' }, + searchControl: { type: 'NullableBoolean' }, + locateControl: { type: 'NullableBoolean' }, + fullscreenControl: { type: 'NullableBoolean' }, + editinosmControl: { type: 'NullableBoolean' }, + embedControl: { type: 'NullableBoolean' }, + measureControl: { type: 'NullableBoolean' }, + tilelayersControl: { type: 'NullableBoolean' }, + starControl: { type: 'NullableBoolean' }, + easing: { type: undefined }, +} + +export default { SCHEMA } diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index 2d28a026..7834b499 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -1276,6 +1276,9 @@ U.FormBuilder = L.FormBuilder.extend({ initialize: function (obj, fields, options) { this.map = obj.map || obj.getMap() + for (const [key, schema] of Object.entries(U.SCHEMA)) { + this.defaultOptions[key] = this.defaultOptions[key] || schema + } L.FormBuilder.prototype.initialize.call(this, obj, fields, options) this.on('finish', this.finish) }, diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index bc73784b..c503c418 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -57,64 +57,6 @@ L.Map.mergeOptions({ U.Map = L.Map.extend({ includes: [ControlsMixin], - editableOptions: { - zoom: undefined, - scrollWheelZoom: Boolean, - scaleControl: Boolean, - moreControl: Boolean, - miniMap: Boolean, - displayPopupFooter: undefined, - onLoadPanel: String, - defaultView: String, - name: String, - description: String, - licence: undefined, - tilelayer: undefined, - overlay: undefined, - limitBounds: undefined, - color: String, - iconClass: String, - iconUrl: String, - smoothFactor: undefined, - iconOpacity: undefined, - opacity: undefined, - weight: undefined, - fill: undefined, - fillColor: undefined, - fillOpacity: undefined, - dashArray: undefined, - popupShape: String, - popupTemplate: String, - popupContentTemplate: String, - zoomTo: Number, - captionBar: Boolean, - captionMenus: Boolean, - slideshow: undefined, - sortKey: undefined, - labelKey: String, - filterKey: undefined, - facetKey: undefined, - slugKey: undefined, - showLabel: 'NullableBoolean', - labelDirection: undefined, - labelInteractive: undefined, - outlinkTarget: undefined, - shortCredit: undefined, - longCredit: undefined, - permanentCredit: undefined, - permanentCreditBackground: undefined, - zoomControl: 'NullableBoolean', - datalayersControl: 'NullableBoolean', - searchControl: 'NullableBoolean', - locateControl: 'NullableBoolean', - fullscreenControl: 'NullableBoolean', - editinosmControl: 'NullableBoolean', - embedControl: 'NullableBoolean', - measureControl: 'NullableBoolean', - tilelayersControl: 'NullableBoolean', - starControl: 'NullableBoolean', - easing: undefined, - }, initialize: function (el, geojson) { // Locale name (pt_PT, en_US…) @@ -329,7 +271,7 @@ U.Map = L.Map.extend({ // FIXME retrocompat L.Util.setBooleanFromQueryString(options, 'displayDataBrowserOnLoad') L.Util.setBooleanFromQueryString(options, 'displayCaptionOnLoad') - for (const [key, type] of Object.entries(this.editableOptions)) { + for (const [key, { type }] of Object.entries(U.SCHEMA)) { switch (type) { case Boolean: L.Util.setBooleanFromQueryString(options, key) @@ -904,7 +846,7 @@ U.Map = L.Map.extend({ let mustReindex = false - for (const option of Object.keys(this.editableOptions)) { + for (const option of Object.keys(U.SCHEMA)) { if (typeof importedData.properties[option] !== 'undefined') { this.options[option] = importedData.properties[option] if (option === 'sortKey') mustReindex = true @@ -1033,7 +975,7 @@ U.Map = L.Map.extend({ exportOptions: function () { const properties = {} - for (const option of Object.keys(this.editableOptions)) { + for (const option of Object.keys(U.SCHEMA)) { if (typeof this.options[option] !== 'undefined') { properties[option] = this.options[option] } From fcf22195cbc3876a827ea824d43e23850609e4b9 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 28 Feb 2024 11:56:32 +0100 Subject: [PATCH 03/11] chore: move defaultOptions from forms to schema --- umap/static/umap/js/modules/global.js | 2 +- umap/static/umap/js/modules/schema.js | 416 ++++++++++++++++++++++---- umap/static/umap/js/umap.forms.js | 337 +++------------------ umap/static/umap/js/umap.js | 44 +-- 4 files changed, 404 insertions(+), 395 deletions(-) diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js index 90bd180f..25ee3505 100644 --- a/umap/static/umap/js/modules/global.js +++ b/umap/static/umap/js/modules/global.js @@ -1,7 +1,7 @@ import URLs from './urls.js' import Browser from './browser.js' import * as Utils from './utils.js' -import SCHEMA from './schema.js' +import {SCHEMA} from './schema.js' import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js' // Import modules and export them to the global scope. diff --git a/umap/static/umap/js/modules/schema.js b/umap/static/umap/js/modules/schema.js index db3075ca..39b26864 100644 --- a/umap/static/umap/js/modules/schema.js +++ b/umap/static/umap/js/modules/schema.js @@ -1,62 +1,360 @@ import { translate } from './i18n.js' -const SCHEMA = { - zoom: { type: undefined }, - scrollWheelZoom: { type: Boolean }, - scaleControl: { type: Boolean }, - moreControl: { type: Boolean }, - miniMap: { type: Boolean }, - displayPopupFooter: { type: undefined }, - onLoadPanel: { type: String }, - defaultView: { type: String }, - name: { type: String, label: translate('name') }, - description: { type: String }, - licence: { type: undefined }, - tilelayer: { type: undefined }, - overlay: { type: undefined }, - limitBounds: { type: undefined }, - color: { type: String }, - iconClass: { type: String }, - iconUrl: { type: String }, - smoothFactor: { type: undefined }, - iconOpacity: { type: undefined }, - opacity: { type: undefined }, - weight: { type: undefined }, - fill: { type: undefined }, - fillColor: { type: undefined }, - fillOpacity: { type: undefined }, - dashArray: { type: undefined }, - popupShape: { type: String }, - popupTemplate: { type: String }, - popupContentTemplate: { type: String }, - zoomTo: { type: Number }, - captionBar: { type: Boolean }, - captionMenus: { type: Boolean }, - slideshow: { type: undefined }, - sortKey: { type: undefined }, - labelKey: { type: String }, - filterKey: { type: undefined }, - facetKey: { type: undefined }, - slugKey: { type: undefined }, - showLabel: { type: 'NullableBoolean' }, - labelDirection: { type: undefined }, - labelInteractive: { type: undefined }, - outlinkTarget: { type: undefined }, - shortCredit: { type: undefined }, - longCredit: { type: undefined }, - permanentCredit: { type: undefined }, - permanentCreditBackground: { type: undefined }, - zoomControl: { type: 'NullableBoolean' }, - datalayersControl: { type: 'NullableBoolean' }, - searchControl: { type: 'NullableBoolean' }, - locateControl: { type: 'NullableBoolean' }, - fullscreenControl: { type: 'NullableBoolean' }, - editinosmControl: { type: 'NullableBoolean' }, - embedControl: { type: 'NullableBoolean' }, - measureControl: { type: 'NullableBoolean' }, - tilelayersControl: { type: 'NullableBoolean' }, - starControl: { type: 'NullableBoolean' }, - easing: { type: undefined }, +export const SCHEMA = { + zoom: { + type: Number, + }, + scrollWheelZoom: { + type: Boolean, + label: translate('Allow scroll wheel zoom?'), + }, + scaleControl: { + type: Boolean, + label: translate('Do you want to display the scale control?'), + }, + moreControl: { + type: Boolean, + label: translate('Do you want to display the «more» control?'), + }, + miniMap: { + type: Boolean, + label: translate('Do you want to display a minimap?'), + }, + displayPopupFooter: { + type: Boolean, + label: translate('Do you want to display popup footer?'), + }, + onLoadPanel: { + type: String, + label: translate('Do you want to display a panel on load?'), + choices: [ + ['none', translate('None')], + ['caption', translate('Caption')], + ['databrowser', translate('Data browser')], + ['facet', translate('Facet search')], + ], + default: 'none', + }, + defaultView: { + type: String, + label: translate('Default view'), + choices: [ + ['center', translate('Saved center and zoom')], + ['data', translate('Fit all data')], + ['latest', translate('Latest feature')], + ['locate', translate('User location')], + ], + default: 'center', + }, + name: { + type: String, + label: translate('name'), + }, + description: { + label: translate('description'), + type: 'Text', + helpEntries: 'textFormatting', + }, + licence: { + type: String, + label: translate('licence'), + }, + tilelayer: { + type: Object, + }, + overlay: { + type: Object, + }, + limitBounds: { + type: Object, + }, + color: { + type: String, + handler: 'ColorPicker', + label: translate('color'), + helpEntries: 'colorValue', + inheritable: true, + }, + iconClass: { + type: String, + label: translate('Icon shape'), + inheritable: true, + choices: [ + ['Default', translate('Default')], + ['Circle', translate('Circle')], + ['Drop', translate('Drop')], + ['Ball', translate('Ball')], + ], + }, + iconUrl: { + type: String, + handler: 'IconUrl', + label: translate('Icon symbol'), + inheritable: true, + helpText: 'formatIconSymbol', + }, + smoothFactor: { + type: Number, + min: 0, + max: 10, + step: 0.5, + label: translate('Simplify'), + helpEntries: 'smoothFactor', + inheritable: true, + }, + iconOpacity: { + type: Number, + min: 0.1, + max: 1, + step: 0.1, + label: translate('icon opacity'), + inheritable: true, + }, + opacity: { + type: Number, + min: 0.1, + max: 1, + step: 0.1, + label: translate('opacity'), + inheritable: true, + }, + weight: { + type: Number, + min: 1, + max: 20, + step: 1, + label: translate('weight'), + inheritable: true, + }, + fill: { + type: Boolean, + label: translate('fill'), + helpEntries: 'fill', + inheritable: true, + }, + fillColor: { + type: String, + handler: 'ColorPicker', + label: translate('fill color'), + helpEntries: 'fillColor', + inheritable: true, + }, + fillOpacity: { + type: Number, + min: 0.1, + max: 1, + step: 0.1, + label: translate('fill opacity'), + inheritable: true, + }, + dashArray: { + type: String, + label: translate('dash array'), + helpEntries: 'dashArray', + inheritable: true, + }, + popupShape: { + type: String, + label: translate('Popup shape'), + inheritable: true, + choices: [ + ['Default', translate('Popup')], + ['Large', translate('Popup (large)')], + ['Panel', translate('Side panel')], + ], + default: 'Default', + }, + popupTemplate: { + type: String, + label: translate('Popup content style'), + inheritable: true, + choices: [ + ['Default', translate('Default')], + ['Table', translate('Table')], + ['GeoRSSImage', translate('GeoRSS (title + image)')], + ['GeoRSSLink', translate('GeoRSS (only link)')], + ['OSM', translate('OpenStreetMap')], + ], + default: 'Default', + }, + popupContentTemplate: { + type: 'Text', + label: translate('Popup content template'), + helpEntries: ['dynamicProperties', 'textFormatting'], + placeholder: '# {name}', + inheritable: true, + }, + zoomTo: { + type: Number, + placeholder: translate('Inherit'), + helpEntries: 'zoomTo', + label: translate('Default zoom level'), + inheritable: true, + }, + captionBar: { + type: Boolean, + label: translate('Do you want to display a caption bar?'), + }, + captionMenus: { + type: Boolean, + label: translate('Do you want to display caption menus?'), + }, + slideshow: { + type: Object, + }, + sortKey: { + type: String, + }, + labelKey: { + type: String, + helpEntries: 'labelKey', + placeholder: translate('Default: name'), + label: translate('Label key'), + inheritable: true, + }, + filterKey: { + type: String, + }, + facetKey: { + type: String, + }, + slugKey: { + type: String, + }, + showLabel: { + type: Boolean, + nullable: true, + label: translate('Display label'), + inheritable: true, + default: false, + }, + labelDirection: { + type: String, + label: translate('Label direction'), + inheritable: true, + choices: [ + ['auto', translate('Automatic')], + ['left', translate('On the left')], + ['right', translate('On the right')], + ['top', translate('On the top')], + ['bottom', translate('On the bottom')], + ], + }, + labelInteractive: { + type: Boolean, + label: translate('Labels are clickable'), + inheritable: true, + }, + outlinkTarget: { + type: String, + label: translate('Open link in…'), + inheritable: true, + default: 'blank', + choices: [ + ['blank', translate('new window')], + ['self', translate('iframe')], + ['parent', translate('parent window')], + ], + }, + shortCredit: { + type: String, + label: translate('Short credits'), + helpEntries: ['shortCredit', 'textFormatting'], + }, + longCredit: { + type: 'Text', + label: translate('Long credits'), + helpEntries: ['longCredit', 'textFormatting'], + }, + permanentCredit: { + type: 'Text', + label: translate('Permanent credits'), + helpEntries: ['permanentCredit', 'textFormatting'], + }, + permanentCreditBackground: { + type: Boolean, + label: translate('Permanent credits background'), + }, + zoomControl: { + type: Boolean, + nullable: true, + label: translate('Display the zoom control'), + }, + datalayersControl: { + type: Boolean, + nullable: true, + handler: 'DataLayersControl', + label: translate('Display the data layers control'), + }, + searchControl: { + type: Boolean, + nullable: true, + label: translate('Display the search control'), + }, + locateControl: { + type: Boolean, + nullable: true, + label: translate('Display the locate control'), + }, + fullscreenControl: { + type: Boolean, + nullable: true, + label: translate('Display the fullscreen control'), + }, + editinosmControl: { + type: Boolean, + nullable: true, + label: translate('Display the control to open OpenStreetMap editor'), + }, + embedControl: { + type: Boolean, + nullable: true, + label: translate('Display the embed control'), + }, + measureControl: { + type: Boolean, + nullable: true, + label: translate('Display the measure control'), + }, + tilelayersControl: { + type: Boolean, + nullable: true, + label: translate('Display the tile layers control'), + }, + starControl: { + type: Boolean, + nullable: true, + label: translate('Display the star map button'), + }, + easing: { + type: Boolean, + }, + interactive: { + type: Boolean, + label: translate('Allow interactions'), + helpEntries: 'interactive', + inheritable: true, + }, + fromZoom: { + type: Number, + label: translate('From zoom'), + helpText: translate('Optional.'), + }, + toZoom: { + type: Number, + label: translate('To zoom'), + helpText: translate('Optional.'), + }, + stroke: { + type: Boolean, + label: translate('stroke'), + helpEntries: 'stroke', + inheritable: true, + }, + outlink: { + label: translate('Link to…'), + helpEntries: 'outlink', + placeholder: 'http://...', + inheritable: true, + }, } - -export default { SCHEMA } diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index 7834b499..958329d3 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -340,15 +340,6 @@ L.FormBuilder.TextColorPicker = L.FormBuilder.ColorPicker.extend({ ], }) -L.FormBuilder.IconClassSwitcher = L.FormBuilder.Select.extend({ - selectOptions: [ - ['Default', L._('Default')], - ['Circle', L._('Circle')], - ['Drop', L._('Drop')], - ['Ball', L._('Ball')], - ], -}) - L.FormBuilder.ProxyTTLSelect = L.FormBuilder.Select.extend({ selectOptions: [ [undefined, L._('No cache')], @@ -358,24 +349,6 @@ L.FormBuilder.ProxyTTLSelect = L.FormBuilder.Select.extend({ ], }) -L.FormBuilder.PopupShape = L.FormBuilder.Select.extend({ - selectOptions: [ - ['Default', L._('Popup')], - ['Large', L._('Popup (large)')], - ['Panel', L._('Side panel')], - ], -}) - -L.FormBuilder.PopupContent = L.FormBuilder.Select.extend({ - selectOptions: [ - ['Default', L._('Default')], - ['Table', L._('Table')], - ['GeoRSSImage', L._('GeoRSS (title + image)')], - ['GeoRSSLink', L._('GeoRSS (only link)')], - ['OSM', L._('OpenStreetMap')], - ], -}) - L.FormBuilder.LayerTypeChooser = L.FormBuilder.Select.extend({ getOptions: function () { const layer_classes = [ @@ -427,24 +400,6 @@ L.FormBuilder.DataLayerSwitcher = L.FormBuilder.Select.extend({ }, }) -L.FormBuilder.DefaultView = L.FormBuilder.Select.extend({ - selectOptions: [ - ['center', L._('Saved center and zoom')], - ['data', L._('Fit all data')], - ['latest', L._('Latest feature')], - ['locate', L._('User location')], - ], -}) - -L.FormBuilder.OnLoadPanel = L.FormBuilder.Select.extend({ - selectOptions: [ - ['none', L._('None')], - ['caption', L._('Caption')], - ['databrowser', L._('Data browser')], - ['facet', L._('Facet search')], - ], -}) - L.FormBuilder.DataFormat = L.FormBuilder.Select.extend({ selectOptions: [ [undefined, L._('Choose the data format')], @@ -457,16 +412,6 @@ L.FormBuilder.DataFormat = L.FormBuilder.Select.extend({ ], }) -L.FormBuilder.LabelDirection = L.FormBuilder.Select.extend({ - selectOptions: [ - ['auto', L._('Automatic')], - ['left', L._('On the left')], - ['right', L._('On the right')], - ['top', L._('On the top')], - ['bottom', L._('On the bottom')], - ], -}) - L.FormBuilder.LicenceChooser = L.FormBuilder.Select.extend({ getOptions: function () { const licences = [] @@ -905,7 +850,7 @@ L.FormBuilder.TernaryChoices = L.FormBuilder.MultiChoice.extend({ }, }) -L.FormBuilder.ControlChoice = L.FormBuilder.TernaryChoices.extend({ +L.FormBuilder.NullableChoices = L.FormBuilder.TernaryChoices.extend({ choices: [ [true, L._('always')], [false, L._('never')], @@ -913,17 +858,7 @@ L.FormBuilder.ControlChoice = L.FormBuilder.TernaryChoices.extend({ ], }) -L.FormBuilder.LabelChoice = L.FormBuilder.TernaryChoices.extend({ - default: false, - - choices: [ - [true, L._('always')], - [false, L._('never')], - ['null', L._('on hover')], - ], -}) - -L.FormBuilder.DataLayersControl = L.FormBuilder.ControlChoice.extend({ +L.FormBuilder.DataLayersControl = L.FormBuilder.TernaryChoices.extend({ choices: [ [true, L._('collapsed')], ['expanded', L._('expanded')], @@ -934,21 +869,11 @@ L.FormBuilder.DataLayersControl = L.FormBuilder.ControlChoice.extend({ toJS: function () { let value = this.value() if (value !== 'expanded') - value = L.FormBuilder.ControlChoice.prototype.toJS.call(this) + value = L.FormBuilder.TernaryChoices.prototype.toJS.call(this) return value }, }) -L.FormBuilder.OutlinkTarget = L.FormBuilder.MultiChoice.extend({ - default: 'blank', - - choices: [ - ['blank', L._('new window')], - ['self', L._('iframe')], - ['parent', L._('parent window')], - ], -}) - L.FormBuilder.Range = L.FormBuilder.FloatInput.extend({ type: function () { return 'range' @@ -1053,232 +978,44 @@ U.FormBuilder = L.FormBuilder.extend({ }, defaultOptions: { - name: { label: L._('name') }, - description: { - label: L._('description'), - handler: 'Textarea', - helpEntries: 'textFormatting', - }, - color: { - handler: 'ColorPicker', - label: L._('color'), - helpEntries: 'colorValue', - inheritable: true, - }, - iconOpacity: { - handler: 'Range', - min: 0.1, - max: 1, - step: 0.1, - label: L._('icon opacity'), - inheritable: true, - }, - opacity: { - handler: 'Range', - min: 0.1, - max: 1, - step: 0.1, - label: L._('opacity'), - inheritable: true, - }, - stroke: { - handler: 'Switch', - label: L._('stroke'), - helpEntries: 'stroke', - inheritable: true, - }, - weight: { - handler: 'Range', - min: 1, - max: 20, - step: 1, - label: L._('weight'), - inheritable: true, - }, - fill: { - handler: 'Switch', - label: L._('fill'), - helpEntries: 'fill', - inheritable: true, - }, - fillColor: { - handler: 'ColorPicker', - label: L._('fill color'), - helpEntries: 'fillColor', - inheritable: true, - }, - fillOpacity: { - handler: 'Range', - min: 0.1, - max: 1, - step: 0.1, - label: L._('fill opacity'), - inheritable: true, - }, - smoothFactor: { - handler: 'Range', - min: 0, - max: 10, - step: 0.5, - label: L._('Simplify'), - helpEntries: 'smoothFactor', - inheritable: true, - }, - dashArray: { - label: L._('dash array'), - helpEntries: 'dashArray', - inheritable: true, - }, - iconClass: { - handler: 'IconClassSwitcher', - label: L._('Icon shape'), - inheritable: true, - }, - iconUrl: { - handler: 'IconUrl', - label: L._('Icon symbol'), - inheritable: true, - helpText: U.Help.formatIconSymbol, - }, - popupShape: { handler: 'PopupShape', label: L._('Popup shape'), inheritable: true }, - popupTemplate: { - handler: 'PopupContent', - label: L._('Popup content style'), - inheritable: true, - }, - popupContentTemplate: { - label: L._('Popup content template'), - handler: 'Textarea', - helpEntries: ['dynamicProperties', 'textFormatting'], - placeholder: '# {name}', - inheritable: true, - }, - datalayer: { - handler: 'DataLayerSwitcher', - label: L._('Choose the layer of the feature'), - }, - moreControl: { - handler: 'Switch', - label: L._('Do you want to display the «more» control?'), - }, - scrollWheelZoom: { handler: 'Switch', label: L._('Allow scroll wheel zoom?') }, - miniMap: { handler: 'Switch', label: L._('Do you want to display a minimap?') }, - scaleControl: { - handler: 'Switch', - label: L._('Do you want to display the scale control?'), - }, - onLoadPanel: { - handler: 'OnLoadPanel', - label: L._('Do you want to display a panel on load?'), - }, - defaultView: { - handler: 'DefaultView', - label: L._('Default view'), - }, - displayPopupFooter: { - handler: 'Switch', - label: L._('Do you want to display popup footer?'), - }, - captionBar: { - handler: 'Switch', - label: L._('Do you want to display a caption bar?'), - }, - captionMenus: { - handler: 'Switch', - label: L._('Do you want to display caption menus?'), - }, - zoomTo: { - handler: 'IntInput', - placeholder: L._('Inherit'), - helpEntries: 'zoomTo', - label: L._('Default zoom level'), - inheritable: true, - }, - showLabel: { - handler: 'LabelChoice', - label: L._('Display label'), - inheritable: true, - }, - labelDirection: { - handler: 'LabelDirection', - label: L._('Label direction'), - inheritable: true, - }, - labelInteractive: { - handler: 'Switch', - label: L._('Labels are clickable'), - inheritable: true, - }, - outlink: { - label: L._('Link to…'), - helpEntries: 'outlink', - placeholder: 'http://...', - inheritable: true, - }, - outlinkTarget: { - handler: 'OutlinkTarget', - label: L._('Open link in…'), - inheritable: true, - }, - labelKey: { - helpEntries: 'labelKey', - placeholder: L._('Default: name'), - label: L._('Label key'), - inheritable: true, - }, - zoomControl: { handler: 'ControlChoice', label: L._('Display the zoom control') }, - searchControl: { - handler: 'ControlChoice', - label: L._('Display the search control'), - }, - fullscreenControl: { - handler: 'ControlChoice', - label: L._('Display the fullscreen control'), - }, - embedControl: { handler: 'ControlChoice', label: L._('Display the embed control') }, - locateControl: { - handler: 'ControlChoice', - label: L._('Display the locate control'), - }, - measureControl: { - handler: 'ControlChoice', - label: L._('Display the measure control'), - }, - tilelayersControl: { - handler: 'ControlChoice', - label: L._('Display the tile layers control'), - }, - editinosmControl: { - handler: 'ControlChoice', - label: L._('Display the control to open OpenStreetMap editor'), - }, - datalayersControl: { - handler: 'DataLayersControl', - label: L._('Display the data layers control'), - }, - starControl: { - handler: 'ControlChoice', - label: L._('Display the star map button'), - }, - fromZoom: { - handler: 'IntInput', - label: L._('From zoom'), - helpText: L._('Optional.'), - }, - toZoom: { handler: 'IntInput', label: L._('To zoom'), helpText: L._('Optional.') }, - interactive: { - handler: 'Switch', - label: L._('Allow interactions'), - helpEntries: 'interactive', - inheritable: true, - }, + color: { handler: 'ColorPicker' }, + fillColor: { handler: 'ColorPicker' }, + iconUrl: { handler: 'IconUrl' }, + datalayer: { handler: 'DataLayerSwitcher' }, + datalayersControl: { handler: 'DataLayersControl' }, + licence: { handler: 'LicenceChooser' }, + }, + + computeDefaultOptions: function () { + for (let [key, schema] of Object.entries(U.SCHEMA)) { + schema = L.Util.extend({}, schema, this.defaultOptions[key]) + if (!schema.handler) { + if (schema.type === Boolean) { + if (schema.nullable) schema.handler = 'NullableChoices' + else schema.handler = 'Switch' + } else if (schema.type === 'Text') { + schema.handler = 'Textarea' + } else if (schema.type === Number) { + if (schema.step) schema.handler = 'Range' + else schema.handler = 'IntInput' + } else if (schema.choices) { + if (schema.choices.length <= 5) { + schema.handler = 'MultiChoice' + } else { + schema.handler = 'Select' + schema.selectOptions = schema.choices + } + } + } + // FormBuilder use this key for the input type itself + delete schema.type + this.defaultOptions[key] = schema + } }, initialize: function (obj, fields, options) { this.map = obj.map || obj.getMap() - for (const [key, schema] of Object.entries(U.SCHEMA)) { - this.defaultOptions[key] = this.defaultOptions[key] || schema - } + this.computeDefaultOptions() L.FormBuilder.prototype.initialize.call(this, obj, fields, options) this.on('finish', this.finish) }, diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index c503c418..2fe72afb 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -271,13 +271,11 @@ U.Map = L.Map.extend({ // FIXME retrocompat L.Util.setBooleanFromQueryString(options, 'displayDataBrowserOnLoad') L.Util.setBooleanFromQueryString(options, 'displayCaptionOnLoad') - for (const [key, { type }] of Object.entries(U.SCHEMA)) { - switch (type) { + for (const [key, schema] of Object.entries(U.SCHEMA)) { + switch (schema.type) { case Boolean: - L.Util.setBooleanFromQueryString(options, key) - break - case 'NullableBoolean': - L.Util.setNullableBooleanFromQueryString(options, key) + if (schema.nullable) L.Util.setNullableBooleanFromQueryString(options, key) + else L.Util.setBooleanFromQueryString(options, key) break case Number: L.Util.setNumberFromQueryString(options, key) @@ -1497,35 +1495,11 @@ U.Map = L.Map.extend({ _editCredits: function (container) { const credits = L.DomUtil.createFieldset(container, L._('Credits')) const creditsFields = [ - ['options.licence', { handler: 'LicenceChooser', label: L._('licence') }], - [ - 'options.shortCredit', - { - handler: 'Input', - label: L._('Short credits'), - helpEntries: ['shortCredit', 'textFormatting'], - }, - ], - [ - 'options.longCredit', - { - handler: 'Textarea', - label: L._('Long credits'), - helpEntries: ['longCredit', 'textFormatting'], - }, - ], - [ - 'options.permanentCredit', - { - handler: 'Textarea', - label: L._('Permanent credits'), - helpEntries: ['permanentCredit', 'textFormatting'], - }, - ], - [ - 'options.permanentCreditBackground', - { handler: 'Switch', label: L._('Permanent credits background') }, - ], + 'options.licence', + 'options.shortCredit', + 'options.longCredit', + 'options.permanentCredit', + 'options.permanentCreditBackground', ] const creditsBuilder = new U.FormBuilder(this, creditsFields, { callback: this.renderControls, From da945cf733ebf751eab37e8391d7f64c85e7d4c4 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 28 Feb 2024 18:21:49 +0100 Subject: [PATCH 04/11] wip: remove Leaflet.i18n from frontend and expose L._ But we keep Leaflet.i18n for now, as we use its script to collect strings (this script to be tweaked to support also `translate`). --- umap/static/umap/js/modules/i18n.js | 4 ++-- umap/static/umap/js/modules/leaflet-configure.js | 1 + umap/static/umap/test/index.html | 1 - umap/templates/umap/js.html | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/umap/static/umap/js/modules/i18n.js b/umap/static/umap/js/modules/i18n.js index d2b6b429..02c90997 100644 --- a/umap/static/umap/js/modules/i18n.js +++ b/umap/static/umap/js/modules/i18n.js @@ -1,7 +1,7 @@ // Comes from https://github.com/Leaflet/Leaflet/pull/9281 import { Util } from '../../vendors/leaflet/leaflet-src.esm.js' -const locales = {} +export const locales = {} // @property locale: String // The current locale code, that will be used when translating strings. @@ -19,7 +19,7 @@ export function setLocale(code) { } // @function translate(string: String, data?: Object): String // Actually try to translate the `string`, with optionnal variable passed in `data`. -export function translate(string, data) { +export function translate(string, data = {}) { if (locale && locales[locale] && locales[locale][string] !== undefined) { string = locales[locale][string] } diff --git a/umap/static/umap/js/modules/leaflet-configure.js b/umap/static/umap/js/modules/leaflet-configure.js index 9679f3f4..b7b502ff 100644 --- a/umap/static/umap/js/modules/leaflet-configure.js +++ b/umap/static/umap/js/modules/leaflet-configure.js @@ -4,3 +4,4 @@ import * as L from '../../vendors/leaflet/leaflet-src.esm.js' import * as i18n from './i18n.js' window.L = { ...L, ...i18n } +window.L._ = i18n.translate diff --git a/umap/static/umap/test/index.html b/umap/static/umap/test/index.html index 9d6da7d4..e01794a3 100644 --- a/umap/static/umap/test/index.html +++ b/umap/static/umap/test/index.html @@ -8,7 +8,6 @@ - diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html index bcc700f0..86ea502e 100644 --- a/umap/templates/umap/js.html +++ b/umap/templates/umap/js.html @@ -12,7 +12,6 @@ -