mirror of
https://github.com/umap-project/umap.git
synced 2025-05-04 21:51:50 +02:00
Compare commits
5 commits
b0eb263d93
...
51e41b7bce
Author | SHA1 | Date | |
---|---|---|---|
![]() |
51e41b7bce | ||
![]() |
b49f3d7633 | ||
![]() |
0dbac92853 | ||
![]() |
6d56bbb5de | ||
![]() |
e1a24b6180 |
12 changed files with 61 additions and 317 deletions
|
@ -1,37 +1,13 @@
|
||||||
import {
|
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
||||||
uMapAlert as Alert,
|
import { AjaxAutocomplete, AjaxAutocompleteMultiple } from './autocomplete.js'
|
||||||
uMapAlertCreation as AlertCreation,
|
|
||||||
} from '../components/alerts/alert.js'
|
|
||||||
import {
|
|
||||||
AjaxAutocomplete,
|
|
||||||
AjaxAutocompleteMultiple,
|
|
||||||
AutocompleteDatalist,
|
|
||||||
} from './autocomplete.js'
|
|
||||||
import Browser from './browser.js'
|
|
||||||
import Caption from './caption.js'
|
|
||||||
import ContextMenu from './ui/contextmenu.js'
|
|
||||||
import Facets from './facets.js'
|
|
||||||
import { Formatter } from './formatter.js'
|
|
||||||
import Help from './help.js'
|
import Help from './help.js'
|
||||||
import Importer from './importer.js'
|
import { ServerRequest } from './request.js'
|
||||||
import Orderable from './orderable.js'
|
|
||||||
import { HTTPError, NOKError, Request, RequestError, ServerRequest } from './request.js'
|
|
||||||
import Rules from './rules.js'
|
|
||||||
import { SCHEMA } from './schema.js'
|
import { SCHEMA } from './schema.js'
|
||||||
import Share from './share.js'
|
|
||||||
import Slideshow from './slideshow.js'
|
|
||||||
import { SyncEngine } from './sync/engine.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'
|
import * as Utils from './utils.js'
|
||||||
import * as Icon from './rendering/icon.js'
|
import * as Icon from './rendering/icon.js'
|
||||||
import { DataLayer, LAYER_TYPES } from './data/layer.js'
|
import { LAYER_TYPES } from './data/layer.js'
|
||||||
import { DataLayerPermissions, MapPermissions } from './permissions.js'
|
|
||||||
import { Point, LineString, Polygon } from './data/features.js'
|
import { Point, LineString, Polygon } from './data/features.js'
|
||||||
import { LeafletMarker, LeafletPolyline, LeafletPolygon } from './rendering/ui.js'
|
import { LeafletMarker, LeafletPolyline, LeafletPolygon } from './rendering/ui.js'
|
||||||
import * as SAVEMANAGER from './saving.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.
|
||||||
|
@ -39,45 +15,18 @@ import * as SAVEMANAGER from './saving.js'
|
||||||
// By alphabetic order
|
// By alphabetic order
|
||||||
window.U = {
|
window.U = {
|
||||||
Alert,
|
Alert,
|
||||||
AlertCreation,
|
|
||||||
AjaxAutocomplete,
|
AjaxAutocomplete,
|
||||||
AjaxAutocompleteMultiple,
|
AjaxAutocompleteMultiple,
|
||||||
AutocompleteDatalist,
|
|
||||||
Browser,
|
|
||||||
Caption,
|
|
||||||
ContextMenu,
|
|
||||||
DataLayer,
|
|
||||||
DataLayerPermissions,
|
|
||||||
Dialog,
|
|
||||||
EditPanel,
|
|
||||||
Facets,
|
|
||||||
Formatter,
|
|
||||||
FullPanel,
|
|
||||||
Help,
|
Help,
|
||||||
HTTPError,
|
|
||||||
Icon,
|
Icon,
|
||||||
Importer,
|
|
||||||
LAYER_TYPES,
|
LAYER_TYPES,
|
||||||
LeafletMarker,
|
LeafletMarker,
|
||||||
LeafletPolygon,
|
LeafletPolygon,
|
||||||
LeafletPolyline,
|
LeafletPolyline,
|
||||||
LineString,
|
LineString,
|
||||||
MapPermissions,
|
|
||||||
NOKError,
|
|
||||||
Orderable,
|
|
||||||
Panel,
|
|
||||||
Point,
|
Point,
|
||||||
Polygon,
|
Polygon,
|
||||||
Request,
|
|
||||||
RequestError,
|
|
||||||
Rules,
|
|
||||||
SAVEMANAGER,
|
|
||||||
SCHEMA,
|
SCHEMA,
|
||||||
ServerRequest,
|
ServerRequest,
|
||||||
Share,
|
|
||||||
Slideshow,
|
|
||||||
SyncEngine,
|
|
||||||
Tooltip,
|
|
||||||
URLs,
|
|
||||||
Utils,
|
Utils,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +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 * as Utils from './utils.js'
|
||||||
|
import Dialog from './ui/dialog.js'
|
||||||
|
|
||||||
const SHORTCUTS = {
|
const SHORTCUTS = {
|
||||||
DRAW_MARKER: {
|
DRAW_MARKER: {
|
||||||
|
@ -166,7 +167,7 @@ const ENTRIES = {
|
||||||
export default class Help {
|
export default class Help {
|
||||||
constructor(umap) {
|
constructor(umap) {
|
||||||
this.umap = umap
|
this.umap = umap
|
||||||
this.dialog = new U.Dialog({ className: 'dark', accept: false, cancel: false })
|
this.dialog = new Dialog({ className: 'dark', accept: false, cancel: false })
|
||||||
this.isMacOS = /mac/i.test(
|
this.isMacOS = /mac/i.test(
|
||||||
// eslint-disable-next-line compat/compat -- Fallback available.
|
// eslint-disable-next-line compat/compat -- Fallback available.
|
||||||
navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform
|
navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform
|
||||||
|
|
|
@ -251,7 +251,6 @@ export default class Importer {
|
||||||
}
|
}
|
||||||
|
|
||||||
full() {
|
full() {
|
||||||
this.umap._leafletMap.once('postsync', this.umap._leafletMap._setDefaultCenter)
|
|
||||||
try {
|
try {
|
||||||
if (this.files.length) {
|
if (this.files.length) {
|
||||||
for (const file of this.files) {
|
for (const file of this.files) {
|
||||||
|
|
|
@ -193,7 +193,6 @@ export class MapPermissions extends ServerStored {
|
||||||
)
|
)
|
||||||
if (!error) {
|
if (!error) {
|
||||||
this.commit()
|
this.commit()
|
||||||
this.umap._leafletMap.fire('postsync')
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { translate } from '../i18n.js'
|
||||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
import { uMapAlert as Alert } from '../../components/alerts/alert.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 ContextMenu from '../ui/contextmenu.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
|
||||||
|
@ -203,7 +204,7 @@ const ControlsMixin = {
|
||||||
</button>
|
</button>
|
||||||
`)
|
`)
|
||||||
rightContainer.appendChild(button)
|
rightContainer.appendChild(button)
|
||||||
const menu = new U.ContextMenu({ className: 'dark', fixed: true })
|
const menu = new ContextMenu({ className: 'dark', fixed: true })
|
||||||
const actions = [
|
const actions = [
|
||||||
{
|
{
|
||||||
label: translate('New map'),
|
label: translate('New map'),
|
||||||
|
@ -252,7 +253,7 @@ const ControlsMixin = {
|
||||||
})
|
})
|
||||||
|
|
||||||
const updateConnectedPeersCount = () => {
|
const updateConnectedPeersCount = () => {
|
||||||
connectedPeersCount.innerHTML = this.sync.getNumberOfConnectedPeers()
|
connectedPeersCount.innerHTML = this.umap.sync.getNumberOfConnectedPeers()
|
||||||
}
|
}
|
||||||
updateConnectedPeersCount()
|
updateConnectedPeersCount()
|
||||||
}
|
}
|
||||||
|
@ -306,8 +307,12 @@ const ControlsMixin = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
initCaptionBar: function () {
|
renderCaptionBar: function () {
|
||||||
const container = DomUtil.create('div', 'umap-caption-bar', this._controlContainer)
|
if (this.options.noControl) return
|
||||||
|
const container =
|
||||||
|
this._controlContainer.querySelector('.umap-caption-bar') ||
|
||||||
|
DomUtil.create('div', 'umap-caption-bar', this._controlContainer)
|
||||||
|
container.innerHTML = ''
|
||||||
const name = DomUtil.create('h3', 'map-name', container)
|
const name = DomUtil.create('h3', 'map-name', container)
|
||||||
DomEvent.disableClickPropagation(container)
|
DomEvent.disableClickPropagation(container)
|
||||||
this.umap.addAuthorLink(container)
|
this.umap.addAuthorLink(container)
|
||||||
|
@ -316,8 +321,7 @@ const ControlsMixin = {
|
||||||
'umap-about-link flat',
|
'umap-about-link flat',
|
||||||
container,
|
container,
|
||||||
translate('Open caption'),
|
translate('Open caption'),
|
||||||
this.umap.openCaption,
|
() => this.umap.openCaption()
|
||||||
this
|
|
||||||
)
|
)
|
||||||
DomUtil.createButton(
|
DomUtil.createButton(
|
||||||
'umap-open-browser-link flat',
|
'umap-open-browser-link flat',
|
||||||
|
@ -334,8 +338,8 @@ const ControlsMixin = {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.umap.onceDatalayersLoaded(function () {
|
this.umap.onceDatalayersLoaded(() => {
|
||||||
this.slideshow.renderToolbox(container)
|
this.umap.slideshow.renderToolbox(container)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -481,11 +485,18 @@ export const LeafletMap = BaseMap.extend({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
attachToDom: function () {
|
setup: function () {
|
||||||
this.initControls()
|
this.initControls()
|
||||||
// Needs locate control and hash to exist
|
// Needs locate control and hash to exist
|
||||||
this.initCenter()
|
this.initCenter()
|
||||||
|
this.update()
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function () {
|
||||||
|
this.setOptions(this.umap.properties)
|
||||||
this.initTileLayers()
|
this.initTileLayers()
|
||||||
|
this.renderCaptionBar()
|
||||||
|
this.renderEditToolbar()
|
||||||
// Needs tilelayer to exist for minimap
|
// Needs tilelayer to exist for minimap
|
||||||
this.renderControls()
|
this.renderControls()
|
||||||
this.handleLimitBounds()
|
this.handleLimitBounds()
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.
|
||||||
import { translate } from './i18n.js'
|
import { translate } from './i18n.js'
|
||||||
import * as Utils from './utils.js'
|
import * as Utils from './utils.js'
|
||||||
import { AutocompleteDatalist } from './autocomplete.js'
|
import { AutocompleteDatalist } from './autocomplete.js'
|
||||||
|
import Orderable from './orderable.js'
|
||||||
|
|
||||||
const EMPTY_VALUES = ['', undefined, null]
|
const EMPTY_VALUES = ['', undefined, null]
|
||||||
|
|
||||||
|
@ -236,7 +237,7 @@ export default class Rules {
|
||||||
rule.renderToolbox(DomUtil.create('li', 'orderable', ul))
|
rule.renderToolbox(DomUtil.create('li', 'orderable', ul))
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderable = new U.Orderable(ul, this.onReorder.bind(this))
|
const orderable = new Orderable(ul, this.onReorder.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
DomUtil.createButton('umap-add', body, translate('Add rule'), this.addRule, this)
|
DomUtil.createButton('umap-add', body, translate('Add rule'), this.addRule, this)
|
||||||
|
|
|
@ -83,7 +83,7 @@ export default class Slideshow extends WithTemplate {
|
||||||
|
|
||||||
play() {
|
play() {
|
||||||
if (this._id) return
|
if (this._id) return
|
||||||
if (this.umap.editEnabled || !this.umap.options.slideshow.active) return
|
if (this.umap.editEnabled || !this.umap.properties.slideshow.active) return
|
||||||
L.DomUtil.addClass(document.body, this.CLASSNAME)
|
L.DomUtil.addClass(document.body, this.CLASSNAME)
|
||||||
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay)
|
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay)
|
||||||
this.startSpinner()
|
this.startSpinner()
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { fieldInSchema } from '../utils.js'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class BaseUpdater {
|
class BaseUpdater {
|
||||||
constructor(map) {
|
constructor(umap) {
|
||||||
this.map = map
|
this.umap = umap
|
||||||
}
|
}
|
||||||
|
|
||||||
updateObjectValue(obj, key, value) {
|
updateObjectValue(obj, key, value) {
|
||||||
|
@ -32,8 +32,8 @@ class BaseUpdater {
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataLayerFromID(layerId) {
|
getDataLayerFromID(layerId) {
|
||||||
if (layerId) return this.map.getDataLayerByUmapId(layerId)
|
if (layerId) return this.umap.getDataLayerByUmapId(layerId)
|
||||||
return this.map.defaultEditDataLayer()
|
return this.umap.defaultEditDataLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
applyMessage(payload) {
|
applyMessage(payload) {
|
||||||
|
@ -45,18 +45,18 @@ class BaseUpdater {
|
||||||
export class MapUpdater extends BaseUpdater {
|
export class MapUpdater extends BaseUpdater {
|
||||||
update({ key, value }) {
|
update({ key, value }) {
|
||||||
if (fieldInSchema(key)) {
|
if (fieldInSchema(key)) {
|
||||||
this.updateObjectValue(this.map, key, value)
|
this.updateObjectValue(this.umap, key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.map.render([key])
|
this.umap.render([key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DataLayerUpdater extends BaseUpdater {
|
export class DataLayerUpdater extends BaseUpdater {
|
||||||
upsert({ value }) {
|
upsert({ value }) {
|
||||||
// Inserts does not happen (we use multiple updates instead).
|
// Inserts does not happen (we use multiple updates instead).
|
||||||
this.map.createDataLayer(value, false)
|
this.umap.createDataLayer(value, false)
|
||||||
this.map.render([])
|
this.umap.render([])
|
||||||
}
|
}
|
||||||
|
|
||||||
update({ key, metadata, value }) {
|
update({ key, metadata, value }) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import {
|
||||||
uMapAlertCreation as AlertCreation,
|
uMapAlertCreation as AlertCreation,
|
||||||
uMapAlert as Alert,
|
uMapAlert as Alert,
|
||||||
} from '../components/alerts/alert.js'
|
} from '../components/alerts/alert.js'
|
||||||
|
import Orderable from './orderable.js'
|
||||||
|
|
||||||
export default class Umap extends ServerStored {
|
export default class Umap extends ServerStored {
|
||||||
constructor(element, geojson) {
|
constructor(element, geojson) {
|
||||||
|
@ -85,11 +86,16 @@ export default class Umap extends ServerStored {
|
||||||
if (center) {
|
if (center) {
|
||||||
this._leafletMap.options.center = this._leafletMap.latLng(center)
|
this._leafletMap.options.center = this._leafletMap.latLng(center)
|
||||||
}
|
}
|
||||||
this._leafletMap.attachToDom()
|
|
||||||
|
// Needed to render controls
|
||||||
|
this.permissions = new MapPermissions(this)
|
||||||
|
this.urls = new URLs(this.properties.urls)
|
||||||
|
this.slideshow = new Slideshow(this, this.properties.slideshow)
|
||||||
|
|
||||||
|
this._leafletMap.setup()
|
||||||
|
|
||||||
if (geojson.properties.schema) this.overrideSchema(geojson.properties.schema)
|
if (geojson.properties.schema) this.overrideSchema(geojson.properties.schema)
|
||||||
|
|
||||||
this.urls = new URLs(this.properties.urls)
|
|
||||||
|
|
||||||
this.panel = new Panel(this)
|
this.panel = new Panel(this)
|
||||||
this.dialog = new Dialog({ className: 'dark' })
|
this.dialog = new Dialog({ className: 'dark' })
|
||||||
|
@ -171,15 +177,12 @@ export default class Umap extends ServerStored {
|
||||||
await this.loadDataFromQueryString()
|
await this.loadDataFromQueryString()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.slideshow = new Slideshow(this, this.properties.slideshow)
|
|
||||||
this.permissions = new MapPermissions(this)
|
|
||||||
if (this.hasEditMode()) {
|
if (this.hasEditMode()) {
|
||||||
this._leafletMap.initEditTools()
|
this._leafletMap.initEditTools()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.properties.noControl) {
|
if (!this.properties.noControl) {
|
||||||
this.initShortcuts()
|
this.initShortcuts()
|
||||||
this._leafletMap.initCaptionBar()
|
|
||||||
this._leafletMap.on('contextmenu', this.onContextMenu)
|
this._leafletMap.on('contextmenu', this.onContextMenu)
|
||||||
this.onceDataLoaded(this.setViewFromQueryString)
|
this.onceDataLoaded(this.setViewFromQueryString)
|
||||||
this.propagate()
|
this.propagate()
|
||||||
|
@ -1245,7 +1248,7 @@ export default class Umap extends ServerStored {
|
||||||
|
|
||||||
render(fields) {
|
render(fields) {
|
||||||
if (fields.includes('numberOfConnectedPeers')) {
|
if (fields.includes('numberOfConnectedPeers')) {
|
||||||
this.renderEditToolbar()
|
this._leafletMap.renderEditToolbar()
|
||||||
this.propagate()
|
this.propagate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,10 +1256,7 @@ export default class Umap extends ServerStored {
|
||||||
for (const impact of impacts) {
|
for (const impact of impacts) {
|
||||||
switch (impact) {
|
switch (impact) {
|
||||||
case 'ui':
|
case 'ui':
|
||||||
this._leafletMap.setOptions(this.properties)
|
this._leafletMap.update()
|
||||||
this._leafletMap.initCaptionBar()
|
|
||||||
this._leafletMap.renderEditToolbar()
|
|
||||||
this._leafletMap.renderControls()
|
|
||||||
this.browser.redraw()
|
this.browser.redraw()
|
||||||
this.propagate()
|
this.propagate()
|
||||||
break
|
break
|
||||||
|
@ -1383,7 +1383,7 @@ export default class Umap extends ServerStored {
|
||||||
})
|
})
|
||||||
this.indexDatalayers()
|
this.indexDatalayers()
|
||||||
}
|
}
|
||||||
const orderable = new U.Orderable(ul, onReorder)
|
const orderable = new Orderable(ul, onReorder)
|
||||||
|
|
||||||
const bar = DomUtil.create('div', 'button-bar', container)
|
const bar = DomUtil.create('div', 'button-bar', container)
|
||||||
DomUtil.createButton(
|
DomUtil.createButton(
|
||||||
|
@ -1499,17 +1499,13 @@ export default class Umap extends ServerStored {
|
||||||
dataLayer.fromUmapGeoJSON(geojson)
|
dataLayer.fromUmapGeoJSON(geojson)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor with leafletMap init / render
|
this._leafletMap.update()
|
||||||
this._leafletMap.setOptions(this.properties)
|
|
||||||
this._leafletMap.initTileLayers()
|
|
||||||
this._leafletMap.renderControls()
|
|
||||||
this._leafletMap.handleLimitBounds()
|
|
||||||
this.eachDataLayer((datalayer) => {
|
this.eachDataLayer((datalayer) => {
|
||||||
if (mustReindex) datalayer.reindex()
|
if (mustReindex) datalayer.reindex()
|
||||||
datalayer.redraw()
|
datalayer.redraw()
|
||||||
})
|
})
|
||||||
this.propagate()
|
this.propagate()
|
||||||
this._leafletMap.fire('postsync')
|
this._leafletMap._setDefaultCenter()
|
||||||
this.isDirty = true
|
this.isDirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,10 @@ export function getImpactsFromSchema(fields, schema) {
|
||||||
export function fieldInSchema(field, schema) {
|
export function fieldInSchema(field, schema) {
|
||||||
const current_schema = schema || U.SCHEMA
|
const current_schema = schema || U.SCHEMA
|
||||||
if (typeof field !== 'string') return false
|
if (typeof field !== 'string') return false
|
||||||
const field_name = field.replace('options.', '').split('.')[0]
|
const field_name = field
|
||||||
|
.replace('options.', '')
|
||||||
|
.replace('properties.', '')
|
||||||
|
.split('.')[0]
|
||||||
return current_schema[field_name] !== undefined
|
return current_schema[field_name] !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,215 +0,0 @@
|
||||||
L.Map.mergeOptions({
|
|
||||||
overlay: {},
|
|
||||||
datalayers: [],
|
|
||||||
maxZoomLimit: 24,
|
|
||||||
attributionControl: false,
|
|
||||||
editMode: 'advanced',
|
|
||||||
noControl: false, // Do not render any control.
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
// 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
|
|
||||||
// See https://github.com/Leaflet/Leaflet/pull/9201
|
|
||||||
// And let's remove this -y when this PR is merged and released.
|
|
||||||
demoTileInfos: { s: 'a', z: 9, x: 265, y: 181, '-y': 181, r: '' },
|
|
||||||
licences: [],
|
|
||||||
licence: '',
|
|
||||||
slideshow: {},
|
|
||||||
clickable: true,
|
|
||||||
permissions: {},
|
|
||||||
featuresHaveOwner: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
U.Map = L.Map.extend({
|
|
||||||
includes: [ControlsMixin],
|
|
||||||
|
|
||||||
initialize: async function (el, geojson) {
|
|
||||||
this.sync_engine = new U.SyncEngine(this)
|
|
||||||
this.sync = this.sync_engine.proxy(this)
|
|
||||||
// Locale name (pt_PT, en_US…)
|
|
||||||
// To be used for Django localization
|
|
||||||
if (geojson.properties.locale) L.setLocale(geojson.properties.locale)
|
|
||||||
|
|
||||||
// Language code (pt-pt, en-us…)
|
|
||||||
// To be used in javascript APIs
|
|
||||||
if (geojson.properties.lang) L.lang = geojson.properties.lang
|
|
||||||
|
|
||||||
this.setOptionsFromQueryString(geojson.properties)
|
|
||||||
// Prevent default creation of controls
|
|
||||||
const zoomControl = geojson.properties.zoomControl
|
|
||||||
const fullscreenControl = geojson.properties.fullscreenControl
|
|
||||||
geojson.properties.zoomControl = false
|
|
||||||
geojson.properties.fullscreenControl = false
|
|
||||||
|
|
||||||
L.Map.prototype.initialize.call(this, el, geojson.properties)
|
|
||||||
|
|
||||||
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)
|
|
||||||
this.urls = new U.URLs(this.options.urls)
|
|
||||||
|
|
||||||
this.panel = new U.Panel(this)
|
|
||||||
this.dialog = new U.Dialog({ className: 'dark' })
|
|
||||||
this.tooltip = new U.Tooltip(this._controlContainer)
|
|
||||||
this.contextmenu = new U.ContextMenu()
|
|
||||||
if (this.hasEditMode()) {
|
|
||||||
this.editPanel = new U.EditPanel(this)
|
|
||||||
this.fullPanel = new U.FullPanel(this)
|
|
||||||
}
|
|
||||||
if (!this.options.noControl) {
|
|
||||||
L.DomEvent.on(document.body, 'dataloading', (e) => this.fire('dataloading', e))
|
|
||||||
L.DomEvent.on(document.body, 'dataload', (e) => this.fire('dataload', e))
|
|
||||||
}
|
|
||||||
this.server = new U.ServerRequest()
|
|
||||||
this.request = new U.Request()
|
|
||||||
|
|
||||||
this.initLoader()
|
|
||||||
this.name = this.options.name
|
|
||||||
this.description = this.options.description
|
|
||||||
this.demoTileInfos = this.options.demoTileInfos
|
|
||||||
this.options.zoomControl = zoomControl !== undefined ? zoomControl : true
|
|
||||||
this.options.fullscreenControl =
|
|
||||||
fullscreenControl !== undefined ? fullscreenControl : true
|
|
||||||
|
|
||||||
this.datalayersFromQueryString = L.Util.queryString('datalayers')
|
|
||||||
if (this.datalayersFromQueryString) {
|
|
||||||
this.datalayersFromQueryString = this.datalayersFromQueryString
|
|
||||||
.toString()
|
|
||||||
.split(',')
|
|
||||||
}
|
|
||||||
|
|
||||||
let editedFeature = null
|
|
||||||
try {
|
|
||||||
Object.defineProperty(this, 'editedFeature', {
|
|
||||||
get: () => editedFeature,
|
|
||||||
set: (feature) => {
|
|
||||||
if (editedFeature && editedFeature !== feature) {
|
|
||||||
editedFeature.endEdit()
|
|
||||||
}
|
|
||||||
editedFeature = feature
|
|
||||||
this.fire('seteditedfeature')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
// Certainly IE8, which has a limited version of defineProperty
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrocompat
|
|
||||||
if (this.options.slideshow?.delay && this.options.slideshow.active === undefined) {
|
|
||||||
this.options.slideshow.active = true
|
|
||||||
}
|
|
||||||
if (this.options.advancedFilterKey) {
|
|
||||||
this.options.facetKey = this.options.advancedFilterKey
|
|
||||||
delete this.options.advancedFilterKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global storage for retrieving datalayers and features.
|
|
||||||
this.datalayers = {} // All datalayers, including deleted.
|
|
||||||
this.datalayers_index = [] // Datalayers actually on the map and ordered.
|
|
||||||
this.features_index = {}
|
|
||||||
|
|
||||||
// Needed for actions labels
|
|
||||||
this.help = new U.Help(this)
|
|
||||||
|
|
||||||
this.formatter = new U.Formatter(this)
|
|
||||||
|
|
||||||
this.initControls()
|
|
||||||
// Needs locate control and hash to exist
|
|
||||||
this.initCenter()
|
|
||||||
this.initTileLayers()
|
|
||||||
// Needs tilelayer to exist for minimap
|
|
||||||
this.renderControls()
|
|
||||||
this.handleLimitBounds()
|
|
||||||
this.initDataLayers()
|
|
||||||
|
|
||||||
if (this.options.displayCaptionOnLoad) {
|
|
||||||
// Retrocompat
|
|
||||||
if (!this.options.onLoadPanel) {
|
|
||||||
this.options.onLoadPanel = 'caption'
|
|
||||||
}
|
|
||||||
delete this.options.displayCaptionOnLoad
|
|
||||||
}
|
|
||||||
if (this.options.displayDataBrowserOnLoad) {
|
|
||||||
// Retrocompat
|
|
||||||
if (!this.options.onLoadPanel) {
|
|
||||||
this.options.onLoadPanel = 'databrowser'
|
|
||||||
}
|
|
||||||
delete this.options.displayDataBrowserOnLoad
|
|
||||||
}
|
|
||||||
if (this.options.datalayersControl === 'expanded') {
|
|
||||||
if (!this.options.onLoadPanel) {
|
|
||||||
this.options.onLoadPanel = 'datalayers'
|
|
||||||
}
|
|
||||||
delete this.options.datalayersControl
|
|
||||||
}
|
|
||||||
if (this.options.onLoadPanel === 'facet') {
|
|
||||||
this.options.onLoadPanel = 'datafilters'
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove me when moved to modules
|
|
||||||
// and inheriting from ServerStored
|
|
||||||
try {
|
|
||||||
Object.defineProperty(this, 'isDirty', {
|
|
||||||
get: () => U.SAVEMANAGER.has(this),
|
|
||||||
set: (status) => {
|
|
||||||
if (status) {
|
|
||||||
U.SAVEMANAGER.add(this)
|
|
||||||
} else {
|
|
||||||
U.SAVEMANAGER.remove(this)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
// Certainly IE8, which has a limited version of defineProperty
|
|
||||||
}
|
|
||||||
this.on(
|
|
||||||
'baselayerchange',
|
|
||||||
function (e) {
|
|
||||||
if (this._controls.miniMap) this._controls.miniMap.onMainMapBaseLayerChange(e)
|
|
||||||
},
|
|
||||||
this
|
|
||||||
)
|
|
||||||
|
|
||||||
// Creation mode
|
|
||||||
if (!this.options.umap_id) {
|
|
||||||
if (!this.options.preview) {
|
|
||||||
this.isDirty = true
|
|
||||||
this.enableEdit()
|
|
||||||
}
|
|
||||||
this._default_extent = true
|
|
||||||
this.options.name = L._('Untitled map')
|
|
||||||
await this.loadDataFromQueryString()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.slideshow = new U.Slideshow(this, this.options.slideshow)
|
|
||||||
this.permissions = new U.MapPermissions(this)
|
|
||||||
if (this.hasEditMode()) {
|
|
||||||
this.editTools = new U.Editable(this)
|
|
||||||
this.renderEditToolbar()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.options.noControl) {
|
|
||||||
this.initShortcuts()
|
|
||||||
this.initCaptionBar()
|
|
||||||
this.on('contextmenu', this.onContextMenu)
|
|
||||||
this.onceDataLoaded(this.setViewFromQueryString)
|
|
||||||
this.on('click', this.closeInplaceToolbar)
|
|
||||||
this.propagate()
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onbeforeunload = () => (this.editEnabled && U.SAVEMANAGER.isDirty) || null
|
|
||||||
this.backup()
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
getFeatureById: function (id) {
|
|
||||||
let feature
|
|
||||||
for (const datalayer of this.datalayers_index) {
|
|
||||||
feature = datalayer.getFeatureById(id)
|
|
||||||
if (feature) return feature
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
})
|
|
|
@ -161,7 +161,7 @@ def test_websocket_connection_can_sync_polygons(
|
||||||
|
|
||||||
@pytest.mark.xdist_group(name="websockets")
|
@pytest.mark.xdist_group(name="websockets")
|
||||||
def test_websocket_connection_can_sync_map_properties(
|
def test_websocket_connection_can_sync_map_properties(
|
||||||
context, live_server, websocket_server, tilelayer
|
new_page, live_server, websocket_server, tilelayer
|
||||||
):
|
):
|
||||||
map = MapFactory(name="sync", edit_status=Map.ANONYMOUS)
|
map = MapFactory(name="sync", edit_status=Map.ANONYMOUS)
|
||||||
map.settings["properties"]["syncEnabled"] = True
|
map.settings["properties"]["syncEnabled"] = True
|
||||||
|
@ -169,9 +169,9 @@ def test_websocket_connection_can_sync_map_properties(
|
||||||
DataLayerFactory(map=map, data={})
|
DataLayerFactory(map=map, data={})
|
||||||
|
|
||||||
# Create two tabs
|
# Create two tabs
|
||||||
peerA = context.new_page()
|
peerA = new_page()
|
||||||
peerA.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
peerA.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
peerB = context.new_page()
|
peerB = new_page()
|
||||||
peerB.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
peerB.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
|
||||||
# Name change is synced
|
# Name change is synced
|
||||||
|
@ -193,7 +193,7 @@ def test_websocket_connection_can_sync_map_properties(
|
||||||
|
|
||||||
@pytest.mark.xdist_group(name="websockets")
|
@pytest.mark.xdist_group(name="websockets")
|
||||||
def test_websocket_connection_can_sync_datalayer_properties(
|
def test_websocket_connection_can_sync_datalayer_properties(
|
||||||
context, live_server, websocket_server, tilelayer
|
new_page, live_server, websocket_server, tilelayer
|
||||||
):
|
):
|
||||||
map = MapFactory(name="sync", edit_status=Map.ANONYMOUS)
|
map = MapFactory(name="sync", edit_status=Map.ANONYMOUS)
|
||||||
map.settings["properties"]["syncEnabled"] = True
|
map.settings["properties"]["syncEnabled"] = True
|
||||||
|
@ -201,9 +201,9 @@ def test_websocket_connection_can_sync_datalayer_properties(
|
||||||
DataLayerFactory(map=map, data={})
|
DataLayerFactory(map=map, data={})
|
||||||
|
|
||||||
# Create two tabs
|
# Create two tabs
|
||||||
peerA = context.new_page()
|
peerA = new_page()
|
||||||
peerA.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
peerA.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
peerB = context.new_page()
|
peerB = new_page()
|
||||||
peerB.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
peerB.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
|
||||||
# Layer addition, name and type are synced
|
# Layer addition, name and type are synced
|
||||||
|
@ -215,7 +215,7 @@ def test_websocket_connection_can_sync_datalayer_properties(
|
||||||
peerA.locator("body").press("Escape")
|
peerA.locator("body").press("Escape")
|
||||||
|
|
||||||
peerB.get_by_role("link", name="Manage layers").click()
|
peerB.get_by_role("link", name="Manage layers").click()
|
||||||
peerB.get_by_role("button", name="Edit").first.click()
|
peerB.locator(".panel.right").get_by_role("button", name="Edit").first.click()
|
||||||
expect(peerB.locator('input[name="name"]')).to_have_value("synced layer!")
|
expect(peerB.locator('input[name="name"]')).to_have_value("synced layer!")
|
||||||
expect(peerB.get_by_role("combobox")).to_have_value("Choropleth")
|
expect(peerB.get_by_role("combobox")).to_have_value("Choropleth")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue