mirror of
https://github.com/umap-project/umap.git
synced 2025-04-28 03:22:37 +02:00
chore: use our contexmenu class for inplace toolbar
And remove Leaflet.Toolbar dependency. This also teach ContextMenu how to display icons instead of text and how to render in horizontal orientation instead of vertical.
This commit is contained in:
parent
fb6df6f955
commit
4adc558560
19 changed files with 128 additions and 279 deletions
|
@ -16,7 +16,6 @@ mkdir -p umap/static/umap/vendors/markercluster/ && cp -r node_modules/leaflet.m
|
||||||
mkdir -p umap/static/umap/vendors/markercluster/ && cp -r node_modules/leaflet.markercluster/dist/MarkerCluster.* umap/static/umap/vendors/markercluster/
|
mkdir -p umap/static/umap/vendors/markercluster/ && cp -r node_modules/leaflet.markercluster/dist/MarkerCluster.* umap/static/umap/vendors/markercluster/
|
||||||
mkdir -p umap/static/umap/vendors/heat/ && cp -r node_modules/leaflet.heat/dist/leaflet-heat.js umap/static/umap/vendors/heat/
|
mkdir -p umap/static/umap/vendors/heat/ && cp -r node_modules/leaflet.heat/dist/leaflet-heat.js umap/static/umap/vendors/heat/
|
||||||
mkdir -p umap/static/umap/vendors/fullscreen/ && cp -r node_modules/leaflet-fullscreen/dist/** umap/static/umap/vendors/fullscreen/
|
mkdir -p umap/static/umap/vendors/fullscreen/ && cp -r node_modules/leaflet-fullscreen/dist/** umap/static/umap/vendors/fullscreen/
|
||||||
mkdir -p umap/static/umap/vendors/toolbar/ && cp -r node_modules/leaflet-toolbar/dist/leaflet.toolbar.* umap/static/umap/vendors/toolbar/
|
|
||||||
mkdir -p umap/static/umap/vendors/measurable/ && cp -r node_modules/leaflet-measurable/Leaflet.Measurable.* umap/static/umap/vendors/measurable/
|
mkdir -p umap/static/umap/vendors/measurable/ && cp -r node_modules/leaflet-measurable/Leaflet.Measurable.* umap/static/umap/vendors/measurable/
|
||||||
mkdir -p umap/static/umap/vendors/photon/ && cp -r node_modules/leaflet.photon/leaflet.photon.js umap/static/umap/vendors/photon/
|
mkdir -p umap/static/umap/vendors/photon/ && cp -r node_modules/leaflet.photon/leaflet.photon.js umap/static/umap/vendors/photon/
|
||||||
mkdir -p umap/static/umap/vendors/csv2geojson/ && cp -r node_modules/csv2geojson/csv2geojson.js umap/static/umap/vendors/csv2geojson/
|
mkdir -p umap/static/umap/vendors/csv2geojson/ && cp -r node_modules/csv2geojson/csv2geojson.js umap/static/umap/vendors/csv2geojson/
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
.umap-contextmenu {
|
.umap-contextmenu {
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
padding: calc(var(--box-padding) / 2) var(--box-padding);
|
padding: calc(var(--box-padding) / 2) calc(var(--box-padding) / 2);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: var(--zindex-contextmenu);
|
z-index: var(--zindex-contextmenu);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
box-shadow: var(--block-shadow);
|
box-shadow: var(--block-shadow);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.umap-contextmenu li + li {
|
.umap-contextmenu-rows {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
.umap-contextmenu:not(.umap-contextmenu-rows) li + li {
|
||||||
margin-top: var(--text-margin);
|
margin-top: var(--text-margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,12 +68,21 @@ html[dir="rtl"] .icon {
|
||||||
.icon-close {
|
.icon-close {
|
||||||
background-position: var(--tile) 0px;
|
background-position: var(--tile) 0px;
|
||||||
}
|
}
|
||||||
|
.icon-continue-line {
|
||||||
|
background-position: calc(var(--tile) * 4) 0;
|
||||||
|
}
|
||||||
.icon-copy {
|
.icon-copy {
|
||||||
background-position: calc(var(--tile) * 2) calc(var(--tile) * 4);
|
background-position: calc(var(--tile) * 2) calc(var(--tile) * 4);
|
||||||
}
|
}
|
||||||
.icon-delete {
|
.icon-delete {
|
||||||
background-position: calc(var(--tile) * 5) calc(var(--tile) * 2);
|
background-position: calc(var(--tile) * 5) calc(var(--tile) * 2);
|
||||||
}
|
}
|
||||||
|
.icon-delete-shape {
|
||||||
|
background-position: calc(var(--tile) * 4) calc(var(--tile) * 3);
|
||||||
|
}
|
||||||
|
.icon-delete-vertex {
|
||||||
|
background-position: calc(var(--tile) * 5) calc(var(--tile) * 4);
|
||||||
|
}
|
||||||
.readonly .icon-delete,
|
.readonly .icon-delete,
|
||||||
.off .icon-delete {
|
.off .icon-delete {
|
||||||
background-position: calc(var(--tile) * 5) calc(var(--tile) * 5);
|
background-position: calc(var(--tile) * 5) calc(var(--tile) * 5);
|
||||||
|
@ -98,6 +107,9 @@ html[dir="rtl"] .icon {
|
||||||
.off .icon-edit {
|
.off .icon-edit {
|
||||||
background-position: calc(var(--tile) * 2) calc(var(--tile) * 3);
|
background-position: calc(var(--tile) * 2) calc(var(--tile) * 3);
|
||||||
}
|
}
|
||||||
|
.icon-extract-shape {
|
||||||
|
background-position: calc(var(--tile) * 5) 0;
|
||||||
|
}
|
||||||
.icon-filters {
|
.icon-filters {
|
||||||
background-position: 0px var(--tile);
|
background-position: 0px var(--tile);
|
||||||
}
|
}
|
||||||
|
@ -107,6 +119,9 @@ html[dir="rtl"] .icon {
|
||||||
.icon-help {
|
.icon-help {
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
}
|
}
|
||||||
|
.icon-hole {
|
||||||
|
background-position: calc(var(--tile) * 3) calc(var(--tile) * 4);
|
||||||
|
}
|
||||||
.icon-key {
|
.icon-key {
|
||||||
background-position: calc(var(--tile) * 6) calc(var(--tile) * 5);
|
background-position: calc(var(--tile) * 6) calc(var(--tile) * 5);
|
||||||
}
|
}
|
||||||
|
@ -165,6 +180,9 @@ html[dir="rtl"] .icon {
|
||||||
.icon-share {
|
.icon-share {
|
||||||
background-position: 0px calc(var(--tile) * 5);
|
background-position: 0px calc(var(--tile) * 5);
|
||||||
}
|
}
|
||||||
|
.icon-split-line {
|
||||||
|
background-position: calc(var(--tile) * 5) var(--tile);
|
||||||
|
}
|
||||||
.icon-star {
|
.icon-star {
|
||||||
background-position: var(--tile) calc(var(--tile) * 7);
|
background-position: var(--tile) calc(var(--tile) * 7);
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,6 +270,10 @@ class Feature {
|
||||||
if (!this.ui.isOnScreen(this._umap._leafletMap.getBounds())) this.zoomTo(event)
|
if (!this.ui.isOnScreen(this._umap._leafletMap.getBounds())) this.zoomTo(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleEditing() {
|
||||||
|
this.edit()
|
||||||
|
}
|
||||||
|
|
||||||
getAdvancedEditActions(container) {
|
getAdvancedEditActions(container) {
|
||||||
const button = Utils.loadTemplate(`
|
const button = Utils.loadTemplate(`
|
||||||
<button class="button" type="button">
|
<button class="button" type="button">
|
||||||
|
@ -508,8 +512,19 @@ class Feature {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getInplaceToolbarActions() {
|
getInplaceEditMenu() {
|
||||||
return [U.ToggleEditAction, U.DeleteFeatureAction]
|
return [
|
||||||
|
{
|
||||||
|
action: () => this.toggleEditing(),
|
||||||
|
title: translate('Toggle edit mode (⇧+Click)'),
|
||||||
|
icon: 'icon-edit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: () => this.confirmDelete(),
|
||||||
|
title: translate('Delete this feature'),
|
||||||
|
icon: 'icon-delete',
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
isFiltered() {
|
isFiltered() {
|
||||||
|
@ -785,7 +800,7 @@ class Path extends Feature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggleEditing(event) {
|
toggleEditing(event) {
|
||||||
if (this._umap.editEnabled) {
|
if (this._umap.editEnabled) {
|
||||||
if (this.ui.editEnabled()) {
|
if (this.ui.editEnabled()) {
|
||||||
this.endEdit()
|
this.endEdit()
|
||||||
|
@ -795,7 +810,7 @@ class Path extends Feature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME: disable when disabling global edit
|
// FIXME: disable when disabling global edit
|
||||||
L.DomEvent.stop(event)
|
// L.DomEvent.stop(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
getShapeOptions() {
|
getShapeOptions() {
|
||||||
|
@ -846,15 +861,33 @@ class Path extends Feature {
|
||||||
return other
|
return other
|
||||||
}
|
}
|
||||||
|
|
||||||
getInplaceToolbarActions(event) {
|
getInplaceEditMenu(event) {
|
||||||
const items = super.getInplaceToolbarActions(event)
|
const items = super.getInplaceEditMenu()
|
||||||
if (this.isMulti()) {
|
if (this.isMulti()) {
|
||||||
items.push(U.DeleteShapeAction)
|
items.push({
|
||||||
items.push(U.ExtractShapeFromMultiAction)
|
action: () => this.ui.enableEdit().deleteShapeAt(event.latlng),
|
||||||
|
title: translate('Delete this shape'),
|
||||||
|
icon: 'icon-delete-shape',
|
||||||
|
})
|
||||||
|
items.push({
|
||||||
|
action: () => this.ui.isolateShape(event.latlng),
|
||||||
|
title: translate('Extract shape to separate feature'),
|
||||||
|
icon: 'icon-extract-shape',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getInplaceEditVertexMenu(event) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
action: () => event.vertex.delete(),
|
||||||
|
title: translate('Delete this vertex (Alt+Click)'),
|
||||||
|
icon: 'icon-delete-vertex',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
zoomTo({ easing, callback }) {
|
zoomTo({ easing, callback }) {
|
||||||
// Use bounds instead of centroid for paths.
|
// Use bounds instead of centroid for paths.
|
||||||
easing = easing || this._umap.getProperty('easing')
|
easing = easing || this._umap.getProperty('easing')
|
||||||
|
@ -1077,6 +1110,25 @@ export class LineString extends Path {
|
||||||
const [gain, loss] = this.ui.getElevation()
|
const [gain, loss] = this.ui.getElevation()
|
||||||
return Object.assign({ gain, loss }, super.extendedProperties())
|
return Object.assign({ gain, loss }, super.extendedProperties())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getInplaceEditVertexMenu(event) {
|
||||||
|
const items = super.getInplaceEditVertexMenu(event)
|
||||||
|
const index = event.vertex.getIndex()
|
||||||
|
if (index === 0 || index === event.vertex.getLastIndex()) {
|
||||||
|
items.push({
|
||||||
|
action: () => event.vertex.continue(),
|
||||||
|
title: translate('Continue line'),
|
||||||
|
icon: 'icon-continue-line',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
items.push({
|
||||||
|
action: () => event.vertex.split(),
|
||||||
|
title: translate('Split line'),
|
||||||
|
icon: 'icon-split-line',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Polygon extends Path {
|
export class Polygon extends Path {
|
||||||
|
@ -1182,9 +1234,13 @@ export class Polygon extends Path {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getInplaceToolbarActions(event) {
|
getInplaceEditMenu(event) {
|
||||||
const items = super.getInplaceToolbarActions(event)
|
const items = super.getInplaceEditMenu()
|
||||||
items.push(U.CreateHoleAction)
|
items.push({
|
||||||
|
action: () => this.ui.startHole(event),
|
||||||
|
title: translate('Start a hole here'),
|
||||||
|
icon: 'icon-hole',
|
||||||
|
})
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -250,7 +250,6 @@ export const LeafletMap = BaseMap.extend({
|
||||||
DomEvent.on(document.body, 'dataload', (event) =>
|
DomEvent.on(document.body, 'dataload', (event) =>
|
||||||
this.fire('dataload', event.detail)
|
this.fire('dataload', event.detail)
|
||||||
)
|
)
|
||||||
this.on('click', this.closeInplaceToolbar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.on('baselayerchange', (e) => {
|
this.on('baselayerchange', (e) => {
|
||||||
|
@ -284,11 +283,6 @@ export const LeafletMap = BaseMap.extend({
|
||||||
this.handleLimitBounds()
|
this.handleLimitBounds()
|
||||||
},
|
},
|
||||||
|
|
||||||
closeInplaceToolbar: function () {
|
|
||||||
const toolbar = this._toolbars[L.Toolbar.Popup._toolbar_class_id]
|
|
||||||
if (toolbar) toolbar.remove()
|
|
||||||
},
|
|
||||||
|
|
||||||
latLng: (a, b, c) => {
|
latLng: (a, b, c) => {
|
||||||
// manage geojson case and call original method
|
// manage geojson case and call original method
|
||||||
if (!(a instanceof L.LatLng) && a.coordinates) {
|
if (!(a instanceof L.LatLng) && a.coordinates) {
|
||||||
|
|
|
@ -64,11 +64,10 @@ const FeatureMixin = {
|
||||||
else this.feature.edit(event)
|
else this.feature.edit(event)
|
||||||
}
|
}
|
||||||
} else if (!this._map.editTools?.drawing()) {
|
} else if (!this._map.editTools?.drawing()) {
|
||||||
new L.Toolbar.Popup(event.latlng, {
|
this._map._umap.editContextmenu.open(
|
||||||
className: 'leaflet-inplace-toolbar',
|
event.originalEvent,
|
||||||
anchor: this.getPopupToolbarAnchor(),
|
this.feature.getInplaceEditMenu(event)
|
||||||
actions: this.feature.getInplaceToolbarActions(event),
|
)
|
||||||
}).addTo(this._map, this.feature, event.latlng)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DomEvent.stop(event)
|
DomEvent.stop(event)
|
||||||
|
@ -105,8 +104,6 @@ const FeatureMixin = {
|
||||||
this.feature.pullGeometry(false)
|
this.feature.pullGeometry(false)
|
||||||
this.feature.onCommit()
|
this.feature.onCommit()
|
||||||
},
|
},
|
||||||
|
|
||||||
getPopupToolbarAnchor: () => [0, 0],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PointMixin = {
|
const PointMixin = {
|
||||||
|
@ -248,10 +245,6 @@ export const LeafletMarker = Marker.extend({
|
||||||
this._redraw()
|
this._redraw()
|
||||||
this._resetZIndex()
|
this._resetZIndex()
|
||||||
},
|
},
|
||||||
|
|
||||||
getPopupToolbarAnchor: function () {
|
|
||||||
return this.options.icon.options.popupAnchor
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const PathMixin = {
|
const PathMixin = {
|
||||||
|
@ -341,13 +334,11 @@ const PathMixin = {
|
||||||
this.resetTooltip()
|
this.resetTooltip()
|
||||||
},
|
},
|
||||||
|
|
||||||
getVertexActions: () => [U.DeleteVertexAction],
|
|
||||||
|
|
||||||
onVertexRawClick: function (event) {
|
onVertexRawClick: function (event) {
|
||||||
new L.Toolbar.Popup(event.latlng, {
|
this._map._umap.editContextmenu.open(
|
||||||
className: 'leaflet-inplace-toolbar',
|
event.originalEvent,
|
||||||
actions: this.getVertexActions(event),
|
this.feature.getInplaceEditVertexMenu(event)
|
||||||
}).addTo(this._map, this, event.latlng, event.vertex)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
isolateShape: function (atLatLng) {
|
isolateShape: function (atLatLng) {
|
||||||
|
@ -383,17 +374,6 @@ export const LeafletPolyline = Polyline.extend({
|
||||||
|
|
||||||
getClass: () => LeafletPolyline,
|
getClass: () => LeafletPolyline,
|
||||||
|
|
||||||
getVertexActions: function (event) {
|
|
||||||
const actions = PathMixin.getVertexActions.call(this, event)
|
|
||||||
const index = event.vertex.getIndex()
|
|
||||||
if (index === 0 || index === event.vertex.getLastIndex()) {
|
|
||||||
actions.push(U.ContinueLineAction)
|
|
||||||
} else {
|
|
||||||
actions.push(U.SplitLineAction)
|
|
||||||
}
|
|
||||||
return actions
|
|
||||||
},
|
|
||||||
|
|
||||||
getMeasure: function (shape) {
|
getMeasure: function (shape) {
|
||||||
let shapes
|
let shapes
|
||||||
if (shape) {
|
if (shape) {
|
||||||
|
|
|
@ -10,6 +10,9 @@ export default class ContextMenu extends Positioned {
|
||||||
if (options.className) {
|
if (options.className) {
|
||||||
this.container.classList.add(options.className)
|
this.container.classList.add(options.className)
|
||||||
}
|
}
|
||||||
|
if (options.orientation === 'rows') {
|
||||||
|
this.container.classList.add('umap-contextmenu-rows')
|
||||||
|
}
|
||||||
this.container.addEventListener('focusout', (event) => {
|
this.container.addEventListener('focusout', (event) => {
|
||||||
if (!this.container.contains(event.relatedTarget)) this.close()
|
if (!this.container.contains(event.relatedTarget)) this.close()
|
||||||
})
|
})
|
||||||
|
@ -37,10 +40,14 @@ export default class ContextMenu extends Positioned {
|
||||||
)
|
)
|
||||||
this.container.appendChild(li)
|
this.container.appendChild(li)
|
||||||
} else {
|
} else {
|
||||||
|
let content = item.label || ''
|
||||||
|
if (item.icon) {
|
||||||
|
content = `<i class="icon icon-16 ${item.icon}"></i>${content}`
|
||||||
|
}
|
||||||
const li = loadTemplate(
|
const li = loadTemplate(
|
||||||
`<li class="${item.className || ''}"><button tabindex="0" class="flat">${item.label}</button></li>`
|
`<li class="${item.className || ''}"><button tabindex="0" class="flat" title="${item.title || ''}">${content}</button></li>`
|
||||||
)
|
)
|
||||||
li.addEventListener('click', () => {
|
li.firstChild.addEventListener('click', () => {
|
||||||
this.close()
|
this.close()
|
||||||
item.action()
|
item.action()
|
||||||
})
|
})
|
||||||
|
|
|
@ -120,6 +120,7 @@ export default class Umap extends ServerStored {
|
||||||
)
|
)
|
||||||
this.tooltip = new Tooltip(this._leafletMap._controlContainer)
|
this.tooltip = new Tooltip(this._leafletMap._controlContainer)
|
||||||
this.contextmenu = new ContextMenu()
|
this.contextmenu = new ContextMenu()
|
||||||
|
this.editContextmenu = new ContextMenu({ className: 'dark', orientation: 'rows' })
|
||||||
this.server = new ServerRequest()
|
this.server = new ServerRequest()
|
||||||
this.request = new Request()
|
this.request = new Request()
|
||||||
this.facets = new Facets(this)
|
this.facets = new Facets(this)
|
||||||
|
@ -1299,7 +1300,6 @@ export default class Umap extends ServerStored {
|
||||||
this.editPanel.close()
|
this.editPanel.close()
|
||||||
this.fullPanel.close()
|
this.fullPanel.close()
|
||||||
this.sync.stop()
|
this.sync.stop()
|
||||||
this._leafletMap.closeInplaceToolbar()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fire(name) {
|
fire(name) {
|
||||||
|
|
|
@ -1,186 +1,3 @@
|
||||||
U.BaseFeatureAction = L.ToolbarAction.extend({
|
|
||||||
initialize: function (map, feature, latlng) {
|
|
||||||
this.map = map
|
|
||||||
this.feature = feature
|
|
||||||
this.latlng = latlng
|
|
||||||
L.ToolbarAction.prototype.initialize.call(this)
|
|
||||||
this.postInit()
|
|
||||||
},
|
|
||||||
|
|
||||||
postInit: () => {},
|
|
||||||
|
|
||||||
hideToolbar: function () {
|
|
||||||
this.map.removeLayer(this.toolbar)
|
|
||||||
},
|
|
||||||
|
|
||||||
addHooks: function () {
|
|
||||||
this.onClick({ latlng: this.latlng })
|
|
||||||
this.hideToolbar()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.CreateHoleAction = U.BaseFeatureAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-new-hole',
|
|
||||||
tooltip: L._('Start a hole here'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function (event) {
|
|
||||||
this.feature.ui.startHole(event)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.ToggleEditAction = U.BaseFeatureAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-toggle-edit',
|
|
||||||
tooltip: L._('Toggle edit mode (⇧+Click)'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function (event) {
|
|
||||||
if (this.feature._toggleEditing) {
|
|
||||||
this.feature._toggleEditing(event) // Path
|
|
||||||
} else {
|
|
||||||
this.feature.edit(event) // Marker
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.DeleteFeatureAction = U.BaseFeatureAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-delete-all',
|
|
||||||
tooltip: L._('Delete this feature'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
postInit: function () {
|
|
||||||
if (!this.feature.isMulti())
|
|
||||||
this.options.toolbarIcon.className = 'umap-delete-one-of-one'
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function (e) {
|
|
||||||
this.feature.confirmDelete(e)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.DeleteShapeAction = U.BaseFeatureAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-delete-one-of-multi',
|
|
||||||
tooltip: L._('Delete this shape'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function (e) {
|
|
||||||
this.feature.ui.enableEdit().deleteShapeAt(e.latlng)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.ExtractShapeFromMultiAction = U.BaseFeatureAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-extract-shape-from-multi',
|
|
||||||
tooltip: L._('Extract shape to separate feature'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function (e) {
|
|
||||||
this.feature.ui.isolateShape(e.latlng)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.BaseVertexAction = U.BaseFeatureAction.extend({
|
|
||||||
initialize: function (map, feature, latlng, vertex) {
|
|
||||||
this.vertex = vertex
|
|
||||||
U.BaseFeatureAction.prototype.initialize.call(this, map, feature, latlng)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.DeleteVertexAction = U.BaseVertexAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-delete-vertex',
|
|
||||||
tooltip: L._('Delete this vertex (Alt+Click)'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function () {
|
|
||||||
this.vertex.delete()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.SplitLineAction = U.BaseVertexAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-split-line',
|
|
||||||
tooltip: L._('Split line'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function () {
|
|
||||||
this.vertex.split()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.ContinueLineAction = U.BaseVertexAction.extend({
|
|
||||||
options: {
|
|
||||||
toolbarIcon: {
|
|
||||||
className: 'umap-continue-line',
|
|
||||||
tooltip: L._('Continue line'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function () {
|
|
||||||
this.vertex.continue()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Leaflet.Toolbar doesn't allow twice same toolbar class…
|
|
||||||
U.SettingsToolbar = L.Toolbar.Control.extend({})
|
|
||||||
U.DrawToolbar = L.Toolbar.Control.extend({
|
|
||||||
initialize: function (options) {
|
|
||||||
L.Toolbar.Control.prototype.initialize.call(this, options)
|
|
||||||
this.map = this.options.map
|
|
||||||
this.map.on('seteditedfeature', this.redraw, this)
|
|
||||||
},
|
|
||||||
|
|
||||||
appendToContainer: function (container) {
|
|
||||||
this.options.actions = []
|
|
||||||
if (this.map._umap.properties.enableMarkerDraw) {
|
|
||||||
this.options.actions.push(U.DrawMarkerAction)
|
|
||||||
}
|
|
||||||
if (this.map._umap.properties.enablePolylineDraw) {
|
|
||||||
this.options.actions.push(U.DrawPolylineAction)
|
|
||||||
if (
|
|
||||||
this.map._umap.editedFeature &&
|
|
||||||
this.map._umap.editedFeature instanceof U.LineString
|
|
||||||
) {
|
|
||||||
this.options.actions.push(U.AddPolylineShapeAction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.map._umap.properties.enablePolygonDraw) {
|
|
||||||
this.options.actions.push(U.DrawPolygonAction)
|
|
||||||
if (
|
|
||||||
this.map._umap.editedFeature &&
|
|
||||||
this.map._umap.editedFeature instanceof U.Polygon
|
|
||||||
) {
|
|
||||||
this.options.actions.push(U.AddPolygonShapeAction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
L.Toolbar.Control.prototype.appendToContainer.call(this, container)
|
|
||||||
},
|
|
||||||
|
|
||||||
redraw: function () {
|
|
||||||
const container = this._control.getContainer()
|
|
||||||
container.innerHTML = ''
|
|
||||||
this.appendToContainer(container)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.EditControl = L.Control.extend({
|
U.EditControl = L.Control.extend({
|
||||||
options: {
|
options: {
|
||||||
position: 'topright',
|
position: 'topright',
|
||||||
|
|
|
@ -475,9 +475,6 @@ ul.photon-autocomplete {
|
||||||
.layer-edit {
|
.layer-edit {
|
||||||
background-position: -50px -49px;
|
background-position: -50px -49px;
|
||||||
}
|
}
|
||||||
.umap-toggle-edit {
|
|
||||||
background-position: -44px -48px;
|
|
||||||
}
|
|
||||||
.readonly .layer-edit,
|
.readonly .layer-edit,
|
||||||
.off .layer-edit {
|
.off .layer-edit {
|
||||||
background-position: -50px -73px;
|
background-position: -50px -73px;
|
||||||
|
@ -486,28 +483,6 @@ ul.photon-autocomplete {
|
||||||
.off .layer-delete {
|
.off .layer-delete {
|
||||||
background-position: -122px -121px;
|
background-position: -122px -121px;
|
||||||
}
|
}
|
||||||
.umap-new-hole {
|
|
||||||
background-position: -71px -94px;
|
|
||||||
}
|
|
||||||
.umap-delete-one-of-multi {
|
|
||||||
background-position: -97px -70px;
|
|
||||||
}
|
|
||||||
.umap-delete-all,
|
|
||||||
.umap-delete-one-of-one {
|
|
||||||
background-position: -119px -48px;
|
|
||||||
}
|
|
||||||
.umap-delete-vertex {
|
|
||||||
background-position: -119px -94px;
|
|
||||||
}
|
|
||||||
.umap-continue-line {
|
|
||||||
background-position: -96px 1px;
|
|
||||||
}
|
|
||||||
.umap-split-line {
|
|
||||||
background-position: -119px -22px;
|
|
||||||
}
|
|
||||||
.umap-extract-shape-from-multi{
|
|
||||||
background-position: -119px 2px;
|
|
||||||
}
|
|
||||||
.umap-browser .feature-title {
|
.umap-browser .feature-title {
|
||||||
width: inherit;
|
width: inherit;
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
.leaflet-toolbar-0{list-style:none;padding-left:0;box-shadow:0 1px 5px rgba(0,0,0,.65)}.leaflet-toolbar-0>li{position:relative}.leaflet-toolbar-0>li>.leaflet-toolbar-icon{display:block;width:26px;height:26px;line-height:26px;margin-right:0;padding-right:0;border-right:0;text-align:center;text-decoration:none;background-color:#fff}.leaflet-toolbar-0>li>.leaflet-toolbar-icon:hover{background-color:#f4f4f4}.leaflet-toolbar-0 .leaflet-toolbar-1{display:none;list-style:none}.leaflet-toolbar-tip-container{margin:0 auto;height:12px;position:relative;overflow:hidden}.leaflet-toolbar-tip{width:12px;height:12px;margin:-6px auto 0;background-color:#fff;box-shadow:0 1px 5px rgba(0,0,0,.65);-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.leaflet-control-toolbar>li>.leaflet-toolbar-icon{border-bottom:1px solid #ccc}.leaflet-control-toolbar>li:first-child>.leaflet-toolbar-icon{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-control-toolbar>li:last-child>.leaflet-toolbar-icon{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-bottom-width:0}.leaflet-control-toolbar .leaflet-toolbar-1{margin:0;padding:0;position:absolute;left:26px;top:0;white-space:nowrap;height:26px}.leaflet-control-toolbar .leaflet-toolbar-1>li{display:inline-block}.leaflet-control-toolbar .leaflet-toolbar-1>li>.leaflet-toolbar-icon{display:block;background-color:#919187;border-left:1px solid #aaa;color:#fff;font:11px/19px "Helvetica Neue",Arial,Helvetica,sans-serif;line-height:26px;text-decoration:none;padding-left:10px;padding-right:10px;height:26px}.leaflet-control-toolbar .leaflet-toolbar-1>li>.leaflet-toolbar-icon:hover{background-color:#a0a098}.leaflet-popup-toolbar{position:relative}.leaflet-popup-toolbar>li{float:left}.leaflet-popup-toolbar>li:first-child>.leaflet-toolbar-icon{border-top-left-radius:4px;border-bottom-left-radius:4px}.leaflet-popup-toolbar>li:last-child>.leaflet-toolbar-icon{border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-width:0}.leaflet-popup-toolbar .leaflet-toolbar-1{position:absolute;top:26px;left:0;padding-left:0}.leaflet-popup-toolbar .leaflet-toolbar-1>li>.leaflet-toolbar-icon{position:relative;float:left;width:26px;height:26px}
|
|
File diff suppressed because one or more lines are too long
|
@ -12,8 +12,6 @@
|
||||||
href="{% static 'umap/vendors/editinosm/Leaflet.EditInOSM.css' %}" />
|
href="{% static 'umap/vendors/editinosm/Leaflet.EditInOSM.css' %}" />
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="{% static 'umap/vendors/minimap/Control.MiniMap.min.css' %}" />
|
href="{% static 'umap/vendors/minimap/Control.MiniMap.min.css' %}" />
|
||||||
<link rel="stylesheet"
|
|
||||||
href="{% static 'umap/vendors/toolbar/leaflet.toolbar.css' %}" />
|
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="{% static 'umap/vendors/measurable/Leaflet.Measurable.css' %}" />
|
href="{% static 'umap/vendors/measurable/Leaflet.Measurable.css' %}" />
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
<script src="{% static 'umap/vendors/photon/leaflet.photon.js' %}" defer></script>
|
<script src="{% static 'umap/vendors/photon/leaflet.photon.js' %}" defer></script>
|
||||||
<script src="{% static 'umap/vendors/fullscreen/Leaflet.fullscreen.min.js' %}"
|
<script src="{% static 'umap/vendors/fullscreen/Leaflet.fullscreen.min.js' %}"
|
||||||
defer></script>
|
defer></script>
|
||||||
<script src="{% static 'umap/vendors/toolbar/leaflet.toolbar.js' %}" defer></script>
|
|
||||||
<script src="{% static 'umap/vendors/measurable/Leaflet.Measurable.js' %}"
|
<script src="{% static 'umap/vendors/measurable/Leaflet.Measurable.js' %}"
|
||||||
defer></script>
|
defer></script>
|
||||||
<script src="{% static 'umap/vendors/iconlayers/iconLayers.js' %}" defer></script>
|
<script src="{% static 'umap/vendors/iconlayers/iconLayers.js' %}" defer></script>
|
||||||
|
|
|
@ -10,7 +10,7 @@ def test_draw_polygon(page, live_server, tilelayer):
|
||||||
page.goto(f"{live_server.url}/en/map/new/")
|
page.goto(f"{live_server.url}/en/map/new/")
|
||||||
|
|
||||||
# Click on the Draw a polygon button on a new map.
|
# Click on the Draw a polygon button on a new map.
|
||||||
create_path = page.locator(".umap-edit-bar ").get_by_title("Draw a polygon")
|
create_path = page.locator(".umap-edit-bar").get_by_title("Draw a polygon")
|
||||||
create_path.click()
|
create_path.click()
|
||||||
|
|
||||||
# Check no polygon is present by default.
|
# Check no polygon is present by default.
|
||||||
|
@ -180,7 +180,7 @@ def test_can_draw_hole(page, live_server, tilelayer):
|
||||||
|
|
||||||
# First vertex of the hole will be created here
|
# First vertex of the hole will be created here
|
||||||
map.click(position={"x": 180, "y": 120})
|
map.click(position={"x": 180, "y": 120})
|
||||||
page.get_by_role("link", name="Start a hole here").click()
|
page.get_by_role("button", name="Start a hole here").click()
|
||||||
map.click(position={"x": 180, "y": 180})
|
map.click(position={"x": 180, "y": 180})
|
||||||
map.click(position={"x": 120, "y": 180})
|
map.click(position={"x": 120, "y": 180})
|
||||||
map.click(position={"x": 120, "y": 120})
|
map.click(position={"x": 120, "y": 120})
|
||||||
|
@ -475,7 +475,7 @@ def test_vertexmarker_not_shown_if_too_many(live_server, map, page, settings):
|
||||||
page.locator('select[name="format"]').select_option("geojson")
|
page.locator('select[name="format"]').select_option("geojson")
|
||||||
page.get_by_role("button", name="Import data", exact=True).click()
|
page.get_by_role("button", name="Import data", exact=True).click()
|
||||||
page.locator("path").click()
|
page.locator("path").click()
|
||||||
page.get_by_role("link", name="Toggle edit mode (⇧+Click)").click()
|
page.get_by_role("button", name="Toggle edit mode (⇧+Click)").click()
|
||||||
expect(page.locator(".umap-tooltip-container")).to_contain_text(
|
expect(page.locator(".umap-tooltip-container")).to_contain_text(
|
||||||
"Please zoom in to edit the geometry"
|
"Please zoom in to edit the geometry"
|
||||||
)
|
)
|
||||||
|
|
|
@ -329,11 +329,11 @@ def test_can_delete_shape_using_toolbar(live_server, page, tilelayer, settings):
|
||||||
|
|
||||||
# Now split the line
|
# Now split the line
|
||||||
map.click(position={"x": 100, "y": 100})
|
map.click(position={"x": 100, "y": 100})
|
||||||
page.get_by_role("link", name="Split line").click()
|
page.get_by_role("button", name="Split line").click()
|
||||||
|
|
||||||
# Delete part of it
|
# Delete part of it
|
||||||
map.click(position={"x": 125, "y": 100})
|
map.click(position={"x": 125, "y": 100})
|
||||||
page.get_by_role("link", name="Delete this shape").click()
|
page.get_by_role("button", name="Delete this shape").click()
|
||||||
data = save_and_get_json(page)
|
data = save_and_get_json(page)
|
||||||
assert len(data["features"]) == 1
|
assert len(data["features"]) == 1
|
||||||
assert data["features"][0]["geometry"]["type"] == "LineString"
|
assert data["features"][0]["geometry"]["type"] == "LineString"
|
||||||
|
|
|
@ -78,8 +78,8 @@ def test_marker_style_should_have_precedence(live_server, openmap, page, bootstr
|
||||||
def test_should_open_an_edit_toolbar_on_click(live_server, openmap, page, bootstrap):
|
def test_should_open_an_edit_toolbar_on_click(live_server, openmap, page, bootstrap):
|
||||||
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
|
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
|
||||||
page.locator(".leaflet-marker-icon").click()
|
page.locator(".leaflet-marker-icon").click()
|
||||||
expect(page.get_by_role("link", name="Toggle edit mode")).to_be_visible()
|
expect(page.get_by_role("button", name="Toggle edit mode")).to_be_visible()
|
||||||
expect(page.get_by_role("link", name="Delete this feature")).to_be_visible()
|
expect(page.get_by_role("button", name="Delete this feature")).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
def test_should_update_open_popup_on_edit(live_server, openmap, page, bootstrap):
|
def test_should_update_open_popup_on_edit(live_server, openmap, page, bootstrap):
|
||||||
|
@ -115,6 +115,6 @@ def test_should_follow_datalayer_style_when_changing_datalayer(
|
||||||
expect(marker).to_have_css("background-color", "rgb(0, 139, 139)")
|
expect(marker).to_have_css("background-color", "rgb(0, 139, 139)")
|
||||||
# Change datalayer
|
# Change datalayer
|
||||||
marker.click()
|
marker.click()
|
||||||
page.get_by_role("link", name="Toggle edit mode (⇧+Click)").click()
|
page.get_by_role("button", name="Toggle edit mode (⇧+Click)").click()
|
||||||
page.locator(".umap-field-datalayer select").select_option(label="other datalayer")
|
page.locator(".umap-field-datalayer select").select_option(label="other datalayer")
|
||||||
expect(marker).to_have_css("background-color", "rgb(148, 0, 211)")
|
expect(marker).to_have_css("background-color", "rgb(148, 0, 211)")
|
||||||
|
|
|
@ -88,8 +88,8 @@ def test_marker_style_should_have_precedence(live_server, openmap, page, bootstr
|
||||||
def test_should_open_an_edit_toolbar_on_click(live_server, openmap, page, bootstrap):
|
def test_should_open_an_edit_toolbar_on_click(live_server, openmap, page, bootstrap):
|
||||||
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
|
page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
|
||||||
page.locator("path").click()
|
page.locator("path").click()
|
||||||
expect(page.get_by_role("link", name="Toggle edit mode")).to_be_visible()
|
expect(page.get_by_role("button", name="Toggle edit mode")).to_be_visible()
|
||||||
expect(page.get_by_role("link", name="Delete this feature")).to_be_visible()
|
expect(page.get_by_role("button", name="Delete this feature")).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
def test_can_remove_stroke(live_server, openmap, page, bootstrap):
|
def test_can_remove_stroke(live_server, openmap, page, bootstrap):
|
||||||
|
@ -98,7 +98,7 @@ def test_can_remove_stroke(live_server, openmap, page, bootstrap):
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
page.locator("path").click()
|
page.locator("path").click()
|
||||||
page.get_by_role("link", name="Toggle edit mode").click()
|
page.get_by_role("button", name="Toggle edit mode").click()
|
||||||
page.get_by_text("Shape properties").click()
|
page.get_by_text("Shape properties").click()
|
||||||
page.locator(".umap-field-stroke .define").first.click()
|
page.locator(".umap-field-stroke .define").first.click()
|
||||||
page.locator(".umap-field-stroke .show-on-defined label").first.click()
|
page.locator(".umap-field-stroke .show-on-defined label").first.click()
|
||||||
|
|
|
@ -59,7 +59,7 @@ def test_websocket_connection_can_sync_markers(new_page, asgi_live_server, tilel
|
||||||
peerA.wait_for_timeout(300)
|
peerA.wait_for_timeout(300)
|
||||||
|
|
||||||
peerB.locator(".leaflet-marker-icon").first.click()
|
peerB.locator(".leaflet-marker-icon").first.click()
|
||||||
peerB.get_by_role("link", name="Toggle edit mode (⇧+Click)").click()
|
peerB.get_by_role("button", name="Toggle edit mode (⇧+Click)").click()
|
||||||
expect(peerB.locator('input[name="name"]')).to_have_value("Synced name")
|
expect(peerB.locator('input[name="name"]')).to_have_value("Synced name")
|
||||||
|
|
||||||
a_first_marker = peerA.locator("div:nth-child(4) > div:nth-child(2)").first
|
a_first_marker = peerA.locator("div:nth-child(4) > div:nth-child(2)").first
|
||||||
|
@ -139,7 +139,7 @@ def test_websocket_connection_can_sync_polygons(context, asgi_live_server, tilel
|
||||||
assert b_polygon_bbox_t1 == a_polygon_bbox_t1
|
assert b_polygon_bbox_t1 == a_polygon_bbox_t1
|
||||||
|
|
||||||
b_polygon.click()
|
b_polygon.click()
|
||||||
peerB.get_by_role("link", name="Toggle edit mode (⇧+Click)").click()
|
peerB.get_by_role("button", name="Toggle edit mode (⇧+Click)").click()
|
||||||
|
|
||||||
edited_vertex = peerB.locator("div:nth-child(6)").first
|
edited_vertex = peerB.locator("div:nth-child(6)").first
|
||||||
edited_vertex.drag_to(b_map_el, target_position={"x": 233, "y": 126})
|
edited_vertex.drag_to(b_map_el, target_position={"x": 233, "y": 126})
|
||||||
|
@ -153,7 +153,7 @@ def test_websocket_connection_can_sync_polygons(context, asgi_live_server, tilel
|
||||||
|
|
||||||
# Move the polygon on peer B and check it moved also on peer A
|
# Move the polygon on peer B and check it moved also on peer A
|
||||||
b_polygon.click()
|
b_polygon.click()
|
||||||
peerB.get_by_role("link", name="Toggle edit mode (⇧+Click)").click()
|
peerB.get_by_role("button", name="Toggle edit mode (⇧+Click)").click()
|
||||||
|
|
||||||
b_polygon.drag_to(b_map_el, target_position={"x": 400, "y": 400})
|
b_polygon.drag_to(b_map_el, target_position={"x": 400, "y": 400})
|
||||||
peerB.keyboard.press("Escape")
|
peerB.keyboard.press("Escape")
|
||||||
|
@ -343,7 +343,7 @@ def test_websocket_connection_can_sync_late_joining_peer(
|
||||||
|
|
||||||
# Verify marker properties
|
# Verify marker properties
|
||||||
peerB.locator(".leaflet-marker-icon").first.click()
|
peerB.locator(".leaflet-marker-icon").first.click()
|
||||||
peerB.get_by_role("link", name="Toggle edit mode (⇧+Click)").click()
|
peerB.get_by_role("button", name="Toggle edit mode (⇧+Click)").click()
|
||||||
expect(peerB.locator('input[name="name"]')).to_have_value("First marker")
|
expect(peerB.locator('input[name="name"]')).to_have_value("First marker")
|
||||||
|
|
||||||
# Verify polygon exists (we've already checked the count)
|
# Verify polygon exists (we've already checked the count)
|
||||||
|
|
Loading…
Reference in a new issue