mirror of
https://github.com/umap-project/umap.git
synced 2025-04-29 03:42:37 +02:00
chore: move help to a separate module
This commit is contained in:
parent
d3599fbe9e
commit
c70951a994
3 changed files with 232 additions and 271 deletions
|
@ -12,6 +12,7 @@ import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './req
|
|||
import { AjaxAutocomplete, AjaxAutocompleteMultiple } from './autocomplete.js'
|
||||
import Orderable from './orderable.js'
|
||||
import Importer from './importer.js'
|
||||
import Help from './help.js'
|
||||
|
||||
// Import modules and export them to the global scope.
|
||||
// For the not yet module-compatible JS out there.
|
||||
|
@ -38,4 +39,5 @@ window.U = {
|
|||
Caption,
|
||||
AjaxAutocomplete,
|
||||
AjaxAutocompleteMultiple,
|
||||
Help,
|
||||
}
|
||||
|
|
230
umap/static/umap/js/modules/help.js
Normal file
230
umap/static/umap/js/modules/help.js
Normal file
|
@ -0,0 +1,230 @@
|
|||
import { DomUtil, DomEvent } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import { translate } from './i18n.js'
|
||||
|
||||
const SHORTCUTS = {
|
||||
DRAW_MARKER: {
|
||||
shortcut: 'Modifier+M',
|
||||
label: translate('Draw a marker'),
|
||||
},
|
||||
DRAW_LINE: {
|
||||
shortcut: 'Modifier+L',
|
||||
label: translate('Draw a polyline'),
|
||||
},
|
||||
DRAW_POLYGON: {
|
||||
shortcut: 'Modifier+P',
|
||||
label: translate('Draw a polygon'),
|
||||
},
|
||||
TOGGLE_EDIT: {
|
||||
shortcut: 'Modifier+E',
|
||||
label: translate('Toggle edit mode'),
|
||||
},
|
||||
STOP_EDIT: {
|
||||
shortcut: 'Modifier+E',
|
||||
label: translate('Stop editing'),
|
||||
},
|
||||
SAVE_MAP: {
|
||||
shortcut: 'Modifier+S',
|
||||
label: translate('Save map'),
|
||||
},
|
||||
IMPORT_PANEL: {
|
||||
shortcut: 'Modifier+I',
|
||||
label: translate('Import data'),
|
||||
},
|
||||
SEARCH: {
|
||||
shortcut: 'Modifier+F',
|
||||
label: translate('Search location'),
|
||||
},
|
||||
CANCEL: {
|
||||
shortcut: 'Modifier+Z',
|
||||
label: translate('Cancel edits'),
|
||||
},
|
||||
PREVIEW: {
|
||||
shortcut: 'Modifier+E',
|
||||
label: translate('Back to preview'),
|
||||
},
|
||||
SAVE: {
|
||||
shortcut: 'Modifier+S',
|
||||
label: translate('Save current edits'),
|
||||
},
|
||||
EDIT_FEATURE_LAYER: {
|
||||
shortcut: 'Modifier+⇧+Click',
|
||||
label: translate("Edit feature's layer"),
|
||||
},
|
||||
CONTINUE_LINE: {
|
||||
shortcut: 'Modifier+Click',
|
||||
label: translate('Continue line'),
|
||||
},
|
||||
}
|
||||
|
||||
const ENTRIES = {
|
||||
formatURL: `${translate(
|
||||
'Supported variables that will be dynamically replaced'
|
||||
)}: {bbox}, {lat}, {lng}, {zoom}, {east}, {north}..., {left}, {top}..., locale, lang`,
|
||||
colorValue: translate('Must be a valid CSS value (eg.: DarkBlue or #123456)'),
|
||||
smoothFactor: translate(
|
||||
'How much to simplify the polyline on each zoom level (more = better performance and smoother look, less = more accurate)'
|
||||
),
|
||||
dashArray: translate(
|
||||
'A comma separated list of numbers that defines the stroke dash pattern. Ex.: "5, 10, 15".'
|
||||
),
|
||||
zoomTo: translate('Zoom level for automatic zooms'),
|
||||
labelKey: translate(
|
||||
'The name of the property to use as feature label (eg.: "nom"). You can also use properties inside brackets to use more than one or mix with static content (eg.: "{name} in {place}")'
|
||||
),
|
||||
stroke: translate('Whether to display or not polygons paths.'),
|
||||
fill: translate('Whether to fill polygons with color.'),
|
||||
fillColor: translate('Optional. Same as color if not set.'),
|
||||
shortCredit: translate('Will be displayed in the bottom right corner of the map'),
|
||||
longCredit: translate('Will be visible in the caption of the map'),
|
||||
permanentCredit: translate(
|
||||
'Will be permanently visible in the bottom left corner of the map'
|
||||
),
|
||||
sortKey: translate(
|
||||
'Comma separated list of properties to use for sorting features. To reverse the sort, put a minus sign (-) before. Eg. mykey,-otherkey.'
|
||||
),
|
||||
slugKey: translate('The name of the property to use as feature unique identifier.'),
|
||||
filterKey: translate(
|
||||
'Comma separated list of properties to use when filtering features by text input'
|
||||
),
|
||||
facetKey: translate(
|
||||
'Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.'
|
||||
),
|
||||
interactive: translate(
|
||||
'If false, the polygon or line will act as a part of the underlying map.'
|
||||
),
|
||||
outlink: translate('Define link to open in a new window on polygon click.'),
|
||||
dynamicRemoteData: translate('Fetch data each time map view changes.'),
|
||||
proxyRemoteData: translate(
|
||||
"To use if remote server doesn't allow cross domain (slower)"
|
||||
),
|
||||
browsable: translate(
|
||||
'Set it to false to hide this layer from the slideshow, the data browser, the popup navigation…'
|
||||
),
|
||||
importFormats: `
|
||||
<div>
|
||||
<h3>GeoJSON</h3>
|
||||
<p>${translate('All properties are imported.')}</p>
|
||||
<h3>GPX</h3>
|
||||
<p>${translate('Properties imported:')}name, desc</p>
|
||||
<h3>KML</h3>
|
||||
<p>${translate('Properties imported:')}name, description</p>
|
||||
<h3>CSV</h3>
|
||||
<p>${translate('Comma, tab or semi-colon separated values. SRS WGS84 is implied. Only Point geometries are imported. The import will look at the column headers for any mention of «lat» and «lon» at the begining of the header, case insensitive. All other column are imported as properties.')}</p>
|
||||
<h3>uMap</h3>
|
||||
<p>${translate('Imports all umap data, including layers and settings.')}</p>
|
||||
</div>
|
||||
`,
|
||||
dynamicProperties: `
|
||||
<div>
|
||||
<h3>${translate('Dynamic properties')}</h3>
|
||||
<p>${translate('Use placeholders with feature properties between brackets, eg. {name}, they will be dynamically replaced by the corresponding values.')}</p>
|
||||
</div>
|
||||
`,
|
||||
|
||||
textFormatting: `
|
||||
<div>
|
||||
<h3>${translate('Text formatting')}</h3>
|
||||
<ul>
|
||||
<li>${translate('*single star for italic*')}</li>
|
||||
<li>${translate('**double star for bold**')}</li>
|
||||
<li>${translate('# one hash for main heading')}</li>
|
||||
<li>${translate('## two hashes for second heading')}</li>
|
||||
<li>${translate('### three hashes for third heading')}</li>
|
||||
<li>${translate('Simple link: [[http://example.com]]')}</li>
|
||||
<li>${translate('Link with text: [[http://example.com|text of the link]]')}</li>
|
||||
<li>${translate('Image: {{http://image.url.com}}')}</li>
|
||||
<li>${translate('Image with custom width (in px): {{http://image.url.com|width}}')}</li>
|
||||
<li>${translate('Iframe: {{{http://iframe.url.com}}}')}</li>
|
||||
<li>${translate('Iframe with custom height (in px): {{{http://iframe.url.com|height}}}')}</li>
|
||||
<li>${translate('Iframe with custom height and width (in px): {{{http://iframe.url.com|height*width}}}')}</li>
|
||||
<li>${translate('--- for a horizontal rule')}</li>
|
||||
</ul>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
|
||||
export default class Help {
|
||||
constructor(map) {
|
||||
this.map = map
|
||||
this.isMacOS = /mac/i.test(
|
||||
// eslint-disable-next-line compat/compat -- Fallback available.
|
||||
navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform
|
||||
)
|
||||
}
|
||||
|
||||
displayLabel(action, withKbdTag = true) {
|
||||
let { shortcut, label } = SHORTCUTS[action]
|
||||
const modifier = this.isMacOS ? 'Cmd' : 'Ctrl'
|
||||
shortcut = shortcut.replace('Modifier', modifier)
|
||||
if (withKbdTag) {
|
||||
shortcut = shortcut
|
||||
.split('+')
|
||||
.map((el) => `<kbd>${el}</kbd>`)
|
||||
.join('+')
|
||||
label += ` ${shortcut}`
|
||||
} else {
|
||||
label += ` (${shortcut})`
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
show(entries) {
|
||||
const container = DomUtil.add('div')
|
||||
// Special dynamic case. Do we still think this dialog is usefull ?
|
||||
if (entries == 'edit') {
|
||||
DomUtil.element({
|
||||
tagName: 'div',
|
||||
className: 'umap-help-entry',
|
||||
parent: container,
|
||||
innerHTML: ENTRIES[name],
|
||||
}).appendChild(this._buildEditEntry())
|
||||
} else {
|
||||
for (const name of entries) {
|
||||
DomUtil.element({
|
||||
tagName: 'div',
|
||||
className: 'umap-help-entry',
|
||||
parent: container,
|
||||
innerHTML: ENTRIES[name],
|
||||
})
|
||||
}
|
||||
}
|
||||
this.map.dialog.open({ content: container, className: 'dark' })
|
||||
}
|
||||
|
||||
button(container, entries, classname) {
|
||||
const button = DomUtil.createButton(
|
||||
classname || 'umap-help-button',
|
||||
container,
|
||||
translate('Help')
|
||||
)
|
||||
entries = typeof entries === 'string' ? [entries] : entries
|
||||
DomEvent.on(button, 'click', DomEvent.stop).on(button, 'click', () =>
|
||||
this.show(entries)
|
||||
)
|
||||
return button
|
||||
}
|
||||
|
||||
link(container, entries) {
|
||||
const button = this.button(container, entries, 'umap-help-link')
|
||||
button.textContent = translate('Help')
|
||||
return button
|
||||
}
|
||||
|
||||
_buildEditEntry() {
|
||||
const container = DomUtil.create('div', '')
|
||||
const title = DomUtil.create('h3', '', container)
|
||||
const actionsContainer = DomUtil.create('ul', 'umap-edit-actions', container)
|
||||
const addAction = (action) => {
|
||||
const actionContainer = DomUtil.add('li', '', actionsContainer)
|
||||
DomUtil.add('i', action.options.className, actionContainer),
|
||||
DomUtil.add('span', '', actionContainer, action.options.tooltip)
|
||||
DomEvent.on(actionContainer, 'click', action.addHooks, action)
|
||||
DomEvent.on(actionContainer, 'click', this.map.dialog.close, this.map.dialog)
|
||||
}
|
||||
title.textContent = translate('Where do we go from here?')
|
||||
for (const id in this.map.helpMenuActions) {
|
||||
addAction(this.map.helpMenuActions[id])
|
||||
}
|
||||
return container
|
||||
}
|
||||
}
|
|
@ -272,277 +272,6 @@ U.Keys = {
|
|||
Z: 90,
|
||||
}
|
||||
|
||||
U.Help = L.Class.extend({
|
||||
SHORTCUTS: {
|
||||
DRAW_MARKER: {
|
||||
shortcut: 'Modifier+M',
|
||||
label: L._('Draw a marker'),
|
||||
},
|
||||
DRAW_LINE: {
|
||||
shortcut: 'Modifier+L',
|
||||
label: L._('Draw a polyline'),
|
||||
},
|
||||
DRAW_POLYGON: {
|
||||
shortcut: 'Modifier+P',
|
||||
label: L._('Draw a polygon'),
|
||||
},
|
||||
TOGGLE_EDIT: {
|
||||
shortcut: 'Modifier+E',
|
||||
label: L._('Toggle edit mode'),
|
||||
},
|
||||
STOP_EDIT: {
|
||||
shortcut: 'Modifier+E',
|
||||
label: L._('Stop editing'),
|
||||
},
|
||||
SAVE_MAP: {
|
||||
shortcut: 'Modifier+S',
|
||||
label: L._('Save map'),
|
||||
},
|
||||
IMPORT_PANEL: {
|
||||
shortcut: 'Modifier+I',
|
||||
label: L._('Import data'),
|
||||
},
|
||||
SEARCH: {
|
||||
shortcut: 'Modifier+F',
|
||||
label: L._('Search location'),
|
||||
},
|
||||
CANCEL: {
|
||||
shortcut: 'Modifier+Z',
|
||||
label: L._('Cancel edits'),
|
||||
},
|
||||
PREVIEW: {
|
||||
shortcut: 'Modifier+E',
|
||||
label: L._('Back to preview'),
|
||||
},
|
||||
SAVE: {
|
||||
shortcut: 'Modifier+S',
|
||||
label: L._('Save current edits'),
|
||||
},
|
||||
EDIT_FEATURE_LAYER: {
|
||||
shortcut: 'Modifier+⇧+Click',
|
||||
label: L._("Edit feature's layer"),
|
||||
},
|
||||
CONTINUE_LINE: {
|
||||
shortcut: 'Modifier+Click',
|
||||
label: L._('Continue line'),
|
||||
},
|
||||
},
|
||||
|
||||
displayLabel: function (action, withKbdTag = true) {
|
||||
let { shortcut, label } = this.SHORTCUTS[action]
|
||||
const modifier = this.isMacOS ? 'Cmd' : 'Ctrl'
|
||||
shortcut = shortcut.replace('Modifier', modifier)
|
||||
if (withKbdTag) {
|
||||
shortcut = shortcut
|
||||
.split('+')
|
||||
.map((el) => `<kbd>${el}</kbd>`)
|
||||
.join('+')
|
||||
label += ` ${shortcut}`
|
||||
} else {
|
||||
label += ` (${shortcut})`
|
||||
}
|
||||
return label
|
||||
},
|
||||
|
||||
initialize: function (map) {
|
||||
this.map = map
|
||||
this.isMacOS = /mac/i.test(
|
||||
// eslint-disable-next-line compat/compat -- Fallback available.
|
||||
navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform
|
||||
)
|
||||
},
|
||||
|
||||
onKeyDown: function (e) {
|
||||
const key = e.keyCode,
|
||||
ESC = 27
|
||||
if (key === ESC) {
|
||||
this.hide()
|
||||
}
|
||||
},
|
||||
|
||||
show: function () {
|
||||
const container = L.DomUtil.add('div')
|
||||
for (let i = 0, name; i < arguments.length; i++) {
|
||||
name = arguments[i]
|
||||
L.DomUtil.add('div', 'umap-help-entry', container, this.resolve(name))
|
||||
}
|
||||
this.map.dialog.open({ content: container, className: 'dark' })
|
||||
},
|
||||
|
||||
resolve: function (name) {
|
||||
return typeof this[name] === 'function' ? this[name]() : this[name]
|
||||
},
|
||||
|
||||
button: function (container, entries, classname) {
|
||||
const helpButton = L.DomUtil.createButton(
|
||||
classname || 'umap-help-button',
|
||||
container,
|
||||
L._('Help')
|
||||
)
|
||||
if (entries) {
|
||||
L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on(
|
||||
helpButton,
|
||||
'click',
|
||||
function (e) {
|
||||
const args = typeof entries === 'string' ? [entries] : entries
|
||||
this.show.apply(this, args)
|
||||
},
|
||||
this
|
||||
)
|
||||
}
|
||||
return helpButton
|
||||
},
|
||||
|
||||
link: function (container, entries) {
|
||||
const helpButton = this.button(container, entries, 'umap-help-link')
|
||||
helpButton.textContent = L._('Help')
|
||||
return helpButton
|
||||
},
|
||||
|
||||
edit: function () {
|
||||
const container = L.DomUtil.create('div', '')
|
||||
const title = L.DomUtil.create('h3', '', container)
|
||||
const actionsContainer = L.DomUtil.create('ul', 'umap-edit-actions', container)
|
||||
const addAction = (action) => {
|
||||
const actionContainer = L.DomUtil.add('li', '', actionsContainer)
|
||||
L.DomUtil.add('i', action.options.className, actionContainer),
|
||||
L.DomUtil.add('span', '', actionContainer, action.options.tooltip)
|
||||
L.DomEvent.on(actionContainer, 'click', action.addHooks, action)
|
||||
L.DomEvent.on(actionContainer, 'click', this.map.dialog.close, this.map.dialog)
|
||||
}
|
||||
title.textContent = L._('Where do we go from here?')
|
||||
for (const id in this.map.helpMenuActions) {
|
||||
addAction(this.map.helpMenuActions[id])
|
||||
}
|
||||
return container
|
||||
},
|
||||
|
||||
importFormats: function () {
|
||||
const container = L.DomUtil.create('div')
|
||||
L.DomUtil.add('h3', '', container, 'GeojSON')
|
||||
L.DomUtil.add('p', '', container, L._('All properties are imported.'))
|
||||
L.DomUtil.add('h3', '', container, 'GPX')
|
||||
L.DomUtil.add('p', '', container, `${L._('Properties imported:')}name, desc`)
|
||||
L.DomUtil.add('h3', '', container, 'KML')
|
||||
L.DomUtil.add('p', '', container, `${L._('Properties imported:')}name, description`)
|
||||
L.DomUtil.add('h3', '', container, 'CSV')
|
||||
L.DomUtil.add(
|
||||
'p',
|
||||
'',
|
||||
container,
|
||||
L._(
|
||||
'Comma, tab or semi-colon separated values. SRS WGS84 is implied. Only Point geometries are imported. The import will look at the column headers for any mention of «lat» and «lon» at the begining of the header, case insensitive. All other column are imported as properties.'
|
||||
)
|
||||
)
|
||||
L.DomUtil.add('h3', '', container, 'uMap')
|
||||
L.DomUtil.add(
|
||||
'p',
|
||||
'',
|
||||
container,
|
||||
L._('Imports all umap data, including layers and settings.')
|
||||
)
|
||||
return container
|
||||
},
|
||||
|
||||
textFormatting: function () {
|
||||
const container = L.DomUtil.create('div'),
|
||||
title = L.DomUtil.add('h3', '', container, L._('Text formatting')),
|
||||
elements = L.DomUtil.create('ul', '', container)
|
||||
L.DomUtil.add('li', '', elements, L._('*single star for italic*'))
|
||||
L.DomUtil.add('li', '', elements, L._('**double star for bold**'))
|
||||
L.DomUtil.add('li', '', elements, L._('# one hash for main heading'))
|
||||
L.DomUtil.add('li', '', elements, L._('## two hashes for second heading'))
|
||||
L.DomUtil.add('li', '', elements, L._('### three hashes for third heading'))
|
||||
L.DomUtil.add('li', '', elements, L._('Simple link: [[http://example.com]]'))
|
||||
L.DomUtil.add(
|
||||
'li',
|
||||
'',
|
||||
elements,
|
||||
L._('Link with text: [[http://example.com|text of the link]]')
|
||||
)
|
||||
L.DomUtil.add('li', '', elements, L._('Image: {{http://image.url.com}}'))
|
||||
L.DomUtil.add(
|
||||
'li',
|
||||
'',
|
||||
elements,
|
||||
L._('Image with custom width (in px): {{http://image.url.com|width}}')
|
||||
)
|
||||
L.DomUtil.add('li', '', elements, L._('Iframe: {{{http://iframe.url.com}}}'))
|
||||
L.DomUtil.add(
|
||||
'li',
|
||||
'',
|
||||
elements,
|
||||
L._('Iframe with custom height (in px): {{{http://iframe.url.com|height}}}')
|
||||
)
|
||||
L.DomUtil.add(
|
||||
'li',
|
||||
'',
|
||||
elements,
|
||||
L._(
|
||||
'Iframe with custom height and width (in px): {{{http://iframe.url.com|height*width}}}'
|
||||
)
|
||||
)
|
||||
L.DomUtil.add('li', '', elements, L._('--- for a horizontal rule'))
|
||||
return container
|
||||
},
|
||||
|
||||
dynamicProperties: function () {
|
||||
const container = L.DomUtil.create('div')
|
||||
L.DomUtil.add('h3', '', container, L._('Dynamic properties'))
|
||||
L.DomUtil.add(
|
||||
'p',
|
||||
'',
|
||||
container,
|
||||
L._(
|
||||
'Use placeholders with feature properties between brackets, eg. {name}, they will be dynamically replaced by the corresponding values.'
|
||||
)
|
||||
)
|
||||
return container
|
||||
},
|
||||
|
||||
formatURL: `${L._(
|
||||
'Supported variables that will be dynamically replaced'
|
||||
)}: {bbox}, {lat}, {lng}, {zoom}, {east}, {north}..., {left}, {top}..., locale, lang`,
|
||||
colorValue: L._('Must be a valid CSS value (eg.: DarkBlue or #123456)'),
|
||||
smoothFactor: L._(
|
||||
'How much to simplify the polyline on each zoom level (more = better performance and smoother look, less = more accurate)'
|
||||
),
|
||||
dashArray: L._(
|
||||
'A comma separated list of numbers that defines the stroke dash pattern. Ex.: "5, 10, 15".'
|
||||
),
|
||||
zoomTo: L._('Zoom level for automatic zooms'),
|
||||
labelKey: L._(
|
||||
'The name of the property to use as feature label (eg.: "nom"). You can also use properties inside brackets to use more than one or mix with static content (eg.: "{name} in {place}")'
|
||||
),
|
||||
stroke: L._('Whether to display or not polygons paths.'),
|
||||
fill: L._('Whether to fill polygons with color.'),
|
||||
fillColor: L._('Optional. Same as color if not set.'),
|
||||
shortCredit: L._('Will be displayed in the bottom right corner of the map'),
|
||||
longCredit: L._('Will be visible in the caption of the map'),
|
||||
permanentCredit: L._(
|
||||
'Will be permanently visible in the bottom left corner of the map'
|
||||
),
|
||||
sortKey: L._(
|
||||
'Comma separated list of properties to use for sorting features. To reverse the sort, put a minus sign (-) before. Eg. mykey,-otherkey.'
|
||||
),
|
||||
slugKey: L._('The name of the property to use as feature unique identifier.'),
|
||||
filterKey: L._(
|
||||
'Comma separated list of properties to use when filtering features by text input'
|
||||
),
|
||||
facetKey: L._(
|
||||
'Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.'
|
||||
),
|
||||
interactive: L._(
|
||||
'If false, the polygon or line will act as a part of the underlying map.'
|
||||
),
|
||||
outlink: L._('Define link to open in a new window on polygon click.'),
|
||||
dynamicRemoteData: L._('Fetch data each time map view changes.'),
|
||||
proxyRemoteData: L._("To use if remote server doesn't allow cross domain (slower)"),
|
||||
browsable: L._(
|
||||
'Set it to false to hide this layer from the slideshow, the data browser, the popup navigation…'
|
||||
),
|
||||
})
|
||||
|
||||
L.LatLng.prototype.isValid = function () {
|
||||
return (
|
||||
isFinite(this.lat) &&
|
||||
|
|
Loading…
Reference in a new issue