mirror of
https://github.com/umap-project/umap.git
synced 2025-05-05 22:11:50 +02:00
Compare commits
20 commits
64c7fe1ec9
...
8292608365
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8292608365 | ||
![]() |
ae8cbf39ad | ||
![]() |
7c5d821ec8 | ||
![]() |
4e9e828c8f | ||
![]() |
79d60d0995 | ||
![]() |
75457b6d5c | ||
![]() |
8538db278d | ||
![]() |
ba9e8ffe9b | ||
![]() |
dcf5f1a763 | ||
![]() |
41264e740f | ||
![]() |
953b37a181 | ||
![]() |
9eaf33c118 | ||
![]() |
f2cde6af4e | ||
![]() |
a4abecbd2c | ||
![]() |
254a2018f5 | ||
![]() |
3df52e002d | ||
![]() |
82208d618a | ||
![]() |
e993aa7dbc | ||
![]() |
ecca66ccc2 | ||
![]() |
360ca100ba |
50 changed files with 277 additions and 188 deletions
|
@ -5,7 +5,7 @@
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2020,
|
"ecmaVersion": 2021,
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
biome.json
14
biome.json
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"include": [
|
"include": ["umap/static/umap/js/**"],
|
||||||
"umap/static/umap/js/**"
|
"ignore": ["umap/static/umap/vendors/**"]
|
||||||
],
|
|
||||||
"ignore": [
|
|
||||||
"umap/static/umap/vendors/**"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
@ -22,7 +18,11 @@
|
||||||
"rules": {
|
"rules": {
|
||||||
"style": {
|
"style": {
|
||||||
"useBlockStatements": "off",
|
"useBlockStatements": "off",
|
||||||
"noShoutyConstants": "warn"
|
"noShoutyConstants": "warn",
|
||||||
|
"noParameterAssign": "off"
|
||||||
|
},
|
||||||
|
"complexity": {
|
||||||
|
"noForEach": "off"
|
||||||
},
|
},
|
||||||
"performance": {
|
"performance": {
|
||||||
"noDelete": "off"
|
"noDelete": "off"
|
||||||
|
|
|
@ -526,7 +526,10 @@ class DataLayer(NamedModel):
|
||||||
metadata = self.settings
|
metadata = self.settings
|
||||||
if not metadata:
|
if not metadata:
|
||||||
# Fallback to file for old datalayers.
|
# Fallback to file for old datalayers.
|
||||||
|
try:
|
||||||
data = json.loads(self.geojson.read().decode())
|
data = json.loads(self.geojson.read().decode())
|
||||||
|
except FileNotFoundError:
|
||||||
|
data = {}
|
||||||
metadata = data.get("_umap_options")
|
metadata = data.get("_umap_options")
|
||||||
if not metadata:
|
if not metadata:
|
||||||
metadata = {
|
metadata = {
|
||||||
|
|
|
@ -84,6 +84,11 @@ hgroup {
|
||||||
hgroup > :not(:first-child):last-child {
|
hgroup > :not(:first-child):last-child {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
hgroup p,
|
||||||
|
hgroup button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List
|
* List
|
||||||
|
@ -158,10 +163,23 @@ dt {
|
||||||
}
|
}
|
||||||
.grid-container {
|
.grid-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
--grid-layout-gap: calc(var(--gutter) * 2);
|
||||||
|
--grid-column-count: 3;
|
||||||
|
--grid-item--min-width: 300px;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated values.
|
||||||
|
*/
|
||||||
|
--gap-count: calc(var(--grid-column-count) - 1);
|
||||||
|
--total-gap-width: calc(var(--gap-count) * var(--grid-layout-gap));
|
||||||
|
--grid-item--max-width: calc((100% - var(--total-gap-width)) / var(--grid-column-count));
|
||||||
|
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(max(var(--grid-item--min-width), var(--grid-item--max-width)), 1fr));
|
||||||
|
grid-gap: var(--grid-layout-gap);
|
||||||
}
|
}
|
||||||
.grid-container.by4 {
|
.grid-container.by4 {
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
--grid-column-count: 4;
|
||||||
|
--grid-item--min-width: 60px;
|
||||||
}
|
}
|
||||||
.grid-container > * {
|
.grid-container > * {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -56,9 +56,9 @@ body.login header {
|
||||||
.map_fragment {
|
.map_fragment {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.map_list .map_fragment,
|
.map_fragment,
|
||||||
.demo_map .map_fragment {
|
.demo_map .map_fragment {
|
||||||
height: 210px;
|
height: var(--map-fragment-height);
|
||||||
}
|
}
|
||||||
.map_list .legend {
|
.map_list .legend {
|
||||||
padding-top: 7px;
|
padding-top: 7px;
|
||||||
|
@ -164,6 +164,9 @@ h2.tabs a:hover {
|
||||||
color: #efefef;
|
color: #efefef;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
.more_button {
|
||||||
|
min-height: var(--map-fragment-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* **************************** */
|
/* **************************** */
|
||||||
|
|
|
@ -163,11 +163,13 @@
|
||||||
.umap-main-edit-toolbox h3 {
|
.umap-main-edit-toolbox h3 {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
.umap-caption-bar button {
|
.umap-caption-bar .umap-map-author {
|
||||||
margin-inline-start: 10px;
|
margin-inline-end: 10px;
|
||||||
}
|
}
|
||||||
.umap-caption-bar button + button:before {
|
.umap-caption-bar > button + button:after,
|
||||||
|
.umap-caption-bar > button + button:before {
|
||||||
content: '|';
|
content: '|';
|
||||||
|
padding-inline-start: 10px;
|
||||||
padding-inline-end: 10px;
|
padding-inline-end: 10px;
|
||||||
}
|
}
|
||||||
.umap-main-edit-toolbox .umap-user:hover {
|
.umap-main-edit-toolbox .umap-user:hover {
|
||||||
|
@ -196,7 +198,14 @@
|
||||||
z-index: var(--zindex-panels);
|
z-index: var(--zindex-panels);
|
||||||
}
|
}
|
||||||
.umap-caption-bar-enabled .umap-caption-bar {
|
.umap-caption-bar-enabled .umap-caption-bar {
|
||||||
display: block;
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
.umap-caption-bar select {
|
||||||
|
margin-top: 0;
|
||||||
|
line-height: initial;
|
||||||
|
height: initial;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
.umap-caption-bar-enabled {
|
.umap-caption-bar-enabled {
|
||||||
--current-footer-height: var(--footer-height);
|
--current-footer-height: var(--footer-height);
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
}
|
}
|
||||||
|
.umap-dialog ul + h4 {
|
||||||
|
margin-top: var(--box-margin);
|
||||||
|
}
|
||||||
:where([data-component="no-dialog"]:not([hidden])) {
|
:where([data-component="no-dialog"]:not([hidden])) {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -140,7 +140,6 @@ class uMapAlertConflict extends uMapAlert {
|
||||||
}
|
}
|
||||||
|
|
||||||
onAlertConflict(event) {
|
onAlertConflict(event) {
|
||||||
// biome-ignore lint/style/useNumberNamespace: Number.Infinity returns undefined by default
|
|
||||||
const {
|
const {
|
||||||
level = 'info',
|
level = 'info',
|
||||||
duration = Number.POSITIVE_INFINITY,
|
duration = Number.POSITIVE_INFINITY,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { Form } from './form/builder.js'
|
||||||
|
import { EXPORT_FORMATS } from './formatter.js'
|
||||||
import { translate } from './i18n.js'
|
import { translate } from './i18n.js'
|
||||||
import * as Icon from './rendering/icon.js'
|
import * as Icon from './rendering/icon.js'
|
||||||
import * as Utils from './utils.js'
|
|
||||||
import { EXPORT_FORMATS } from './formatter.js'
|
|
||||||
import ContextMenu from './ui/contextmenu.js'
|
import ContextMenu from './ui/contextmenu.js'
|
||||||
import { Form } from './form/builder.js'
|
import * as Utils from './utils.js'
|
||||||
|
|
||||||
export default class Browser {
|
export default class Browser {
|
||||||
constructor(umap, leafletMap) {
|
constructor(umap, leafletMap) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
||||||
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">
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import {
|
import {
|
||||||
DomUtil,
|
|
||||||
DomEvent,
|
DomEvent,
|
||||||
stamp,
|
DomUtil,
|
||||||
GeoJSON,
|
GeoJSON,
|
||||||
LineUtil,
|
LineUtil,
|
||||||
|
stamp,
|
||||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import * as Utils from '../utils.js'
|
|
||||||
import { SCHEMA } from '../schema.js'
|
|
||||||
import { translate } from '../i18n.js'
|
|
||||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||||
|
import { MutatingForm } from '../form/builder.js'
|
||||||
|
import { translate } from '../i18n.js'
|
||||||
|
import loadPopup from '../rendering/popup.js'
|
||||||
import {
|
import {
|
||||||
LeafletMarker,
|
LeafletMarker,
|
||||||
LeafletPolyline,
|
|
||||||
LeafletPolygon,
|
LeafletPolygon,
|
||||||
|
LeafletPolyline,
|
||||||
MaskPolygon,
|
MaskPolygon,
|
||||||
} from '../rendering/ui.js'
|
} from '../rendering/ui.js'
|
||||||
import loadPopup from '../rendering/popup.js'
|
import { SCHEMA } from '../schema.js'
|
||||||
import { MutatingForm } from '../form/builder.js'
|
import * as Utils from '../utils.js'
|
||||||
|
|
||||||
class Feature {
|
class Feature {
|
||||||
constructor(umap, datalayer, geojson = {}, id = null) {
|
constructor(umap, datalayer, geojson = {}, id = null) {
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
// FIXME: this module should not depend on Leaflet
|
// FIXME: this module should not depend on Leaflet
|
||||||
import {
|
import {
|
||||||
DomUtil,
|
|
||||||
DomEvent,
|
DomEvent,
|
||||||
stamp,
|
DomUtil,
|
||||||
GeoJSON,
|
GeoJSON,
|
||||||
|
stamp,
|
||||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import * as Utils from '../utils.js'
|
|
||||||
import { Default as DefaultLayer } from '../rendering/layers/base.js'
|
|
||||||
import { Cluster } from '../rendering/layers/cluster.js'
|
|
||||||
import { Heat } from '../rendering/layers/heat.js'
|
|
||||||
import { Categorized, Choropleth, Circles } from '../rendering/layers/classified.js'
|
|
||||||
import {
|
import {
|
||||||
uMapAlert as Alert,
|
uMapAlert as Alert,
|
||||||
uMapAlertConflict as AlertConflict,
|
uMapAlertConflict as AlertConflict,
|
||||||
} from '../../components/alerts/alert.js'
|
} from '../../components/alerts/alert.js'
|
||||||
|
import { MutatingForm } from '../form/builder.js'
|
||||||
import { translate } from '../i18n.js'
|
import { translate } from '../i18n.js'
|
||||||
import { DataLayerPermissions } from '../permissions.js'
|
import { DataLayerPermissions } from '../permissions.js'
|
||||||
import { Point, LineString, Polygon } from './features.js'
|
import { Default as DefaultLayer } from '../rendering/layers/base.js'
|
||||||
import TableEditor from '../tableeditor.js'
|
import { Categorized, Choropleth, Circles } from '../rendering/layers/classified.js'
|
||||||
|
import { Cluster } from '../rendering/layers/cluster.js'
|
||||||
|
import { Heat } from '../rendering/layers/heat.js'
|
||||||
import { ServerStored } from '../saving.js'
|
import { ServerStored } from '../saving.js'
|
||||||
import * as Schema from '../schema.js'
|
import * as Schema from '../schema.js'
|
||||||
import { MutatingForm } from '../form/builder.js'
|
import TableEditor from '../tableeditor.js'
|
||||||
|
import * as Utils from '../utils.js'
|
||||||
|
import { LineString, Point, Polygon } from './features.js'
|
||||||
|
|
||||||
export const LAYER_TYPES = [
|
export const LAYER_TYPES = [
|
||||||
DefaultLayer,
|
DefaultLayer,
|
||||||
|
@ -966,12 +966,18 @@ export class DataLayer extends ServerStored {
|
||||||
this.propagateHide()
|
this.propagateHide()
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle() {
|
toggle(force) {
|
||||||
// From now on, do not try to how/hidedataChanged
|
// From now on, do not try to how/hidedataChanged
|
||||||
// automatically this layer.
|
// automatically this layer.
|
||||||
|
let display = force
|
||||||
this._forcedVisibility = true
|
this._forcedVisibility = true
|
||||||
if (!this.isVisible()) this.show()
|
if (force === undefined) {
|
||||||
|
if (!this.isVisible()) display = true
|
||||||
|
else display = false
|
||||||
|
}
|
||||||
|
if (display) this.show()
|
||||||
else this.hide()
|
else this.hide()
|
||||||
|
this._umap.bottomBar.redraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomTo() {
|
zoomTo() {
|
||||||
|
@ -1258,7 +1264,7 @@ export class DataLayer extends ServerStored {
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DomEvent.on(toggle, 'click', this.toggle, this)
|
DomEvent.on(toggle, 'click', () => this.toggle())
|
||||||
DomEvent.on(zoomTo, 'click', this.zoomTo, this)
|
DomEvent.on(zoomTo, 'click', this.zoomTo, this)
|
||||||
container.classList.add(this.getHidableClass())
|
container.classList.add(this.getHidableClass())
|
||||||
container.classList.toggle('off', !this.isVisible())
|
container.classList.toggle('off', !this.isVisible())
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import getClass from './fields.js'
|
|
||||||
import * as Utils from '../utils.js'
|
|
||||||
import { SCHEMA } from '../schema.js'
|
|
||||||
import { translate } from '../i18n.js'
|
import { translate } from '../i18n.js'
|
||||||
|
import { SCHEMA } from '../schema.js'
|
||||||
|
import * as Utils from '../utils.js'
|
||||||
|
import getClass from './fields.js'
|
||||||
|
|
||||||
export class Form extends Utils.WithEvents {
|
export class Form extends Utils.WithEvents {
|
||||||
constructor(obj, fields, properties) {
|
constructor(obj, fields, properties) {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import * as Utils from '../utils.js'
|
|
||||||
import { translate } from '../i18n.js'
|
|
||||||
import {
|
import {
|
||||||
AjaxAutocomplete,
|
AjaxAutocomplete,
|
||||||
AjaxAutocompleteMultiple,
|
AjaxAutocompleteMultiple,
|
||||||
AutocompleteDatalist,
|
AutocompleteDatalist,
|
||||||
} from '../autocomplete.js'
|
} from '../autocomplete.js'
|
||||||
import { SCHEMA } from '../schema.js'
|
import { translate } from '../i18n.js'
|
||||||
import * as Icon from '../rendering/icon.js'
|
import * as Icon from '../rendering/icon.js'
|
||||||
|
import { SCHEMA } from '../schema.js'
|
||||||
|
import * as Utils from '../utils.js'
|
||||||
|
|
||||||
const Fields = {}
|
const Fields = {}
|
||||||
|
|
||||||
|
@ -254,8 +254,8 @@ Fields.BlurInput = class extends Fields.Input {
|
||||||
const IntegerMixin = (Base) =>
|
const IntegerMixin = (Base) =>
|
||||||
class extends Base {
|
class extends Base {
|
||||||
value() {
|
value() {
|
||||||
return !isNaN(this.input.value) && this.input.value !== ''
|
return !Number.isNaN(this.input.value) && this.input.value !== ''
|
||||||
? parseInt(this.input.value, 10)
|
? Number.parseInt(this.input.value, 10)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,8 +270,8 @@ Fields.BlurIntInput = class extends IntegerMixin(Fields.BlurInput) {}
|
||||||
const FloatMixin = (Base) =>
|
const FloatMixin = (Base) =>
|
||||||
class extends Base {
|
class extends Base {
|
||||||
value() {
|
value() {
|
||||||
return !isNaN(this.input.value) && this.input.value !== ''
|
return !Number.isNaN(this.input.value) && this.input.value !== ''
|
||||||
? parseFloat(this.input.value)
|
? Number.parseFloat(this.input.value)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ Fields.Select = class extends BaseElement {
|
||||||
|
|
||||||
Fields.IntSelect = class extends Fields.Select {
|
Fields.IntSelect = class extends Fields.Select {
|
||||||
value() {
|
value() {
|
||||||
return parseInt(super.value(), 10)
|
return Number.parseInt(super.value(), 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
||||||
/* Uses globals for: csv2geojson, osmtogeojson (not available as ESM) */
|
/* Uses globals for: csv2geojson, osmtogeojson (not available as ESM) */
|
||||||
import { translate } from './i18n.js'
|
import { translate } from './i18n.js'
|
||||||
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
|
||||||
|
|
||||||
export const EXPORT_FORMATS = {
|
export const EXPORT_FORMATS = {
|
||||||
geojson: {
|
geojson: {
|
||||||
|
|
|
@ -4,14 +4,14 @@ import {
|
||||||
AjaxAutocompleteMultiple,
|
AjaxAutocompleteMultiple,
|
||||||
AutocompleteDatalist,
|
AutocompleteDatalist,
|
||||||
} from './autocomplete.js'
|
} from './autocomplete.js'
|
||||||
|
import { LineString, Point, Polygon } from './data/features.js'
|
||||||
|
import { LAYER_TYPES } from './data/layer.js'
|
||||||
import Help from './help.js'
|
import Help from './help.js'
|
||||||
|
import * as Icon from './rendering/icon.js'
|
||||||
|
import { LeafletMarker, LeafletPolygon, LeafletPolyline } from './rendering/ui.js'
|
||||||
import { ServerRequest } from './request.js'
|
import { ServerRequest } from './request.js'
|
||||||
import { SCHEMA } from './schema.js'
|
import { SCHEMA } from './schema.js'
|
||||||
import * as Utils from './utils.js'
|
import * as Utils from './utils.js'
|
||||||
import * as Icon from './rendering/icon.js'
|
|
||||||
import { LAYER_TYPES } from './data/layer.js'
|
|
||||||
import { Point, LineString, Polygon } from './data/features.js'
|
|
||||||
import { LeafletMarker, LeafletPolyline, LeafletPolygon } from './rendering/ui.js'
|
|
||||||
|
|
||||||
// Import modules and export them to the global scope.
|
// Import modules and export them to the global scope.
|
||||||
// For the not yet module-compatible JS out there.
|
// For the not yet module-compatible JS out there.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate } from './i18n.js'
|
import { translate } from './i18n.js'
|
||||||
import * as Utils from './utils.js'
|
|
||||||
import Dialog from './ui/dialog.js'
|
import Dialog from './ui/dialog.js'
|
||||||
|
import * as Utils from './utils.js'
|
||||||
|
|
||||||
const SHORTCUTS = {
|
const SHORTCUTS = {
|
||||||
DRAW_MARKER: {
|
DRAW_MARKER: {
|
||||||
|
@ -135,14 +135,23 @@ const ENTRIES = {
|
||||||
<li>${translate('# one hash for main heading')}</li>
|
<li>${translate('# one hash for main heading')}</li>
|
||||||
<li>${translate('## two hashes for second heading')}</li>
|
<li>${translate('## two hashes for second heading')}</li>
|
||||||
<li>${translate('### three hashes for third heading')}</li>
|
<li>${translate('### three hashes for third heading')}</li>
|
||||||
|
<li>${translate('--- for a horizontal rule')}</li>
|
||||||
|
</ul>
|
||||||
|
<h4>${translate('Links')}</h4>
|
||||||
|
<ul>
|
||||||
<li>${translate('Simple link: [[https://example.com]]')}</li>
|
<li>${translate('Simple link: [[https://example.com]]')}</li>
|
||||||
<li>${translate('Link with text: [[https://example.com|text of the link]]')}</li>
|
<li>${translate('Link with text: [[https://example.com|text of the link]]')}</li>
|
||||||
|
</ul>
|
||||||
|
<h4>${translate('Images')}</h4>
|
||||||
|
<ul>
|
||||||
<li>${translate('Image: {{https://image.url.com}}')}</li>
|
<li>${translate('Image: {{https://image.url.com}}')}</li>
|
||||||
<li>${translate('Image with custom width (in px): {{https://image.url.com|width}}')}</li>
|
<li>${translate('Image with custom width (in px): {{https://image.url.com|width}}')}</li>
|
||||||
|
</ul>
|
||||||
|
<h4>${translate('Iframes')}</h4>
|
||||||
|
<ul>
|
||||||
<li>${translate('Iframe: {{{https://iframe.url.com}}}')}</li>
|
<li>${translate('Iframe: {{{https://iframe.url.com}}}')}</li>
|
||||||
<li>${translate('Iframe with custom height (in px): {{{https://iframe.url.com|height}}}')}</li>
|
<li>${translate('Iframe with custom height (in px): {{{https://iframe.url.com|height}}}')}</li>
|
||||||
<li>${translate('Iframe with custom height and width (in px): {{{https://iframe.url.com|height*width}}}')}</li>
|
<li>${translate('Iframe with custom height and width (in px): {{{https://iframe.url.com|height*width}}}')}</li>
|
||||||
<li>${translate('--- for a horizontal rule')}</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||||
import { BaseAjax, SingleMixin } from '../autocomplete.js'
|
import { BaseAjax, SingleMixin } from '../autocomplete.js'
|
||||||
|
import { translate } from '../i18n.js'
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
import { AutocompleteCommunes } from './communesfr.js'
|
import { AutocompleteCommunes } from './communesfr.js'
|
||||||
import { translate } from '../i18n.js'
|
|
||||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
|
||||||
|
|
||||||
const TEMPLATE = `
|
const TEMPLATE = `
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||||
import { BaseAjax, SingleMixin } from '../autocomplete.js'
|
import { BaseAjax, SingleMixin } from '../autocomplete.js'
|
||||||
|
import { translate } from '../i18n.js'
|
||||||
import * as Util from '../utils.js'
|
import * as Util from '../utils.js'
|
||||||
import { AutocompleteCommunes } from './communesfr.js'
|
import { AutocompleteCommunes } from './communesfr.js'
|
||||||
import { translate } from '../i18n.js'
|
|
||||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
|
||||||
|
|
||||||
const TEMPLATE = `
|
const TEMPLATE = `
|
||||||
<h3>Cadastre</h3>
|
<h3>Cadastre</h3>
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class AutocompleteCommunes extends SingleMixin(BaseAjax) {
|
||||||
let options = { q: encodeURIComponent(value) }
|
let options = { q: encodeURIComponent(value) }
|
||||||
const re = /^(0[1-9]|[1-9][ABab\d])\d{3}$/gm
|
const re = /^(0[1-9]|[1-9][ABab\d])\d{3}$/gm
|
||||||
if (re.test(value)) {
|
if (re.test(value)) {
|
||||||
url = "https://geo.api.gouv.fr/communes?code={code}&limit=5"
|
url = 'https://geo.api.gouv.fr/communes?code={code}&limit=5'
|
||||||
options = { code: encodeURIComponent(value) }
|
options = { code: encodeURIComponent(value) }
|
||||||
}
|
}
|
||||||
return Util.template(url, options)
|
return Util.template(url, options)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate } from './i18n.js'
|
|
||||||
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
||||||
|
import { MutatingForm } from './form/builder.js'
|
||||||
|
import { translate } from './i18n.js'
|
||||||
import { ServerStored } from './saving.js'
|
import { ServerStored } from './saving.js'
|
||||||
import * as Utils from './utils.js'
|
import * as Utils from './utils.js'
|
||||||
import { MutatingForm } from './form/builder.js'
|
|
||||||
|
|
||||||
// Dedicated object so we can deal with a separate dirty status, and thus
|
// Dedicated object so we can deal with a separate dirty status, and thus
|
||||||
// call the endpoint only when needed, saving one call at each save.
|
// call the endpoint only when needed, saving one call at each save.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {
|
import {
|
||||||
|
DivIcon,
|
||||||
DomEvent,
|
DomEvent,
|
||||||
DomUtil,
|
DomUtil,
|
||||||
DivIcon,
|
|
||||||
Icon,
|
Icon,
|
||||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import * as Utils from '../utils.js'
|
|
||||||
import { SCHEMA } from '../schema.js'
|
import { SCHEMA } from '../schema.js'
|
||||||
|
import * as Utils from '../utils.js'
|
||||||
|
|
||||||
export function getClass(name) {
|
export function getClass(name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { FeatureGroup, DomUtil } from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
|
||||||
|
import { DomUtil, FeatureGroup } from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate } from '../../i18n.js'
|
import { translate } from '../../i18n.js'
|
||||||
import { LayerMixin } from './base.js'
|
|
||||||
import * as Utils from '../../utils.js'
|
import * as Utils from '../../utils.js'
|
||||||
import { CircleMarker } from '../ui.js'
|
import { CircleMarker } from '../ui.js'
|
||||||
import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
|
import { LayerMixin } from './base.js'
|
||||||
|
|
||||||
// Layer where each feature color is relative to the others,
|
// Layer where each feature color is relative to the others,
|
||||||
// so we need all features before behing able to set one
|
// so we need all features before behing able to set one
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import { Evented } from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
// WARNING must be loaded dynamically, or at least after leaflet.markercluster
|
// WARNING must be loaded dynamically, or at least after leaflet.markercluster
|
||||||
// Uses global L.MarkerCluster and L.MarkerClusterGroup, not exposed as ESM
|
// Uses global L.MarkerCluster and L.MarkerClusterGroup, not exposed as ESM
|
||||||
import { translate } from '../../i18n.js'
|
import { translate } from '../../i18n.js'
|
||||||
import { LayerMixin } from './base.js'
|
|
||||||
import * as Utils from '../../utils.js'
|
import * as Utils from '../../utils.js'
|
||||||
import { Evented } from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
|
||||||
import { Cluster as ClusterIcon } from '../icon.js'
|
import { Cluster as ClusterIcon } from '../icon.js'
|
||||||
|
import { LayerMixin } from './base.js'
|
||||||
|
|
||||||
const MarkerCluster = L.MarkerCluster.extend({
|
const MarkerCluster = L.MarkerCluster.extend({
|
||||||
// Custom class so we can call computeTextColor
|
// Custom class so we can call computeTextColor
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
// Uses global L.HeatLayer, not exposed as ESM
|
// Uses global L.HeatLayer, not exposed as ESM
|
||||||
import {
|
import {
|
||||||
Marker,
|
|
||||||
LatLng,
|
|
||||||
latLngBounds,
|
|
||||||
Bounds,
|
Bounds,
|
||||||
|
LatLng,
|
||||||
|
Marker,
|
||||||
|
latLngBounds,
|
||||||
point,
|
point,
|
||||||
} from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { LayerMixin } from './base.js'
|
|
||||||
import * as Utils from '../../utils.js'
|
|
||||||
import { translate } from '../../i18n.js'
|
import { translate } from '../../i18n.js'
|
||||||
|
import * as Utils from '../../utils.js'
|
||||||
|
import { LayerMixin } from './base.js'
|
||||||
|
|
||||||
export const Heat = L.HeatLayer.extend({
|
export const Heat = L.HeatLayer.extend({
|
||||||
statics: {
|
statics: {
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
// Goes here all code related to Leaflet, DOM and user interactions.
|
// Goes here all code related to Leaflet, DOM and user interactions.
|
||||||
import {
|
import {
|
||||||
Map as BaseMap,
|
Map as BaseMap,
|
||||||
DomUtil,
|
|
||||||
DomEvent,
|
|
||||||
latLngBounds,
|
|
||||||
latLng,
|
|
||||||
Control,
|
Control,
|
||||||
|
DomEvent,
|
||||||
|
DomUtil,
|
||||||
|
latLng,
|
||||||
|
latLngBounds,
|
||||||
setOptions,
|
setOptions,
|
||||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate } from '../i18n.js'
|
|
||||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||||
|
import DropControl from '../drop.js'
|
||||||
|
import { translate } from '../i18n.js'
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
import * as Icon from './icon.js'
|
import * as Icon from './icon.js'
|
||||||
import DropControl from '../drop.js'
|
|
||||||
|
|
||||||
// Those options are not saved on the server, so they can live here
|
// Those options are not saved on the server, so they can live here
|
||||||
// instead of in umap.properties
|
// instead of in umap.properties
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {
|
import {
|
||||||
|
Popup as BasePopup,
|
||||||
DomEvent,
|
DomEvent,
|
||||||
DomUtil,
|
DomUtil,
|
||||||
Path,
|
Path,
|
||||||
Popup as BasePopup,
|
|
||||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import loadTemplate from './template.js'
|
|
||||||
import Browser from '../browser.js'
|
import Browser from '../browser.js'
|
||||||
|
import loadTemplate from './template.js'
|
||||||
|
|
||||||
export default function loadPopup(name) {
|
export default function loadPopup(name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomEvent, DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate, getLocale } from '../i18n.js'
|
import { getLocale, translate } from '../i18n.js'
|
||||||
|
import { Request } from '../request.js'
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
import * as Icon from './icon.js'
|
import * as Icon from './icon.js'
|
||||||
import { Request } from '../request.js'
|
|
||||||
|
|
||||||
export default async function loadTemplate(name, feature, container) {
|
export default async function loadTemplate(name, feature, container) {
|
||||||
let klass = PopupTemplate
|
let klass = PopupTemplate
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
// Goes here all code related to Leaflet, DOM and user interactions.
|
// Goes here all code related to Leaflet, DOM and user interactions.
|
||||||
import {
|
import {
|
||||||
Marker,
|
|
||||||
Polyline,
|
|
||||||
Polygon,
|
|
||||||
CircleMarker as BaseCircleMarker,
|
CircleMarker as BaseCircleMarker,
|
||||||
|
DomEvent,
|
||||||
DomUtil,
|
DomUtil,
|
||||||
LineUtil,
|
|
||||||
latLng,
|
|
||||||
LatLng,
|
LatLng,
|
||||||
LatLngBounds,
|
LatLngBounds,
|
||||||
DomEvent,
|
LineUtil,
|
||||||
|
Marker,
|
||||||
|
Polygon,
|
||||||
|
Polyline,
|
||||||
|
latLng,
|
||||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate } from '../i18n.js'
|
|
||||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||||
|
import { translate } from '../i18n.js'
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
import * as Icon from './icon.js'
|
import * as Icon from './icon.js'
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate } from './i18n.js'
|
|
||||||
import * as Utils from './utils.js'
|
|
||||||
import { AutocompleteDatalist } from './autocomplete.js'
|
import { AutocompleteDatalist } from './autocomplete.js'
|
||||||
import Orderable from './orderable.js'
|
|
||||||
import { MutatingForm } from './form/builder.js'
|
import { MutatingForm } from './form/builder.js'
|
||||||
|
import { translate } from './i18n.js'
|
||||||
|
import Orderable from './orderable.js'
|
||||||
|
import * as Utils from './utils.js'
|
||||||
|
|
||||||
const EMPTY_VALUES = ['', undefined, null]
|
const EMPTY_VALUES = ['', undefined, null]
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { MutatingForm } from './form/builder.js'
|
||||||
import { EXPORT_FORMATS } from './formatter.js'
|
import { EXPORT_FORMATS } from './formatter.js'
|
||||||
import { translate } from './i18n.js'
|
import { translate } from './i18n.js'
|
||||||
import * as Utils from './utils.js'
|
import * as Utils from './utils.js'
|
||||||
import { MutatingForm } from './form/builder.js'
|
|
||||||
|
|
||||||
export default class Share {
|
export default class Share {
|
||||||
constructor(umap) {
|
constructor(umap) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ export default class Slideshow extends WithTemplate {
|
||||||
this._umap = umap
|
this._umap = umap
|
||||||
this._id = null
|
this._id = null
|
||||||
this.CLASSNAME = 'umap-slideshow-active'
|
this.CLASSNAME = 'umap-slideshow-active'
|
||||||
|
this._umap.properties.slideshow ??= {}
|
||||||
this.load()
|
this.load()
|
||||||
this._current = null
|
this._current = null
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import * as SaveManager from '../saving.js'
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
import { HybridLogicalClock } from './hlc.js'
|
import { HybridLogicalClock } from './hlc.js'
|
||||||
import { DataLayerUpdater, FeatureUpdater, MapUpdater } from './updaters.js'
|
import { DataLayerUpdater, FeatureUpdater, MapUpdater } from './updaters.js'
|
||||||
import { WebSocketTransport } from './websocket.js'
|
import { WebSocketTransport } from './websocket.js'
|
||||||
import * as SaveManager from '../saving.js'
|
|
||||||
|
|
||||||
// Start reconnecting after 2 seconds, then double the delay each time
|
// Start reconnecting after 2 seconds, then double the delay each time
|
||||||
// maxing out at 32 seconds.
|
// maxing out at 32 seconds.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { MutatingForm } from './form/builder.js'
|
||||||
import { translate } from './i18n.js'
|
import { translate } from './i18n.js'
|
||||||
import ContextMenu from './ui/contextmenu.js'
|
import ContextMenu from './ui/contextmenu.js'
|
||||||
import { WithTemplate, loadTemplate } from './utils.js'
|
import { WithTemplate, loadTemplate } from './utils.js'
|
||||||
import { MutatingForm } from './form/builder.js'
|
|
||||||
|
|
||||||
const TEMPLATE = `
|
const TEMPLATE = `
|
||||||
<table>
|
<table>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { LineString, Point, Polygon } from '../data/features.js'
|
||||||
import { translate } from '../i18n.js'
|
import { translate } from '../i18n.js'
|
||||||
import { WithTemplate } from '../utils.js'
|
import { WithTemplate } from '../utils.js'
|
||||||
import ContextMenu from './contextmenu.js'
|
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
import { Point, LineString, Polygon } from '../data/features.js'
|
import ContextMenu from './contextmenu.js'
|
||||||
|
|
||||||
const TOP_BAR_TEMPLATE = `
|
const TOP_BAR_TEMPLATE = `
|
||||||
<div class="umap-main-edit-toolbox with-transition dark">
|
<div class="umap-main-edit-toolbox with-transition dark">
|
||||||
|
@ -167,6 +167,7 @@ const BOTTOM_BAR_TEMPLATE = `
|
||||||
<button class="umap-about-link flat" type="button" title="${translate('Open caption')}" data-ref="caption">${translate('Open caption')}</button>
|
<button class="umap-about-link flat" type="button" title="${translate('Open caption')}" data-ref="caption">${translate('Open caption')}</button>
|
||||||
<button class="umap-open-browser-link flat" type="button" title="${translate('Browse data')}" data-ref="browse">${translate('Browse data')}</button>
|
<button class="umap-open-browser-link flat" type="button" title="${translate('Browse data')}" data-ref="browse">${translate('Browse data')}</button>
|
||||||
<button class="umap-open-browser-link flat" type="button" title="${translate('Filter data')}" data-ref="filter">${translate('Filter data')}</button>
|
<button class="umap-open-browser-link flat" type="button" title="${translate('Filter data')}" data-ref="filter">${translate('Filter data')}</button>
|
||||||
|
<select data-ref=layers></select>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -189,6 +190,14 @@ export class BottomBar extends WithTemplate {
|
||||||
this._umap.openBrowser('filters')
|
this._umap.openBrowser('filters')
|
||||||
)
|
)
|
||||||
this._slideshow.renderToolbox(this.element)
|
this._slideshow.renderToolbox(this.element)
|
||||||
|
this.elements.layers.addEventListener('change', () => {
|
||||||
|
const select = this.elements.layers
|
||||||
|
const selected = select.options[select.selectedIndex].value
|
||||||
|
if (!selected) return
|
||||||
|
this._umap.eachDataLayer((datalayer) => {
|
||||||
|
datalayer.toggle(datalayer.id === selected)
|
||||||
|
})
|
||||||
|
})
|
||||||
this.redraw()
|
this.redraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +210,27 @@ export class BottomBar extends WithTemplate {
|
||||||
this.elements.caption.hidden = !showMenus
|
this.elements.caption.hidden = !showMenus
|
||||||
this.elements.browse.hidden = !showMenus
|
this.elements.browse.hidden = !showMenus
|
||||||
this.elements.filter.hidden = !showMenus || !this._umap.properties.facetKey
|
this.elements.filter.hidden = !showMenus || !this._umap.properties.facetKey
|
||||||
|
this.buildDataLayerSwitcher()
|
||||||
|
}
|
||||||
|
|
||||||
|
buildDataLayerSwitcher() {
|
||||||
|
this.elements.layers.innerHTML = ''
|
||||||
|
const datalayers = this._umap.datalayersIndex.filter((d) => d.options.inCaption)
|
||||||
|
if (datalayers.length < 2) {
|
||||||
|
this.elements.layers.hidden = true
|
||||||
|
} else {
|
||||||
|
this.elements.layers.appendChild(Utils.loadTemplate(`<option value=""></option>`))
|
||||||
|
this.elements.layers.hidden = false
|
||||||
|
const visible = datalayers.filter((datalayer) => datalayer.isVisible())
|
||||||
|
for (const datalayer of datalayers) {
|
||||||
|
const selected = visible.length === 1 && datalayer.isVisible() ? 'selected' : ''
|
||||||
|
this.elements.layers.appendChild(
|
||||||
|
Utils.loadTemplate(
|
||||||
|
`<option value="${datalayer.id}" ${selected}>${datalayer.getName()}</option>`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate } from '../i18n.js'
|
import { translate } from '../i18n.js'
|
||||||
import { Positioned } from './base.js'
|
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
|
import { Positioned } from './base.js'
|
||||||
|
|
||||||
export default class Tooltip extends Positioned {
|
export default class Tooltip extends Positioned {
|
||||||
constructor(parent) {
|
constructor(parent) {
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
import {
|
import {
|
||||||
DomUtil,
|
DomUtil,
|
||||||
Util as LeafletUtil,
|
Util as LeafletUtil,
|
||||||
stamp,
|
|
||||||
latLngBounds,
|
latLngBounds,
|
||||||
|
stamp,
|
||||||
} from '../../vendors/leaflet/leaflet-src.esm.js'
|
} from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate, setLocale, getLocale } from './i18n.js'
|
import {
|
||||||
import * as Utils from './utils.js'
|
uMapAlert as Alert,
|
||||||
import { ServerStored } from './saving.js'
|
uMapAlertCreation as AlertCreation,
|
||||||
import * as SAVEMANAGER from './saving.js'
|
} from '../components/alerts/alert.js'
|
||||||
import { SyncEngine } from './sync/engine.js'
|
|
||||||
import { LeafletMap } from './rendering/map.js'
|
|
||||||
import URLs from './urls.js'
|
|
||||||
import { Panel, EditPanel, FullPanel } from './ui/panel.js'
|
|
||||||
import Dialog from './ui/dialog.js'
|
|
||||||
import { BottomBar, TopBar, EditBar } from './ui/bar.js'
|
|
||||||
import Tooltip from './ui/tooltip.js'
|
|
||||||
import ContextMenu from './ui/contextmenu.js'
|
|
||||||
import { Request, ServerRequest } from './request.js'
|
|
||||||
import Help from './help.js'
|
|
||||||
import { Formatter } from './formatter.js'
|
|
||||||
import Slideshow from './slideshow.js'
|
|
||||||
import { MapPermissions } from './permissions.js'
|
|
||||||
import { SCHEMA } from './schema.js'
|
|
||||||
import { DataLayer } from './data/layer.js'
|
|
||||||
import Facets from './facets.js'
|
|
||||||
import Browser from './browser.js'
|
import Browser from './browser.js'
|
||||||
import Caption from './caption.js'
|
import Caption from './caption.js'
|
||||||
import Importer from './importer.js'
|
import { DataLayer } from './data/layer.js'
|
||||||
import Rules from './rules.js'
|
import Facets from './facets.js'
|
||||||
import Share from './share.js'
|
|
||||||
import {
|
|
||||||
uMapAlertCreation as AlertCreation,
|
|
||||||
uMapAlert as Alert,
|
|
||||||
} from '../components/alerts/alert.js'
|
|
||||||
import Orderable from './orderable.js'
|
|
||||||
import { MutatingForm } from './form/builder.js'
|
import { MutatingForm } from './form/builder.js'
|
||||||
|
import { Formatter } from './formatter.js'
|
||||||
|
import Help from './help.js'
|
||||||
|
import { getLocale, setLocale, translate } from './i18n.js'
|
||||||
|
import Importer from './importer.js'
|
||||||
|
import Orderable from './orderable.js'
|
||||||
|
import { MapPermissions } from './permissions.js'
|
||||||
|
import { LeafletMap } from './rendering/map.js'
|
||||||
|
import { Request, ServerRequest } from './request.js'
|
||||||
|
import Rules from './rules.js'
|
||||||
|
import { ServerStored } from './saving.js'
|
||||||
|
import * as SAVEMANAGER from './saving.js'
|
||||||
|
import { SCHEMA } from './schema.js'
|
||||||
|
import Share from './share.js'
|
||||||
|
import Slideshow from './slideshow.js'
|
||||||
|
import { SyncEngine } from './sync/engine.js'
|
||||||
|
import { BottomBar, EditBar, TopBar } from './ui/bar.js'
|
||||||
|
import ContextMenu from './ui/contextmenu.js'
|
||||||
|
import Dialog from './ui/dialog.js'
|
||||||
|
import { EditPanel, FullPanel, Panel } from './ui/panel.js'
|
||||||
|
import Tooltip from './ui/tooltip.js'
|
||||||
|
import URLs from './urls.js'
|
||||||
|
import * as Utils from './utils.js'
|
||||||
|
|
||||||
export default class Umap extends ServerStored {
|
export default class Umap extends ServerStored {
|
||||||
constructor(element, geojson) {
|
constructor(element, geojson) {
|
||||||
|
|
|
@ -368,10 +368,13 @@ export function isDataImage(value) {
|
||||||
* characters and no diacritics.
|
* characters and no diacritics.
|
||||||
*/
|
*/
|
||||||
export function normalize(s) {
|
export function normalize(s) {
|
||||||
return (s || '')
|
return (
|
||||||
|
(s || '')
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.normalize('NFD')
|
.normalize('NFD')
|
||||||
|
// biome-ignore lint/suspicious/noMisleadingCharacterClass: <explanation>
|
||||||
.replace(/[\u0300-\u036f]/g, '')
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vendorized from leaflet.utils
|
// Vendorized from leaflet.utils
|
||||||
|
|
|
@ -660,10 +660,6 @@ a.umap-control-caption,
|
||||||
.umap-caption .header i.icon {
|
.umap-caption .header i.icon {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.umap-caption hgroup p,
|
|
||||||
.umap-caption hgroup button {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.umap-browser .main-toolbox {
|
.umap-browser .main-toolbox {
|
||||||
padding-left: 4px; /* Align with toolbox below */
|
padding-left: 4px; /* Align with toolbox below */
|
||||||
border-top: 1px solid var(--color-mediumGray);
|
border-top: 1px solid var(--color-mediumGray);
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
--box-margin: 14px;
|
--box-margin: 14px;
|
||||||
--text-margin: 7px;
|
--text-margin: 7px;
|
||||||
--dialog-width: 40vw;
|
--dialog-width: 40vw;
|
||||||
|
--map-fragment-height: 210px;
|
||||||
|
|
||||||
/* z-indexes (leaflet CSS sets the map at 400 by default) */
|
/* z-indexes (leaflet CSS sets the map at 400 by default) */
|
||||||
--zindex-alert: 500;
|
--zindex-alert: 500;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="map_list row">
|
<div class="row grid-container">
|
||||||
{% if maps %}
|
{% if maps %}
|
||||||
{% include "umap/map_list.html" %}
|
{% include "umap/map_list.html" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="map_list row">
|
<div class="grid-container row">
|
||||||
{% if maps %}
|
{% if maps %}
|
||||||
{% include "umap/map_list.html" %}
|
{% include "umap/map_list.html" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -43,22 +43,27 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.addEventListener('DOMContentLoaded', event => {
|
window.addEventListener('DOMContentLoaded', event => {
|
||||||
const server = new U.ServerRequest()
|
const server = new U.ServerRequest()
|
||||||
const getMore = async function (e) {
|
const getMore = async function (link) {
|
||||||
L.DomEvent.stop(e)
|
const container = link.parentNode
|
||||||
const [{html}, response, error] = await server.get(this.href)
|
container.removeChild(link)
|
||||||
|
const [{html}, response, error] = await server.get(link.href)
|
||||||
if (!error) {
|
if (!error) {
|
||||||
const container = this.parentNode
|
const template = document.createElement('template')
|
||||||
container.innerHTML = html
|
template.innerHTML = html
|
||||||
|
container.appendChild(template.content)
|
||||||
|
listenForMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const listenForMore = () => {
|
||||||
const more = document.querySelector('.more_button')
|
const more = document.querySelector('.more_button')
|
||||||
if (more) {
|
if (more) {
|
||||||
L.DomEvent.on(more, 'click', getMore, more)
|
L.DomEvent.on(more, 'click', (e) => {
|
||||||
|
L.DomEvent.stop(e)
|
||||||
|
getMore(more)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
listenForMore()
|
||||||
const more = document.querySelector('.more_button')
|
|
||||||
if (more) {
|
|
||||||
L.DomEvent.on(more, 'click', getMore, more)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock bottom_js %}
|
{% endblock bottom_js %}
|
||||||
|
|
|
@ -20,12 +20,14 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
{% if maps %}
|
{% if maps %}
|
||||||
|
<div class="row">
|
||||||
<h2 class="section">
|
<h2 class="section">
|
||||||
{% blocktrans %}Get inspired, browse maps{% endblocktrans %}
|
{% blocktrans %}Get inspired, browse maps{% endblocktrans %}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="map_list row">
|
<div class="grid-container">
|
||||||
{% include "umap/map_list.html" %}
|
{% include "umap/map_list.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock maincontent %}
|
{% endblock maincontent %}
|
||||||
|
|
|
@ -1,22 +1,19 @@
|
||||||
{% load umap_tags i18n %}
|
{% load umap_tags i18n %}
|
||||||
|
|
||||||
{% for map_inst in maps %}
|
{% for map_inst in maps %}
|
||||||
<hr />
|
<div>
|
||||||
<div class="col wide">
|
|
||||||
{% map_fragment map_inst prefix=prefix page=request.GET.p %}
|
{% map_fragment map_inst prefix=prefix page=request.GET.p %}
|
||||||
<div class="legend">
|
<hgroup>
|
||||||
<a href="{{ map_inst.get_absolute_url }}">{{ map_inst.name }}</a>
|
<h3><a href="{{ map_inst.get_absolute_url }}">{{ map_inst.name }}</a></h3>
|
||||||
{% with author=map_inst.get_author %}
|
{% with author=map_inst.get_author %}
|
||||||
{% if author %}
|
{% if author %}
|
||||||
<em>{% trans "by" %} <a href="{{ author.get_url }}">{{ author }}</a></em>
|
<p>{% trans "by" %} <a href="{{ author.get_url }}">{{ author }}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</hgroup>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if maps.has_next %}
|
{% if maps.has_next %}
|
||||||
<div class="col wide">
|
|
||||||
<a href="?{% paginate_querystring maps.next_page_number %}"
|
<a href="?{% paginate_querystring maps.next_page_number %}"
|
||||||
class="button more_button neutral">{% trans "More" %}</a>
|
class="button more_button neutral">{% trans "More" %}</a>
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
{% include "umap/search_bar.html" %}
|
{% include "umap/search_bar.html" %}
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="map_list row">
|
<div class="row">
|
||||||
{% if request.GET.q %}
|
{% if request.GET.q %}
|
||||||
{% if maps %}
|
{% if maps %}
|
||||||
<h2>
|
<h2>
|
||||||
|
@ -22,7 +22,9 @@
|
||||||
{{ count }} maps found:
|
{{ count }} maps found:
|
||||||
{% endblocktranslate %}
|
{% endblocktranslate %}
|
||||||
</h2>
|
</h2>
|
||||||
|
<div class="grid-container">
|
||||||
{% include "umap/map_list.html" with prefix="search_map" %}
|
{% include "umap/map_list.html" with prefix="search_map" %}
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h2>
|
<h2>
|
||||||
{% trans "No map found." %}
|
{% trans "No map found." %}
|
||||||
|
@ -32,7 +34,9 @@
|
||||||
<h2>
|
<h2>
|
||||||
{% trans "Latest created maps" %}
|
{% trans "Latest created maps" %}
|
||||||
</h2>
|
</h2>
|
||||||
|
<div class="grid-container">
|
||||||
{% include "umap/map_list.html" with prefix="search_map" %}
|
{% include "umap/map_list.html" with prefix="search_map" %}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map_list row">
|
<div class="grid-container row">
|
||||||
{% if maps %}
|
{% if maps %}
|
||||||
{% include "umap/map_list.html" %}
|
{% include "umap/map_list.html" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -182,7 +182,7 @@ def test_can_restore_version(live_server, openmap, page, datalayer):
|
||||||
page.get_by_role("button", name="Manage layers").click()
|
page.get_by_role("button", name="Manage layers").click()
|
||||||
page.locator(".panel.right").get_by_title("Edit", exact=True).click()
|
page.locator(".panel.right").get_by_title("Edit", exact=True).click()
|
||||||
page.get_by_text("Versions").click()
|
page.get_by_text("Versions").click()
|
||||||
page.get_by_role("button", name="Restore this version").last.click()
|
page.get_by_title("Restore this version").last.click()
|
||||||
page.get_by_role("button", name="OK").click()
|
page.get_by_role("button", name="OK").click()
|
||||||
expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))
|
expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,8 @@ def test_umap_import_from_textarea(live_server, tilelayer, page, settings):
|
||||||
expect(page.locator(".umap-main-edit-toolbox .map-name")).to_have_text(
|
expect(page.locator(".umap-main-edit-toolbox .map-name")).to_have_text(
|
||||||
"Imported map"
|
"Imported map"
|
||||||
)
|
)
|
||||||
expect(page.get_by_text("Tunnels")).to_be_visible()
|
expect(page.locator(".panel.left").get_by_text("Tunnels")).to_be_visible()
|
||||||
expect(page.get_by_text("Cities")).to_be_visible()
|
expect(page.locator(".panel.left").get_by_text("Cities")).to_be_visible()
|
||||||
expect(page.locator(".leaflet-control-minimap")).to_be_visible()
|
expect(page.locator(".leaflet-control-minimap")).to_be_visible()
|
||||||
expect(
|
expect(
|
||||||
page.locator('img[src="https://tile.openstreetmap.fr/hot/6/32/21.png"]')
|
page.locator('img[src="https://tile.openstreetmap.fr/hot/6/32/21.png"]')
|
||||||
|
|
|
@ -477,23 +477,23 @@ def test_should_sync_datalayers_delete(new_page, asgi_live_server, tilelayer):
|
||||||
peerB.goto(f"{asgi_live_server.url}{map.get_absolute_url()}?edit")
|
peerB.goto(f"{asgi_live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
|
||||||
peerA.get_by_role("button", name="Open browser").click()
|
peerA.get_by_role("button", name="Open browser").click()
|
||||||
expect(peerA.get_by_text("datalayer 1")).to_be_visible()
|
expect(peerA.locator(".panel").get_by_text("datalayer 1")).to_be_visible()
|
||||||
expect(peerA.get_by_text("datalayer 2")).to_be_visible()
|
expect(peerA.locator(".panel").get_by_text("datalayer 2")).to_be_visible()
|
||||||
peerB.get_by_role("button", name="Open browser").click()
|
peerB.get_by_role("button", name="Open browser").click()
|
||||||
expect(peerB.get_by_text("datalayer 1")).to_be_visible()
|
expect(peerB.locator(".panel").get_by_text("datalayer 1")).to_be_visible()
|
||||||
expect(peerB.get_by_text("datalayer 2")).to_be_visible()
|
expect(peerB.locator(".panel").get_by_text("datalayer 2")).to_be_visible()
|
||||||
|
|
||||||
# Delete "datalayer 2" in peerA
|
# Delete "datalayer 2" in peerA
|
||||||
peerA.locator(".datalayer").get_by_role("button", name="Delete layer").first.click()
|
peerA.locator(".datalayer").get_by_role("button", name="Delete layer").first.click()
|
||||||
peerA.get_by_role("button", name="OK").click()
|
peerA.get_by_role("button", name="OK").click()
|
||||||
expect(peerA.get_by_text("datalayer 2")).to_be_hidden()
|
expect(peerA.locator(".panel").get_by_text("datalayer 2")).to_be_hidden()
|
||||||
expect(peerB.get_by_text("datalayer 2")).to_be_hidden()
|
expect(peerB.locator(".panel").get_by_text("datalayer 2")).to_be_hidden()
|
||||||
|
|
||||||
# Save delete to the server
|
# Save delete to the server
|
||||||
with peerA.expect_response(re.compile(".*/datalayer/delete/.*")):
|
with peerA.expect_response(re.compile(".*/datalayer/delete/.*")):
|
||||||
peerA.get_by_role("button", name="Save").click()
|
peerA.get_by_role("button", name="Save").click()
|
||||||
expect(peerA.get_by_text("datalayer 2")).to_be_hidden()
|
expect(peerA.locator(".panel").get_by_text("datalayer 2")).to_be_hidden()
|
||||||
expect(peerB.get_by_text("datalayer 2")).to_be_hidden()
|
expect(peerB.locator(".panel").get_by_text("datalayer 2")).to_be_hidden()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xdist_group(name="websockets")
|
@pytest.mark.xdist_group(name="websockets")
|
||||||
|
|
Loading…
Reference in a new issue