mirror of
https://github.com/umap-project/umap.git
synced 2025-04-28 11:32:38 +02:00
wip: use our own contextmenu
This commit is contained in:
parent
c14ab4198f
commit
9d727bd01f
16 changed files with 262 additions and 295 deletions
|
@ -46,7 +46,6 @@
|
|||
"georsstogeojson": "^0.1.0",
|
||||
"jsdom": "^24.0.0",
|
||||
"leaflet": "1.9.4",
|
||||
"leaflet-contextmenu": "^1.4.0",
|
||||
"leaflet-editable": "^1.3.0",
|
||||
"leaflet-editinosm": "0.2.3",
|
||||
"leaflet-formbuilder": "0.2.10",
|
||||
|
|
|
@ -14,7 +14,6 @@ mkdir -p umap/static/umap/vendors/minimap/ && cp -r node_modules/leaflet-minimap
|
|||
mkdir -p umap/static/umap/vendors/loading/ && cp -r node_modules/leaflet-loading/src/Control.Loading.* umap/static/umap/vendors/loading/
|
||||
mkdir -p umap/static/umap/vendors/markercluster/ && cp -r node_modules/leaflet.markercluster/dist/leaflet.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/contextmenu/ && cp -r node_modules/leaflet-contextmenu/dist/leaflet.contextmenu.min.* umap/static/umap/vendors/contextmenu/
|
||||
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/toolbar/ && cp -r node_modules/leaflet-toolbar/dist/leaflet.toolbar.* umap/static/umap/vendors/toolbar/
|
||||
|
|
|
@ -9,3 +9,8 @@
|
|||
.umap-contextmenu li + li {
|
||||
margin-top: var(--text-margin);
|
||||
}
|
||||
|
||||
.umap-contextmenu hr {
|
||||
margin-top: var(--text-margin);
|
||||
margin-bottom: var(--text-margin);
|
||||
}
|
||||
|
|
|
@ -591,6 +591,55 @@ class Feature {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
getContextMenuItems(event) {
|
||||
const permalink = this.getPermalink()
|
||||
let items = []
|
||||
if (permalink) {
|
||||
items.push({
|
||||
label: translate('Permalink'),
|
||||
action: () => {
|
||||
window.open(permalink)
|
||||
},
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
label: translate('Copy as GeoJSON'),
|
||||
action: () => {
|
||||
L.Util.copyToClipboard(JSON.stringify(this.toGeoJSON()))
|
||||
this.map.tooltip.open({ content: L._('✅ Copied!') })
|
||||
},
|
||||
})
|
||||
if (this.map.editEnabled && !this.isReadOnly()) {
|
||||
items = items.concat(this.getContextMenuEditItems(event))
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
getContextMenuEditItems() {
|
||||
let items = ['-']
|
||||
if (this.map.editedFeature !== this) {
|
||||
items.push({
|
||||
label: `${translate('Edit this feature')} (⇧+Click)`,
|
||||
action: () => this.edit(),
|
||||
})
|
||||
}
|
||||
items = items.concat(
|
||||
{
|
||||
label: this.map.help.displayLabel('EDIT_FEATURE_LAYER'),
|
||||
action: () => this.datalayer.edit(),
|
||||
},
|
||||
{
|
||||
label: translate('Delete this feature'),
|
||||
action: () => this.confirmDelete(),
|
||||
},
|
||||
{
|
||||
label: translate('Clone this feature'),
|
||||
action: () => this.clone(),
|
||||
}
|
||||
)
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
export class Point extends Feature {
|
||||
|
@ -762,6 +811,62 @@ class Path extends Feature {
|
|||
}
|
||||
if (callback) callback.call(this)
|
||||
}
|
||||
|
||||
getContextMenuItems(event) {
|
||||
const items = super.getContextMenuItems(event)
|
||||
items.push({
|
||||
label: translate('Display measure'),
|
||||
action: () => Alert.info(this.ui.getMeasure()),
|
||||
})
|
||||
if (this.map.editEnabled && !this.isReadOnly() && this.isMulti()) {
|
||||
items.push(...this.getContextMenuMultiItems(event))
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
getContextMenuMultiItems(event) {
|
||||
const items = [
|
||||
'-',
|
||||
{
|
||||
label: translate('Remove shape from the multi'),
|
||||
action: () => {
|
||||
this.ui.enableEdit().deleteShapeAt(event.latlng)
|
||||
},
|
||||
},
|
||||
]
|
||||
const shape = this.ui.shapeAt(event.latlng)
|
||||
if (this.ui._latlngs.indexOf(shape) > 0) {
|
||||
items.push({
|
||||
label: translate('Make main shape'),
|
||||
action: () => {
|
||||
this.ui.enableEdit().deleteShape(shape)
|
||||
this.ui.editor.prependShape(shape)
|
||||
},
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
getContextMenuEditItems(event) {
|
||||
const items = super.getContextMenuEditItems(event)
|
||||
if (this.map?.editedFeature !== this && this.isSameClass(this.map.editedFeature)) {
|
||||
items.push({
|
||||
label: translate('Transfer shape to edited feature'),
|
||||
action: () => {
|
||||
this.transferShape(event.latlng, this.map.editedFeature)
|
||||
},
|
||||
})
|
||||
}
|
||||
if (this.isMulti()) {
|
||||
items.push({
|
||||
label: translate('Extract shape to separate feature'),
|
||||
action: () => {
|
||||
this.ui.isolateShape(event.latlng)
|
||||
},
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
export class LineString extends Path {
|
||||
|
@ -875,6 +980,41 @@ export class LineString extends Path {
|
|||
isMulti() {
|
||||
return !LineUtil.isFlat(this.coordinates) && this.coordinates.length > 1
|
||||
}
|
||||
|
||||
getContextMenuEditItems(event) {
|
||||
const items = super.getContextMenuEditItems(event)
|
||||
const vertexClicked = event.vertex
|
||||
if (!this.isMulti()) {
|
||||
items.push({
|
||||
label: translate('Transform to polygon'),
|
||||
action: () => this.toPolygon(),
|
||||
})
|
||||
}
|
||||
if (vertexClicked) {
|
||||
const index = event.vertex.getIndex()
|
||||
if (index !== 0 && index !== event.vertex.getLastIndex()) {
|
||||
items.push({
|
||||
label: translate('Split line'),
|
||||
action: () => event.vertex.split(),
|
||||
})
|
||||
} else if (index === 0 || index === event.vertex.getLastIndex()) {
|
||||
items.push({
|
||||
label: this.map.help.displayLabel('CONTINUE_LINE'),
|
||||
action: () => event.vertex.continue(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
getContextMenuMultiItems(event) {
|
||||
const items = super.getContextMenuMultiItems(event)
|
||||
items.push({
|
||||
label: translate('Merge lines'),
|
||||
action: () => this.mergeShapes(),
|
||||
})
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
export class Polygon extends Path {
|
||||
|
@ -985,4 +1125,21 @@ export class Polygon extends Path {
|
|||
items.push(U.CreateHoleAction)
|
||||
return items
|
||||
}
|
||||
|
||||
getContextMenuEditItems(event) {
|
||||
const items = super.getContextMenuEditItems(event)
|
||||
const shape = this.ui.shapeAt(event.latlng)
|
||||
// No multi and no holes.
|
||||
if (shape && !this.isMulti() && (LineUtil.isFlat(shape) || shape.length === 1)) {
|
||||
items.push({
|
||||
label: translate('Transform to lines'),
|
||||
action: () => this.toLineString(),
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
label: translate('Start a hole here'),
|
||||
action: () => this.ui.startHole(event),
|
||||
})
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
} 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'
|
||||
|
@ -43,6 +44,7 @@ window.U = {
|
|||
AutocompleteDatalist,
|
||||
Browser,
|
||||
Caption,
|
||||
ContextMenu,
|
||||
DataLayer,
|
||||
DataLayerPermissions,
|
||||
Dialog,
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
latLng,
|
||||
LatLng,
|
||||
LatLngBounds,
|
||||
DomEvent,
|
||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import { translate } from '../i18n.js'
|
||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||
|
@ -36,7 +37,7 @@ const FeatureMixin = {
|
|||
},
|
||||
|
||||
addInteractions: function () {
|
||||
this.on('contextmenu editable:vertex:contextmenu', this._showContextMenu)
|
||||
this.on('contextmenu editable:vertex:contextmenu', this.onContextMenu)
|
||||
this.on('click', this.onClick)
|
||||
},
|
||||
|
||||
|
@ -61,7 +62,7 @@ const FeatureMixin = {
|
|||
}).addTo(this._map, this.feature, event.latlng)
|
||||
}
|
||||
}
|
||||
L.DomEvent.stop(event)
|
||||
DomEvent.stop(event)
|
||||
},
|
||||
|
||||
resetTooltip: function () {
|
||||
|
@ -83,67 +84,14 @@ const FeatureMixin = {
|
|||
}
|
||||
},
|
||||
|
||||
_showContextMenu: function (event) {
|
||||
L.DomEvent.stop(event)
|
||||
const pt = this._map.mouseEventToContainerPoint(event.originalEvent)
|
||||
event.relatedTarget = this
|
||||
this._map.contextmenu.showAt(pt, event)
|
||||
},
|
||||
|
||||
getContextMenuItems: function (event) {
|
||||
const permalink = this.feature.getPermalink()
|
||||
let items = []
|
||||
if (permalink) {
|
||||
items.push({
|
||||
text: translate('Permalink'),
|
||||
callback: () => {
|
||||
window.open(permalink)
|
||||
},
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
text: translate('Copy as GeoJSON'),
|
||||
callback: () => {
|
||||
L.Util.copyToClipboard(JSON.stringify(this.feature.toGeoJSON()))
|
||||
this._map.tooltip.open({ content: L._('✅ Copied!') })
|
||||
},
|
||||
})
|
||||
if (this._map.editEnabled && !this.feature.isReadOnly()) {
|
||||
items = items.concat(this.getContextMenuEditItems(event))
|
||||
}
|
||||
return items
|
||||
},
|
||||
|
||||
getContextMenuEditItems: function () {
|
||||
let items = ['-']
|
||||
if (this._map.editedFeature !== this) {
|
||||
items.push({
|
||||
text: `${translate('Edit this feature')} (⇧+Click)`,
|
||||
callback: this.feature.edit,
|
||||
context: this.feature,
|
||||
iconCls: 'umap-edit',
|
||||
})
|
||||
}
|
||||
items = items.concat(
|
||||
{
|
||||
text: this._map.help.displayLabel('EDIT_FEATURE_LAYER'),
|
||||
callback: this.feature.datalayer.edit,
|
||||
context: this.feature.datalayer,
|
||||
iconCls: 'umap-edit',
|
||||
},
|
||||
{
|
||||
text: translate('Delete this feature'),
|
||||
callback: this.feature.confirmDelete,
|
||||
context: this.feature,
|
||||
iconCls: 'umap-delete',
|
||||
},
|
||||
{
|
||||
text: translate('Clone this feature'),
|
||||
callback: this.feature.clone,
|
||||
context: this.feature,
|
||||
}
|
||||
onContextMenu: function (event) {
|
||||
DomEvent.stop(event)
|
||||
const items = this._map.getContextMenuItems(event)
|
||||
items.push('-', ...this.feature.getContextMenuItems(event))
|
||||
this._map.contextmenu.open(
|
||||
[event.originalEvent.clientX, event.originalEvent.clientY],
|
||||
items
|
||||
)
|
||||
return items
|
||||
},
|
||||
|
||||
onCommit: function () {
|
||||
|
@ -360,65 +308,6 @@ const PathMixin = {
|
|||
}).addTo(this._map, this, event.latlng, event.vertex)
|
||||
},
|
||||
|
||||
getContextMenuItems: function (event) {
|
||||
let items = FeatureMixin.getContextMenuItems.call(this, event)
|
||||
items.push({
|
||||
text: translate('Display measure'),
|
||||
callback: () => Alert.info(this.getMeasure()),
|
||||
})
|
||||
if (this._map.editEnabled && !this.feature.isReadOnly() && this.feature.isMulti()) {
|
||||
items = items.concat(this.getContextMenuMultiItems(event))
|
||||
}
|
||||
return items
|
||||
},
|
||||
|
||||
getContextMenuMultiItems: function (event) {
|
||||
const items = [
|
||||
'-',
|
||||
{
|
||||
text: translate('Remove shape from the multi'),
|
||||
callback: () => {
|
||||
this.enableEdit().deleteShapeAt(event.latlng)
|
||||
},
|
||||
},
|
||||
]
|
||||
const shape = this.shapeAt(event.latlng)
|
||||
if (this._latlngs.indexOf(shape) > 0) {
|
||||
items.push({
|
||||
text: translate('Make main shape'),
|
||||
callback: () => {
|
||||
this.enableEdit().deleteShape(shape)
|
||||
this.editor.prependShape(shape)
|
||||
},
|
||||
})
|
||||
}
|
||||
return items
|
||||
},
|
||||
|
||||
getContextMenuEditItems: function (event) {
|
||||
const items = FeatureMixin.getContextMenuEditItems.call(this, event)
|
||||
if (
|
||||
this._map?.editedFeature !== this.feature &&
|
||||
this.feature.isSameClass(this._map.editedFeature)
|
||||
) {
|
||||
items.push({
|
||||
text: translate('Transfer shape to edited feature'),
|
||||
callback: () => {
|
||||
this.feature.transferShape(event.latlng, this._map.editedFeature)
|
||||
},
|
||||
})
|
||||
}
|
||||
if (this.feature.isMulti()) {
|
||||
items.push({
|
||||
text: translate('Extract shape to separate feature'),
|
||||
callback: () => {
|
||||
this.isolateShape(event.latlng)
|
||||
},
|
||||
})
|
||||
}
|
||||
return items
|
||||
},
|
||||
|
||||
isolateShape: function (atLatLng) {
|
||||
if (!this.feature.isMulti()) return
|
||||
const shape = this.enableEdit().deleteShapeAt(atLatLng)
|
||||
|
@ -463,46 +352,6 @@ export const LeafletPolyline = Polyline.extend({
|
|||
return actions
|
||||
},
|
||||
|
||||
getContextMenuEditItems: function (event) {
|
||||
const items = PathMixin.getContextMenuEditItems.call(this, event)
|
||||
const vertexClicked = event.vertex
|
||||
let index
|
||||
if (!this.feature.isMulti()) {
|
||||
items.push({
|
||||
text: translate('Transform to polygon'),
|
||||
callback: this.feature.toPolygon,
|
||||
context: this.feature,
|
||||
})
|
||||
}
|
||||
if (vertexClicked) {
|
||||
index = event.vertex.getIndex()
|
||||
if (index !== 0 && index !== event.vertex.getLastIndex()) {
|
||||
items.push({
|
||||
text: translate('Split line'),
|
||||
callback: event.vertex.split,
|
||||
context: event.vertex,
|
||||
})
|
||||
} else if (index === 0 || index === event.vertex.getLastIndex()) {
|
||||
items.push({
|
||||
text: this._map.help.displayLabel('CONTINUE_LINE'),
|
||||
callback: event.vertex.continue,
|
||||
context: event.vertex.continue,
|
||||
})
|
||||
}
|
||||
}
|
||||
return items
|
||||
},
|
||||
|
||||
getContextMenuMultiItems: function (event) {
|
||||
const items = PathMixin.getContextMenuMultiItems.call(this, event)
|
||||
items.push({
|
||||
text: translate('Merge lines'),
|
||||
callback: this.feature.mergeShapes,
|
||||
context: this.feature,
|
||||
})
|
||||
return items
|
||||
},
|
||||
|
||||
getMeasure: function (shape) {
|
||||
// FIXME: compute from data in feature (with TurfJS)
|
||||
const length = L.GeoUtil.lineLength(this._map, shape || this._defaultShape())
|
||||
|
@ -516,29 +365,6 @@ export const LeafletPolygon = Polygon.extend({
|
|||
|
||||
getClass: () => LeafletPolygon,
|
||||
|
||||
getContextMenuEditItems: function (event) {
|
||||
const items = PathMixin.getContextMenuEditItems.call(this, event)
|
||||
const shape = this.shapeAt(event.latlng)
|
||||
// No multi and no holes.
|
||||
if (
|
||||
shape &&
|
||||
!this.feature.isMulti() &&
|
||||
(LineUtil.isFlat(shape) || shape.length === 1)
|
||||
) {
|
||||
items.push({
|
||||
text: translate('Transform to lines'),
|
||||
callback: this.feature.toLineString,
|
||||
context: this.feature,
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
text: translate('Start a hole here'),
|
||||
callback: this.startHole,
|
||||
context: this,
|
||||
})
|
||||
return items
|
||||
},
|
||||
|
||||
startHole: function (event) {
|
||||
this.enableEdit().newHole(event.latlng)
|
||||
},
|
||||
|
|
|
@ -72,9 +72,9 @@ export class Positioned {
|
|||
left = x - this.container.offsetWidth
|
||||
}
|
||||
if (y < window.innerHeight / 2) {
|
||||
top = y
|
||||
top = Math.min(y, window.innerHeight - this.container.offsetHeight)
|
||||
} else {
|
||||
top = y - this.container.offsetHeight
|
||||
top = Math.max(0, y - this.container.offsetHeight)
|
||||
}
|
||||
this.setPosition({ left, top })
|
||||
}
|
||||
|
|
|
@ -18,14 +18,18 @@ export default class ContextMenu extends Positioned {
|
|||
open([x, y], items) {
|
||||
this.container.innerHTML = ''
|
||||
for (const item of items) {
|
||||
const li = loadTemplate(
|
||||
`<li class="${item.className || ''}"><button tabindex="0" class="flat">${item.label}</button></li>`
|
||||
)
|
||||
li.addEventListener('click', () => {
|
||||
this.close()
|
||||
item.action()
|
||||
})
|
||||
this.container.appendChild(li)
|
||||
if (item === '-') {
|
||||
this.container.appendChild(document.createElement('hr'))
|
||||
} else {
|
||||
const li = loadTemplate(
|
||||
`<li class="${item.className || ''}"><button tabindex="0" class="flat">${item.label}</button></li>`
|
||||
)
|
||||
li.addEventListener('click', () => {
|
||||
this.close()
|
||||
item.action()
|
||||
})
|
||||
this.container.appendChild(li)
|
||||
}
|
||||
}
|
||||
document.body.appendChild(this.container)
|
||||
this.computePosition([x, y])
|
||||
|
|
|
@ -1140,23 +1140,6 @@ L.Control.Loading.include({
|
|||
},
|
||||
})
|
||||
|
||||
/*
|
||||
* Make it dynamic
|
||||
*/
|
||||
U.ContextMenu = L.Map.ContextMenu.extend({
|
||||
_createItems: function (e) {
|
||||
this._map.setContextMenuItems(e)
|
||||
L.Map.ContextMenu.prototype._createItems.call(this)
|
||||
},
|
||||
|
||||
_showAtPoint: function (pt, e) {
|
||||
this._items = []
|
||||
this._container.innerHTML = ''
|
||||
this._createItems(e)
|
||||
L.Map.ContextMenu.prototype._showAtPoint.call(this, pt, e)
|
||||
},
|
||||
})
|
||||
|
||||
U.Editable = L.Editable.extend({
|
||||
initialize: function (map, options) {
|
||||
L.Editable.prototype.initialize.call(this, map, options)
|
||||
|
|
|
@ -58,6 +58,7 @@ U.Map = L.Map.extend({
|
|||
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)
|
||||
|
@ -197,8 +198,8 @@ U.Map = L.Map.extend({
|
|||
|
||||
window.onbeforeunload = () => (this.editEnabled && this.isDirty) || null
|
||||
this.backup()
|
||||
this.initContextMenu()
|
||||
this.on('click', this.closeInplaceToolbar)
|
||||
this.on('contextmenu', this.onContextMenu)
|
||||
},
|
||||
|
||||
initSyncEngine: async function () {
|
||||
|
@ -1679,118 +1680,107 @@ U.Map = L.Map.extend({
|
|||
this.loader.onAdd(this)
|
||||
},
|
||||
|
||||
initContextMenu: function () {
|
||||
this.contextmenu = new U.ContextMenu(this)
|
||||
this.contextmenu.enable()
|
||||
},
|
||||
|
||||
setContextMenuItems: function (e) {
|
||||
let items = []
|
||||
getContextMenuItems: function (event) {
|
||||
const items = []
|
||||
if (this._zoom !== this.getMaxZoom()) {
|
||||
items.push({
|
||||
text: L._('Zoom in'),
|
||||
callback: function () {
|
||||
this.zoomIn()
|
||||
},
|
||||
label: L._('Zoom in'),
|
||||
action: () => this.zoomIn(),
|
||||
})
|
||||
}
|
||||
if (this._zoom !== this.getMinZoom()) {
|
||||
items.push({
|
||||
text: L._('Zoom out'),
|
||||
callback: function () {
|
||||
this.zoomOut()
|
||||
},
|
||||
label: L._('Zoom out'),
|
||||
action: () => this.zoomOut(),
|
||||
})
|
||||
}
|
||||
if (e?.relatedTarget) {
|
||||
if (e.relatedTarget.getContextMenuItems) {
|
||||
items = items.concat(e.relatedTarget.getContextMenuItems(e))
|
||||
}
|
||||
}
|
||||
if (this.hasEditMode()) {
|
||||
items.push('-')
|
||||
if (this.editEnabled) {
|
||||
if (!this.isDirty) {
|
||||
items.push({
|
||||
text: this.help.displayLabel('STOP_EDIT'),
|
||||
callback: this.disableEdit,
|
||||
label: this.help.displayLabel('STOP_EDIT'),
|
||||
action: () => this.disableEdit(),
|
||||
})
|
||||
}
|
||||
if (this.options.enableMarkerDraw) {
|
||||
items.push({
|
||||
text: this.help.displayLabel('DRAW_MARKER'),
|
||||
callback: this.startMarker,
|
||||
context: this,
|
||||
label: this.help.displayLabel('DRAW_MARKER'),
|
||||
action: () => this.startMarker(event),
|
||||
})
|
||||
}
|
||||
if (this.options.enablePolylineDraw) {
|
||||
items.push({
|
||||
text: this.help.displayLabel('DRAW_POLYGON'),
|
||||
callback: this.startPolygon,
|
||||
context: this,
|
||||
label: this.help.displayLabel('DRAW_POLYGON'),
|
||||
action: () => this.startPolygon(event),
|
||||
})
|
||||
}
|
||||
if (this.options.enablePolygonDraw) {
|
||||
items.push({
|
||||
text: this.help.displayLabel('DRAW_LINE'),
|
||||
callback: this.startPolyline,
|
||||
context: this,
|
||||
label: this.help.displayLabel('DRAW_LINE'),
|
||||
action: () => this.startPolyline(event),
|
||||
})
|
||||
}
|
||||
items.push('-')
|
||||
items.push({
|
||||
text: L._('Help'),
|
||||
callback: function () {
|
||||
this.help.show('edit')
|
||||
},
|
||||
label: L._('Help'),
|
||||
action: () => this.help.show('edit'),
|
||||
})
|
||||
} else {
|
||||
items.push({
|
||||
text: this.help.displayLabel('TOGGLE_EDIT'),
|
||||
callback: this.enableEdit,
|
||||
label: this.help.displayLabel('TOGGLE_EDIT'),
|
||||
action: () => this.enableEdit(),
|
||||
})
|
||||
}
|
||||
}
|
||||
items.push(
|
||||
'-',
|
||||
{
|
||||
text: L._('Open browser'),
|
||||
callback: () => this.openBrowser('layers'),
|
||||
label: L._('Open browser'),
|
||||
action: () => this.openBrowser('layers'),
|
||||
},
|
||||
{
|
||||
text: L._('Browse data'),
|
||||
callback: () => this.openBrowser('data'),
|
||||
label: L._('Browse data'),
|
||||
action: () => this.openBrowser('data'),
|
||||
}
|
||||
)
|
||||
if (this.options.facetKey) {
|
||||
items.push({
|
||||
text: L._('Filter data'),
|
||||
callback: () => this.openBrowser('filters'),
|
||||
label: L._('Filter data'),
|
||||
action: () => this.openBrowser('filters'),
|
||||
})
|
||||
}
|
||||
items.push(
|
||||
{
|
||||
text: L._('Open caption'),
|
||||
callback: this.openCaption,
|
||||
label: L._('Open caption'),
|
||||
action: () => this.openCaption(),
|
||||
},
|
||||
{
|
||||
text: this.help.displayLabel('SEARCH'),
|
||||
callback: this.search,
|
||||
label: this.help.displayLabel('SEARCH'),
|
||||
action: () => this.search(event),
|
||||
}
|
||||
)
|
||||
if (this.options.urls.routing) {
|
||||
items.push('-', {
|
||||
text: L._('Directions from here'),
|
||||
callback: this.openExternalRouting,
|
||||
label: L._('Directions from here'),
|
||||
action: () => this.openExternalRouting(event),
|
||||
})
|
||||
}
|
||||
if (this.options.urls.edit_in_osm) {
|
||||
items.push('-', {
|
||||
text: L._('Edit in OpenStreetMap'),
|
||||
callback: this.editInOSM,
|
||||
label: L._('Edit in OpenStreetMap'),
|
||||
action: () => this.editInOSM(event),
|
||||
})
|
||||
}
|
||||
this.options.contextmenuItems = items
|
||||
return items
|
||||
},
|
||||
|
||||
onContextMenu: function (event) {
|
||||
const items = this.getContextMenuItems(event)
|
||||
this.contextmenu.open(
|
||||
[event.originalEvent.clientX, event.originalEvent.clientY],
|
||||
items
|
||||
)
|
||||
},
|
||||
|
||||
editInOSM: function (e) {
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.leaflet-contextmenu{display:none;box-shadow:0 1px 7px rgba(0,0,0,0.4);-webkit-border-radius:4px;border-radius:4px;padding:4px 0;background-color:#fff;cursor:default;-webkit-user-select:none;-moz-user-select:none;user-select:none}.leaflet-contextmenu a.leaflet-contextmenu-item{display:block;color:#222;font-size:12px;line-height:20px;text-decoration:none;padding:0 12px;border-top:1px solid transparent;border-bottom:1px solid transparent;cursor:default;outline:0}.leaflet-contextmenu a.leaflet-contextmenu-item-disabled{opacity:.5}.leaflet-contextmenu a.leaflet-contextmenu-item.over{background-color:#f4f4f4;border-top:1px solid #f0f0f0;border-bottom:1px solid #f0f0f0}.leaflet-contextmenu a.leaflet-contextmenu-item-disabled.over{background-color:inherit;border-top:1px solid transparent;border-bottom:1px solid transparent}.leaflet-contextmenu-icon{margin:2px 8px 0 0;width:16px;height:16px;float:left;border:0}.leaflet-contextmenu-separator{border-bottom:1px solid #ccc;margin:5px 0}
|
File diff suppressed because one or more lines are too long
|
@ -25,8 +25,6 @@
|
|||
<script src="{% static 'umap/vendors/csv2geojson/csv2geojson.js' %}" defer></script>
|
||||
<script src="{% static 'umap/vendors/osmtogeojson/osmtogeojson.js' %}" defer></script>
|
||||
<script src="{% static 'umap/vendors/loading/Control.Loading.js' %}" defer></script>
|
||||
<script src="{% static 'umap/vendors/contextmenu/leaflet.contextmenu.min.js' %}"
|
||||
defer></script>
|
||||
<script src="{% static 'umap/vendors/photon/leaflet.photon.js' %}" defer></script>
|
||||
<script src="{% static 'umap/vendors/georsstogeojson/GeoRSSToGeoJSON.js' %}"
|
||||
defer></script>
|
||||
|
|
|
@ -161,8 +161,10 @@ def test_can_draw_multi(live_server, page, tilelayer):
|
|||
page.keyboard.press("Escape")
|
||||
expect(multi_button).to_be_hidden()
|
||||
polygons.first.click(button="right", position={"x": 10, "y": 10})
|
||||
expect(page.get_by_role("link", name="Transform to lines")).to_be_hidden()
|
||||
expect(page.get_by_role("link", name="Remove shape from the multi")).to_be_visible()
|
||||
expect(page.get_by_role("button", name="Transform to lines")).to_be_hidden()
|
||||
expect(
|
||||
page.get_by_role("button", name="Remove shape from the multi")
|
||||
).to_be_visible()
|
||||
|
||||
|
||||
def test_can_draw_hole(page, live_server, tilelayer):
|
||||
|
@ -196,7 +198,7 @@ def test_can_draw_hole(page, live_server, tilelayer):
|
|||
expect(vertices).to_have_count(8)
|
||||
# Click on the polygon but not in the hole
|
||||
polygons.first.click(button="right", position={"x": 10, "y": 10})
|
||||
expect(page.get_by_role("link", name="Transform to lines")).to_be_hidden()
|
||||
expect(page.get_by_role("button", name="Transform to lines")).to_be_hidden()
|
||||
|
||||
|
||||
def test_can_transfer_shape_from_simple_polygon(live_server, page, tilelayer):
|
||||
|
@ -228,7 +230,7 @@ def test_can_transfer_shape_from_simple_polygon(live_server, page, tilelayer):
|
|||
# Now that polygon 2 is selected, right click on first one
|
||||
# and transfer shape
|
||||
polygons.first.click(position={"x": 20, "y": 20}, button="right")
|
||||
page.get_by_role("link", name="Transfer shape to edited feature").click()
|
||||
page.get_by_role("button", name="Transfer shape to edited feature").click()
|
||||
expect(polygons).to_have_count(1)
|
||||
|
||||
|
||||
|
@ -246,7 +248,9 @@ def test_can_extract_shape(live_server, page, tilelayer, settings):
|
|||
# Click again to finish
|
||||
map.click(position={"x": 100, "y": 100})
|
||||
expect(polygons).to_have_count(1)
|
||||
extract_button = page.get_by_role("link", name="Extract shape to separate feature")
|
||||
extract_button = page.get_by_role(
|
||||
"button", name="Extract shape to separate feature"
|
||||
)
|
||||
expect(extract_button).to_be_hidden()
|
||||
page.get_by_title("Add a polygon to the current multi").click()
|
||||
map.click(position={"x": 250, "y": 200})
|
||||
|
@ -326,7 +330,9 @@ def test_cannot_transfer_shape_to_line(live_server, page, tilelayer):
|
|||
# Click again to finish
|
||||
map.click(position={"x": 100, "y": 100})
|
||||
expect(polygons).to_have_count(1)
|
||||
extract_button = page.get_by_role("link", name="Extract shape to separate feature")
|
||||
extract_button = page.get_by_role(
|
||||
"button", name="Extract shape to separate feature"
|
||||
)
|
||||
polygons.first.click(position={"x": 20, "y": 20}, button="right")
|
||||
expect(extract_button).to_be_hidden()
|
||||
page.get_by_title("Draw a polyline").click()
|
||||
|
@ -352,7 +358,9 @@ def test_cannot_transfer_shape_to_marker(live_server, page, tilelayer):
|
|||
# Click again to finish
|
||||
map.click(position={"x": 100, "y": 100})
|
||||
expect(polygons).to_have_count(1)
|
||||
extract_button = page.get_by_role("link", name="Extract shape to separate feature")
|
||||
extract_button = page.get_by_role(
|
||||
"button", name="Extract shape to separate feature"
|
||||
)
|
||||
polygons.first.click(position={"x": 20, "y": 20}, button="right")
|
||||
expect(extract_button).to_be_hidden()
|
||||
page.get_by_title("Draw a marker").click()
|
||||
|
@ -377,7 +385,7 @@ def test_can_clone_polygon(live_server, page, tilelayer, settings):
|
|||
map.click(position={"x": 100, "y": 100})
|
||||
expect(polygons).to_have_count(1)
|
||||
polygons.first.click(button="right")
|
||||
page.get_by_role("link", name="Clone this feature").click()
|
||||
page.get_by_role("button", name="Clone this feature").click()
|
||||
expect(polygons).to_have_count(2)
|
||||
data = save_and_get_json(page)
|
||||
assert len(data["features"]) == 2
|
||||
|
@ -402,7 +410,7 @@ def test_can_transform_polygon_to_line(live_server, page, tilelayer, settings):
|
|||
expect(polygons).to_have_count(1)
|
||||
expect(paths).to_have_count(1)
|
||||
polygons.first.click(button="right")
|
||||
page.get_by_role("link", name="Transform to lines").click()
|
||||
page.get_by_role("button", name="Transform to lines").click()
|
||||
# No more polygons (will fill), but one path, it must be a line
|
||||
expect(polygons).to_have_count(0)
|
||||
expect(paths).to_have_count(1)
|
||||
|
|
|
@ -157,8 +157,10 @@ def test_can_draw_multi(live_server, page, tilelayer):
|
|||
page.keyboard.press("Escape")
|
||||
expect(add_shape).to_be_hidden()
|
||||
lines.first.click(button="right", position={"x": 10, "y": 1})
|
||||
expect(page.get_by_role("link", name="Transform to polygon")).to_be_hidden()
|
||||
expect(page.get_by_role("link", name="Remove shape from the multi")).to_be_visible()
|
||||
expect(page.get_by_role("button", name="Transform to polygon")).to_be_hidden()
|
||||
expect(
|
||||
page.get_by_role("button", name="Remove shape from the multi")
|
||||
).to_be_visible()
|
||||
|
||||
|
||||
def test_can_transfer_shape_from_simple_polyline(live_server, page, tilelayer):
|
||||
|
@ -188,7 +190,7 @@ def test_can_transfer_shape_from_simple_polyline(live_server, page, tilelayer):
|
|||
# Now that line 2 is selected, right click on first one
|
||||
# and transfer shape
|
||||
lines.first.click(position={"x": 10, "y": 1}, button="right")
|
||||
page.get_by_role("link", name="Transfer shape to edited feature").click()
|
||||
page.get_by_role("button", name="Transfer shape to edited feature").click()
|
||||
expect(lines).to_have_count(1)
|
||||
|
||||
|
||||
|
@ -227,7 +229,7 @@ def test_can_transfer_shape_from_multi(live_server, page, tilelayer, settings):
|
|||
# Now that line 2 is selected, right click on first one
|
||||
# and transfer shape
|
||||
lines.first.click(position={"x": 10, "y": 1}, button="right")
|
||||
page.get_by_role("link", name="Transfer shape to edited feature").click()
|
||||
page.get_by_role("button", name="Transfer shape to edited feature").click()
|
||||
expect(lines).to_have_count(2)
|
||||
data = save_and_get_json(page)
|
||||
assert data["features"][0]["geometry"] == {
|
||||
|
@ -259,7 +261,9 @@ def test_can_extract_shape(live_server, page, tilelayer):
|
|||
# Click again to finish
|
||||
map.click(position={"x": 100, "y": 200})
|
||||
expect(lines).to_have_count(1)
|
||||
extract_button = page.get_by_role("link", name="Extract shape to separate feature")
|
||||
extract_button = page.get_by_role(
|
||||
"button", name="Extract shape to separate feature"
|
||||
)
|
||||
expect(extract_button).to_be_hidden()
|
||||
page.get_by_title("Add a line to the current multi").click()
|
||||
map.click(position={"x": 250, "y": 250})
|
||||
|
@ -287,7 +291,7 @@ def test_can_clone_polyline(live_server, page, tilelayer, settings):
|
|||
map.click(position={"x": 100, "y": 200})
|
||||
expect(lines).to_have_count(1)
|
||||
lines.first.click(position={"x": 10, "y": 1}, button="right")
|
||||
page.get_by_role("link", name="Clone this feature").click()
|
||||
page.get_by_role("button", name="Clone this feature").click()
|
||||
expect(lines).to_have_count(2)
|
||||
data = save_and_get_json(page)
|
||||
assert len(data["features"]) == 2
|
||||
|
@ -313,7 +317,7 @@ def test_can_transform_polyline_to_polygon(live_server, page, tilelayer, setting
|
|||
expect(paths).to_have_count(1)
|
||||
expect(polygons).to_have_count(0)
|
||||
paths.first.click(position={"x": 10, "y": 1}, button="right")
|
||||
page.get_by_role("link", name="Transform to polygon").click()
|
||||
page.get_by_role("button", name="Transform to polygon").click()
|
||||
expect(polygons).to_have_count(1)
|
||||
expect(paths).to_have_count(1)
|
||||
data = save_and_get_json(page)
|
||||
|
|
|
@ -69,7 +69,7 @@ def test_websocket_connection_can_sync_markers(
|
|||
|
||||
# Delete a marker from peer A and check it's been deleted on peer B
|
||||
a_first_marker.click(button="right")
|
||||
peerA.get_by_role("link", name="Delete this feature").click()
|
||||
peerA.get_by_role("button", name="Delete this feature").click()
|
||||
peerA.locator("dialog").get_by_role("button", name="OK").click()
|
||||
expect(a_marker_pane).to_have_count(1)
|
||||
expect(b_marker_pane).to_have_count(1)
|
||||
|
@ -153,7 +153,7 @@ def test_websocket_connection_can_sync_polygons(
|
|||
|
||||
# Delete a polygon from peer A and check it's been deleted on peer B
|
||||
a_polygon.click(button="right")
|
||||
peerA.get_by_role("link", name="Delete this feature").click()
|
||||
peerA.get_by_role("button", name="Delete this feature").click()
|
||||
peerA.locator("dialog").get_by_role("button", name="OK").click()
|
||||
expect(a_polygons).to_have_count(0)
|
||||
expect(b_polygons).to_have_count(0)
|
||||
|
@ -268,7 +268,7 @@ def test_websocket_connection_can_sync_cloned_polygons(
|
|||
|
||||
# Clone on peer B and save
|
||||
b_polygon.click(button="right")
|
||||
peerB.get_by_role("link", name="Clone this feature").click()
|
||||
peerB.get_by_role("button", name="Clone this feature").click()
|
||||
|
||||
expect(peerB.locator("path")).to_have_count(2)
|
||||
|
||||
|
|
Loading…
Reference in a new issue