Merge pull request #1290 from umap-project/a11y-from-links-to-buttons

A11Y: switch from links to buttons when pertinent
This commit is contained in:
David Larlet 2023-10-27 11:53:23 -04:00 committed by GitHub
commit 67d89874e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 661 additions and 457 deletions

View file

@ -163,7 +163,9 @@ select {
select[multiple="multiple"] { select[multiple="multiple"] {
height: auto; height: auto;
} }
.button, input[type="submit"] { .button,
[type="button"],
input[type="submit"] {
display: block; display: block;
margin-bottom: 14px; margin-bottom: 14px;
text-align: center; text-align: center;
@ -176,18 +178,31 @@ select[multiple="multiple"] {
line-height: 32px; line-height: 32px;
border: none; border: none;
text-decoration: none; text-decoration: none;
background-color: white;
} }
.dark .button { .dark .button,
.dark [type="button"] {
background-color: #2a2e30; background-color: #2a2e30;
color: #eeeeec; color: #eeeeec;
border: 1px solid #1b1f20; border: 1px solid #1b1f20;
} }
.dark .button:hover, .dark input[type="submit"]:hover { .dark .button:hover,
.dark [type="button"]:hover,
.dark input[type="submit"]:hover {
background-color: #2e3436; background-color: #2e3436;
} }
.dark a { .dark a {
color: #eeeeec; color: #eeeeec;
} }
[type="button"].flat,
.dark [type="button"].flat {
border: none;
background-color: inherit;
padding: 0;
text-align: left;
min-height: inherit;
text-decoration: underline;
}
.help-text, .helptext { .help-text, .helptext {
display: block; display: block;
padding: 7px 7px; padding: 7px 7px;
@ -361,7 +376,8 @@ input.switch:checked ~ label:after {
.umap-multiplechoice.by4 { .umap-multiplechoice.by4 {
grid-template-columns: 1fr 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr 1fr;
} }
.button-bar .button { .button-bar .button,
.button-bar [type="button"] {
display: inline-block; display: inline-block;
} }
.umap-multiplechoice input[type='radio'] { .umap-multiplechoice input[type='radio'] {
@ -558,10 +574,12 @@ input.blur {
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
} }
.blur + .button:before { .blur + .button:before,
.blur + [type="button"]:before {
content: '✔'; content: '✔';
} }
.blur + .button { .blur + .button,
.blur + [type="button"] {
width: 40px; width: 40px;
height: 18px; height: 18px;
display: inline-block; display: inline-block;
@ -571,7 +589,8 @@ input.blur {
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
box-sizing: border-box; box-sizing: border-box;
} }
input[type=hidden].blur + .button { input[type=hidden].blur + .button,
input[type=hidden].blur + [type="button"] {
display: none; display: none;
} }
@ -726,6 +745,7 @@ input:invalid {
.umap-alert input { .umap-alert input {
padding: 5px; padding: 5px;
border-radius: 4px; border-radius: 4px;
width: 100%;
} }
/* *********** */ /* *********** */
@ -762,6 +782,19 @@ input:invalid {
border-width: 11px; border-width: 11px;
margin-left: calc(-50% + 21px); margin-left: calc(-50% + 21px);
} }
#umap-tooltip-container.tooltip-bottom:before {
top: -22px;
left: calc(50% - 11px);
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top-color: rgba(30, 30, 30, 0.7);
border-width: 11px;
transform: rotate(180deg);
}
#umap-tooltip-container.tooltip.tooltip-left:after { #umap-tooltip-container.tooltip.tooltip-left:after {
left: 100%; left: 100%;
top: 50%; top: 50%;
@ -807,10 +840,22 @@ input:invalid {
color: #fff; color: #fff;
float: right; float: right;
padding-right: 10px; padding-right: 10px;
width: 100px;
line-height: 1;
margin: .5rem;
background-color: #666;
font-size: .7rem;
} }
#umap-alert-container .umap-close-icon { #umap-alert-container .umap-close-icon {
background-position: -74px -55px; background-position: -74px -55px;
} }
#umap-alert-container .umap-alert-actions {
display: flex;
margin: 1rem;
}
#umap-alert-container .umap-alert-actions .umap-action {
margin-bottom: 0;
}
/* *********** */ /* *********** */

View file

@ -367,18 +367,29 @@ L.U.EditControl = L.Control.extend({
}, },
onAdd: function (map) { onAdd: function (map) {
const container = L.DomUtil.create('div', 'leaflet-control-edit-enable'), const container = L.DomUtil.create('div', 'leaflet-control-edit-enable')
edit = L.DomUtil.create('a', '', container) const enableEditing = L.DomUtil.createButton(
edit.href = '#' '',
edit.title = `${L._('Enable editing')} (Ctrl+E)` container,
edit.textContent = L._('Edit') L._('Edit'),
L.DomEvent.addListener(edit, 'click', L.DomEvent.stop).addListener(
edit,
'click',
map.enableEdit, map.enableEdit,
map map
) )
L.DomEvent.on(
enableEditing,
'mouseover',
function () {
map.ui.tooltip({
content: `${L._('Switch to edit mode')} (<kbd>Ctrl+E</kbd>)`,
anchor: enableEditing,
position: 'bottom',
delay: 750,
duration: 5000,
})
},
this
)
return container return container
}, },
}) })
@ -391,15 +402,14 @@ L.Control.Embed = L.Control.extend({
onAdd: function (map) { onAdd: function (map) {
const container = L.DomUtil.create('div', 'leaflet-control-embed umap-control') const container = L.DomUtil.create('div', 'leaflet-control-embed umap-control')
const shareButton = L.DomUtil.createButton(
const link = L.DomUtil.create('a', '', container) '',
link.href = '#' container,
link.title = L._('Embed and share this map') L._('Embed and share this map'),
map.renderShareBox,
L.DomEvent.on(link, 'click', L.DomEvent.stop) map
.on(link, 'click', map.renderShareBox, map) )
.on(link, 'dblclick', L.DomEvent.stopPropagation) L.DomEvent.on(shareButton, 'dblclick', L.DomEvent.stopPropagation)
return container return container
}, },
}) })
@ -410,19 +420,21 @@ L.U.MoreControls = L.Control.extend({
}, },
onAdd: function () { onAdd: function () {
const container = L.DomUtil.create('div', 'umap-control-text'), const container = L.DomUtil.create('div', 'umap-control-text')
more = L.DomUtil.create('a', 'umap-control-more', container), const moreButton = L.DomUtil.createButton(
less = L.DomUtil.create('a', 'umap-control-less', container) 'umap-control-more',
more.href = '#' container,
more.title = L._('More controls') L._('More controls'),
this.toggle,
L.DomEvent.on(more, 'click', L.DomEvent.stop).on(more, 'click', this.toggle, this) this
)
less.href = '#' const lessButton = L.DomUtil.createButton(
less.title = L._('Hide controls') 'umap-control-less',
container,
L.DomEvent.on(less, 'click', L.DomEvent.stop).on(less, 'click', this.toggle, this) L._('Hide controls'),
this.toggle,
this
)
return container return container
}, },
@ -500,23 +512,21 @@ L.U.DataLayersControl = L.Control.extend({
actions actions
) )
const link = L.DomUtil.create('a', 'umap-browse-link', actions) L.DomUtil.createButton(
link.href = '#' 'umap-browse-link',
link.title = link.textContent = L._('Browse data') actions,
L._('Browse data'),
const toggle = L.DomUtil.create('a', 'umap-browse-toggle', container)
toggle.href = '#'
toggle.title = L._('See data layers')
L.DomEvent.on(toggle, 'click', L.DomEvent.stop)
L.DomEvent.on(link, 'click', L.DomEvent.stop).on(
link,
'click',
map.openBrowser, map.openBrowser,
map map
) )
const toggleButton = L.DomUtil.createButton(
'umap-browse-toggle',
container,
L._('See data layers')
)
L.DomEvent.on(toggleButton, 'click', L.DomEvent.stop)
map.whenReady(function () { map.whenReady(function () {
this.update() this.update()
}, this) }, this)
@ -537,8 +547,8 @@ L.U.DataLayersControl = L.Control.extend({
) )
} else { } else {
L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation) L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation)
L.DomEvent.on(toggle, 'click', L.DomEvent.stop).on( L.DomEvent.on(toggleButton, 'click', L.DomEvent.stop).on(
toggle, toggleButton,
'click', 'click',
this.expand, this.expand,
this this
@ -628,14 +638,11 @@ L.U.DataLayersControl = L.Control.extend({
this this
) )
const bar = L.DomUtil.create('div', 'button-bar', container), const bar = L.DomUtil.create('div', 'button-bar', container)
add = L.DomUtil.create('a', 'show-on-edit block add-datalayer button', bar) L.DomUtil.createButton(
add.href = '#' 'show-on-edit block add-datalayer button',
add.textContent = add.title = L._('Add a layer') bar,
L._('Add a layer'),
L.DomEvent.on(add, 'click', L.DomEvent.stop).on(
add,
'click',
this.newDataLayer, this.newDataLayer,
this this
) )
@ -725,7 +732,6 @@ L.U.DataLayer.addInitHook(function () {
}) })
L.U.Map.include({ L.U.Map.include({
_openFacet: function () { _openFacet: function () {
const container = L.DomUtil.create('div', 'umap-facet-search'), const container = L.DomUtil.create('div', 'umap-facet-search'),
title = L.DomUtil.add('h3', 'umap-filter-title', container, L._('Facet search')), title = L.DomUtil.add('h3', 'umap-filter-title', container, L._('Facet search')),
@ -825,13 +831,17 @@ L.U.Map.include({
} }
if (this.options.licence) { if (this.options.licence) {
const licence = L.DomUtil.add( const licence = L.DomUtil.add(
'p', 'p',
'', '',
credits, credits,
`${L._('Map user content has been published under licence')} ` `${L._('Map user content has been published under licence')} `
), )
link = L.DomUtil.add('a', '', licence, this.options.licence.name) L.DomUtil.createLink(
link.href = this.options.licence.url '',
licence,
this.options.licence.name,
this.options.licence.url
)
} else { } else {
L.DomUtil.add('p', '', credits, L._('No licence has been set')) L.DomUtil.add('p', '', credits, L._('No licence has been set'))
} }
@ -929,76 +939,148 @@ L.U.Map.include({
renderEditToolbar: function () { renderEditToolbar: function () {
const container = L.DomUtil.create( const container = L.DomUtil.create(
'div', 'div',
'umap-main-edit-toolbox with-transition dark', 'umap-main-edit-toolbox with-transition dark',
this._controlContainer this._controlContainer
), )
logo = L.DomUtil.add('a', 'logo', container), const leftContainer = L.DomUtil.create('div', 'umap-left-edit-toolbox', container)
name = L.DomUtil.create('a', 'map-name', container), const rightContainer = L.DomUtil.create('div', 'umap-right-edit-toolbox', container)
share_status = L.DomUtil.create('a', 'share-status', container), const logo = L.DomUtil.create('div', 'logo', leftContainer)
update = () => { L.DomUtil.createLink('', logo, 'uMap', '/', null, L._('Go to the homepage'))
const status = this.permissions.getShareStatusDisplay() const nameButton = L.DomUtil.createButton(
name.textContent = this.getDisplayName() 'map-name',
// status is not set until map is saved once leftContainer,
if (status) '',
share_status.textContent = L._('Visibility: {status}', { this.edit,
status: status, this
}) )
L.DomEvent.on(
nameButton,
'mouseover',
function () {
this.ui.tooltip({
content: L._('Edit the title of the map'),
anchor: nameButton,
position: 'bottom',
delay: 500,
duration: 5000,
})
},
this
)
const shareStatusButton = L.DomUtil.createButton(
'share-status',
leftContainer,
'',
this.permissions.edit,
this.permissions
)
L.DomEvent.on(
shareStatusButton,
'mouseover',
function () {
this.ui.tooltip({
content: L._('Update who can see and edit the map'),
anchor: shareStatusButton,
position: 'bottom',
delay: 500,
duration: 5000,
})
},
this
)
const update = () => {
const status = this.permissions.getShareStatusDisplay()
nameButton.textContent = this.getDisplayName()
// status is not set until map is saved once
if (status) {
shareStatusButton.textContent = L._('Visibility: {status}', {
status: status,
})
} }
}
update() update()
this.once('saved', L.bind(update, this)) this.once('saved', L.bind(update, this))
logo.href = '/'
if (this.options.editMode === 'advanced') { if (this.options.editMode === 'advanced') {
name.href = '#' L.DomEvent.on(nameButton, 'click', this.edit, this)
share_status.href = '#' L.DomEvent.on(shareStatusButton, 'click', this.permissions.edit, this.permissions)
L.DomEvent.on(name, 'click', this.edit, this)
L.DomEvent.on(share_status, 'click', this.permissions.edit, this.permissions)
} }
this.on('postsync', L.bind(update, this)) this.on('postsync', L.bind(update, this))
const save = L.DomUtil.create('a', 'leaflet-control-edit-save button', container)
save.href = '#'
save.title = `${L._('Save current edits')} (Ctrl+S)`
save.textContent = L._('Save')
const cancel = L.DomUtil.create('a', 'leaflet-control-edit-cancel', container)
cancel.href = '#'
cancel.title = `${L._('Cancel edits')} (Ctrl+Z)`
cancel.textContent = L._('Cancel all')
const disable = L.DomUtil.create('a', 'leaflet-control-edit-disable', container)
disable.href = '#'
disable.textContent = L._('Disable editing')
disable.title = `${disable.textContent} (Ctrl+E)`
this.help.link(container, 'edit')
if (this.options.user) { if (this.options.user) {
const userLabel = L.DomUtil.add( L.DomUtil.createLink(
'a',
'umap-user', 'umap-user',
container, rightContainer,
L._(`My Dashboard ({username})`, { username: this.options.user.name }) L._(`My Dashboard <span>({username})</span>`, {
username: this.options.user.name,
}),
this.options.user.url
) )
userLabel.href = this.options.user.url
} }
this.help.link(rightContainer, 'edit')
L.DomEvent.addListener(disable, 'click', L.DomEvent.stop).addListener( const controlEditCancel = L.DomUtil.createButton(
disable, 'leaflet-control-edit-cancel',
'click', rightContainer,
L.DomUtil.add('span', '', null, L._('Cancel edits')),
this.askForReset,
this
)
L.DomEvent.on(
controlEditCancel,
'mouseover',
function () {
this.ui.tooltip({
content: `${L._('Cancel')} (<kbd>Ctrl+Z</kbd>)`,
anchor: controlEditCancel,
position: 'bottom',
delay: 500,
duration: 5000,
})
},
this
)
const controlEditDisable = L.DomUtil.createButton(
'leaflet-control-edit-disable',
rightContainer,
L.DomUtil.add('span', '', null, L._('View')),
function (e) { function (e) {
this.disableEdit(e) this.disableEdit(e)
this.ui.closePanel() this.ui.closePanel()
}, },
this this
) )
L.DomEvent.on(
L.DomEvent.addListener(save, 'click', L.DomEvent.stop).addListener( controlEditDisable,
save, 'mouseover',
'click', function () {
this.ui.tooltip({
content: `${L._('Back to preview')} (<kbd>Ctrl+E</kbd>)`,
anchor: controlEditDisable,
position: 'bottom',
delay: 500,
duration: 5000,
})
},
this
)
const controlEditSave = L.DomUtil.createButton(
'leaflet-control-edit-save button',
rightContainer,
L.DomUtil.add('span', '', null, L._('Save')),
this.save, this.save,
this this
) )
L.DomEvent.on(
L.DomEvent.addListener(cancel, 'click', L.DomEvent.stop).addListener( controlEditSave,
cancel, 'mouseover',
'click', function () {
this.askForReset, this.ui.tooltip({
content: `${L._('Save current edits')} (<kbd>Ctrl+S</kbd>)`,
anchor: controlEditSave,
position: 'bottom',
delay: 500,
duration: 5000,
})
},
this this
) )
}, },
@ -1084,12 +1166,19 @@ L.U.Map.include({
} }
} }
toggleCaveat() toggleCaveat()
const download = L.DomUtil.create('a', 'button', container) L.DomUtil.createButton(
download.textContent = L._('Download data') 'button',
L.DomEvent.on(download, 'click', () => { container,
if (typeInput.value === 'umap') this.fullDownload() L._('Download data'),
else this.download(typeInput.value) () => {
}) if (typeInput.value === 'umap') {
this.fullDownload()
} else {
this.download(typeInput.value)
}
},
this
)
this.ui.openPanel({ data: { html: container } }) this.ui.openPanel({ data: { html: container } })
}, },
@ -1235,15 +1324,14 @@ L.U.TileLayerControl = L.Control.extend({
onAdd: function () { onAdd: function () {
const container = L.DomUtil.create('div', 'leaflet-control-tilelayers umap-control') const container = L.DomUtil.create('div', 'leaflet-control-tilelayers umap-control')
const changeMapBackgroundButton = L.DomUtil.createButton(
const link = L.DomUtil.create('a', '', container) '',
link.href = '#' container,
link.title = L._('Change map background') L._('Change map background'),
this.openSwitcher,
L.DomEvent.on(link, 'click', L.DomEvent.stop) this
.on(link, 'click', this.openSwitcher, this) )
.on(link, 'dblclick', L.DomEvent.stopPropagation) L.DomEvent.on(changeMapBackgroundButton, 'dblclick', L.DomEvent.stopPropagation)
return container return container
}, },
@ -1300,7 +1388,12 @@ L.U.AttributionControl = L.Control.Attribution.extend({
// Use our how container, so we can hide/show on small screens // Use our how container, so we can hide/show on small screens
const credits = this._container.innerHTML const credits = this._container.innerHTML
this._container.innerHTML = '' this._container.innerHTML = ''
const container = L.DomUtil.add('div', 'attribution-container', this._container, credits) const container = L.DomUtil.add(
'div',
'attribution-container',
this._container,
credits
)
if (this._map.options.shortCredit) { if (this._map.options.shortCredit) {
L.DomUtil.add( L.DomUtil.add(
'span', 'span',
@ -1317,19 +1410,17 @@ L.U.AttributionControl = L.Control.Attribution.extend({
} }
if (window.top === window.self && this._map.options.captionMenus) { if (window.top === window.self && this._map.options.captionMenus) {
// We are not in iframe mode // We are not in iframe mode
const home = L.DomUtil.add('a', '', container, `${L._('Home')}`) L.DomUtil.createLink('', container, `${L._('Home')}`, '/')
home.href = '/'
} }
if (this._map.options.captionMenus) { if (this._map.options.captionMenus) {
const poweredBy = L.DomUtil.add( L.DomUtil.createLink(
'a',
'', '',
container, container,
`${L._('Powered by uMap')}` `${L._('Powered by uMap')}`,
'https://github.com/umap-project/umap/'
) )
poweredBy.href = 'https://github.com/umap-project/umap/'
} }
L.DomUtil.create('a', 'attribution-toggle', this._container) L.DomUtil.createLink('attribution-toggle', this._container, '')
}, },
}) })
@ -1341,16 +1432,17 @@ L.U.StarControl = L.Control.extend({
onAdd: function (map) { onAdd: function (map) {
const status = map.options.starred ? ' starred' : '' const status = map.options.starred ? ' starred' : ''
const container = L.DomUtil.create( const container = L.DomUtil.create(
'div', 'div',
`leaflet-control-star umap-control${status}` `leaflet-control-star umap-control${status}`
), )
link = L.DomUtil.create('a', '', container) const starMapButton = L.DomUtil.createButton(
link.href = '#' '',
link.title = L._('Star this map') container,
L.DomEvent.on(link, 'click', L.DomEvent.stop) L._('Star this map'),
.on(link, 'click', map.star, map) map.star,
.on(link, 'dblclick', L.DomEvent.stopPropagation) map
)
L.DomEvent.on(starMapButton, 'dblclick', L.DomEvent.stopPropagation)
return container return container
}, },
}) })
@ -1410,17 +1502,18 @@ L.U.SearchControl = L.Control.extend({
}, },
onAdd: function (map) { onAdd: function (map) {
const container = L.DomUtil.create('div', 'leaflet-control-search umap-control'), const container = L.DomUtil.create('div', 'leaflet-control-search umap-control')
self = this
L.DomEvent.disableClickPropagation(container) L.DomEvent.disableClickPropagation(container)
const link = L.DomUtil.create('a', '', container) L.DomUtil.createButton(
link.href = '#' '',
link.title = L._('Search a place name') container,
L.DomEvent.on(link, 'click', (e) => { L._('Search a place name'),
L.DomEvent.stop(e) (e) => {
self.openPanel(map) L.DomEvent.stop(e)
}) this.openPanel(map)
},
this
)
return container return container
}, },
@ -1626,7 +1719,7 @@ L.U.Editable = L.Editable.extend({
return new L.U.Marker(this.map, latlng, this._getDefaultProperties()) return new L.U.Marker(this.map, latlng, this._getDefaultProperties())
}, },
_getDefaultProperties: function() { _getDefaultProperties: function () {
const result = {} const result = {}
if (this.map.options.featuresHaveOwner && this.map.options.hasOwnProperty('user')) { if (this.map.options.featuresHaveOwner && this.map.options.hasOwnProperty('user')) {
result.geojson = { properties: { owner: this.map.options.user.id } } result.geojson = { properties: { owner: this.map.options.user.id } }

View file

@ -129,7 +129,10 @@ L.Util.toHTML = (r, options) => {
// images // images
r = r.replace(/{{([^\]|]*?)}}/g, '<img src="$1">') r = r.replace(/{{([^\]|]*?)}}/g, '<img src="$1">')
r = r.replace(/{{([^|]*?)\|(\d*?)(px)?}}/g, '<img src="$1" style="width:$2px;min-width:$2px;">') r = r.replace(
/{{([^|]*?)\|(\d*?)(px)?}}/g,
'<img src="$1" style="width:$2px;min-width:$2px;">'
)
//Unescape http //Unescape http
r = r.replace(/(h_t_t_p)/g, 'http') r = r.replace(/(h_t_t_p)/g, 'http')
@ -258,32 +261,31 @@ L.Util.hasVar = (value) => {
} }
L.Util.copyToClipboard = function (textToCopy) { L.Util.copyToClipboard = function (textToCopy) {
// https://stackoverflow.com/a/65996386 // https://stackoverflow.com/a/65996386
// Navigator clipboard api needs a secure context (https) // Navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) { if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(textToCopy) navigator.clipboard.writeText(textToCopy)
} else { } else {
// Use the 'out of viewport hidden text area' trick // Use the 'out of viewport hidden text area' trick
const textArea = document.createElement('textarea') const textArea = document.createElement('textarea')
textArea.value = textToCopy textArea.value = textToCopy
// Move textarea out of the viewport so it's not visible // Move textarea out of the viewport so it's not visible
textArea.style.position = 'absolute' textArea.style.position = 'absolute'
textArea.style.left = '-999999px' textArea.style.left = '-999999px'
document.body.prepend(textArea) document.body.prepend(textArea)
textArea.select() textArea.select()
try { try {
document.execCommand('copy') document.execCommand('copy')
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} finally { } finally {
textArea.remove() textArea.remove()
}
}
} }
}
}
L.DomUtil.add = (tagName, className, container, content) => { L.DomUtil.add = (tagName, className, container, content) => {
const el = L.DomUtil.create(tagName, className, container) const el = L.DomUtil.create(tagName, className, container)
@ -314,14 +316,26 @@ L.DomUtil.createFieldset = (container, legend, options) => {
} }
L.DomUtil.createButton = (className, container, content, callback, context) => { L.DomUtil.createButton = (className, container, content, callback, context) => {
const el = L.DomUtil.add('a', className, container, content) const el = L.DomUtil.add('button', className, container, content)
el.href = '#' el.type = 'button'
if (callback) { if (callback) {
L.DomEvent.on(el, 'click', L.DomEvent.stop).on(el, 'click', callback, context) L.DomEvent.on(el, 'click', L.DomEvent.stop).on(el, 'click', callback, context)
} }
return el return el
} }
L.DomUtil.createLink = (className, container, content, url, target, title) => {
const el = L.DomUtil.add('a', className, container, content)
el.href = url
if (target) {
el.target = target
}
if (title) {
el.title = title
}
return el
}
L.DomUtil.classIf = (el, className, bool) => { L.DomUtil.classIf = (el, className, bool) => {
if (bool) L.DomUtil.addClass(el, className) if (bool) L.DomUtil.addClass(el, className)
else L.DomUtil.removeClass(el, className) else L.DomUtil.removeClass(el, className)
@ -418,13 +432,17 @@ L.U.Help = L.Class.extend({
'umap-help-box with-transition dark', 'umap-help-box with-transition dark',
document.body document.body
) )
const closeLink = L.DomUtil.create('a', 'umap-close-link', this.box) const closeButton = L.DomUtil.createButton(
closeLink.href = '#' 'umap-close-link',
L.DomUtil.add('i', 'umap-close-icon', closeLink) this.box,
const label = L.DomUtil.create('span', '', closeLink) '',
this.hide,
this
)
L.DomUtil.add('i', 'umap-close-icon', closeButton)
const label = L.DomUtil.create('span', '', closeButton)
label.title = label.textContent = L._('Close') label.title = label.textContent = L._('Close')
this.content = L.DomUtil.create('div', 'umap-help-content', this.box) this.content = L.DomUtil.create('div', 'umap-help-content', this.box)
L.DomEvent.on(closeLink, 'click', this.hide, this)
}, },
onKeyDown: function (e) { onKeyDown: function (e) {
@ -457,8 +475,11 @@ L.U.Help = L.Class.extend({
}, },
button: function (container, entries, classname) { button: function (container, entries, classname) {
const helpButton = L.DomUtil.create('a', classname || 'umap-help-button', container) const helpButton = L.DomUtil.createButton(
helpButton.href = '#' classname || 'umap-help-button',
container,
L._('Help')
)
if (entries) { if (entries) {
L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on( L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on(
helpButton, helpButton,
@ -475,7 +496,7 @@ L.U.Help = L.Class.extend({
link: function (container, entries) { link: function (container, entries) {
const helpButton = this.button(container, entries, 'umap-help-link') const helpButton = this.button(container, entries, 'umap-help-link')
helpButton.textContent = L._("Help") helpButton.textContent = L._('Help')
return helpButton return helpButton
}, },

View file

@ -130,12 +130,10 @@ L.U.FeatureMixin = {
}, },
getAdvancedEditActions: function (container) { getAdvancedEditActions: function (container) {
const deleteLink = L.DomUtil.create('a', 'button umap-delete', container) const deleteButton = L.DomUtil.createButton(
deleteLink.href = '#' 'button umap-delete',
deleteLink.textContent = L._('Delete') container,
L.DomEvent.on( L._('Delete'),
deleteLink,
'click',
function (e) { function (e) {
L.DomEvent.stop(e) L.DomEvent.stop(e)
if (this.confirmDelete()) this.map.ui.closePanel() if (this.confirmDelete()) this.map.ui.closePanel()
@ -1018,10 +1016,13 @@ L.U.Polyline = L.Polyline.extend({
getAdvancedEditActions: function (container) { getAdvancedEditActions: function (container) {
L.U.FeatureMixin.getAdvancedEditActions.call(this, container) L.U.FeatureMixin.getAdvancedEditActions.call(this, container)
const toPolygon = L.DomUtil.create('a', 'button umap-to-polygon', container) const toPolygon = L.DomUtil.createButton(
toPolygon.href = '#' 'button umap-to-polygon',
toPolygon.textContent = L._('Transform to polygon') container,
L.DomEvent.on(toPolygon, 'click', this.toPolygon, this) L._('Transform to polygon'),
this.toPolygon,
this
)
}, },
_mergeShapes: function (from, to) { _mergeShapes: function (from, to) {
@ -1165,10 +1166,13 @@ L.U.Polygon = L.Polygon.extend({
getAdvancedEditActions: function (container) { getAdvancedEditActions: function (container) {
L.U.FeatureMixin.getAdvancedEditActions.call(this, container) L.U.FeatureMixin.getAdvancedEditActions.call(this, container)
const toPolyline = L.DomUtil.create('a', 'button umap-to-polyline', container) const toPolyline = L.DomUtil.createButton(
toPolyline.href = '#' 'button umap-to-polyline',
toPolyline.textContent = L._('Transform to lines') container,
L.DomEvent.on(toPolyline, 'click', this.toPolyline, this) L._('Transform to lines'),
this.toPolyline,
this
)
}, },
isMulti: function () { isMulti: function () {

View file

@ -397,7 +397,11 @@ L.FormBuilder.DataLayerSwitcher = L.FormBuilder.Select.extend({
getOptions: function () { getOptions: function () {
const options = [] const options = []
this.builder.map.eachDataLayerReverse((datalayer) => { this.builder.map.eachDataLayerReverse((datalayer) => {
if (datalayer.isLoaded() && !datalayer.isDataReadOnly() && datalayer.canBrowse()) { if (
datalayer.isLoaded() &&
!datalayer.isDataReadOnly() &&
datalayer.canBrowse()
) {
options.push([L.stamp(datalayer), datalayer.getName()]) options.push([L.stamp(datalayer), datalayer.getName()])
} }
}) })
@ -557,12 +561,10 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
L.DomEvent.on(el, 'click', this.fetchIconList, this) L.DomEvent.on(el, 'click', this.fetchIconList, this)
} }
} }
this.button = L.DomUtil.create('a', 'button action-button', this.buttonsContainer) this.button = L.DomUtil.createButton(
this.button.textContent = this.value() ? L._('Change') : L._('Add') 'button action-button',
this.button.href = '#' this.buttonsContainer,
L.DomEvent.on(this.button, 'click', L.DomEvent.stop).on( this.value() ? L._('Change') : L._('Add'),
this.button,
'click',
this.fetchIconList, this.fetchIconList,
this this
) )
@ -616,34 +618,29 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
for (const idx in data.pictogram_list) { for (const idx in data.pictogram_list) {
this.addIconPreview(data.pictogram_list[idx]) this.addIconPreview(data.pictogram_list[idx])
} }
const closeButton = L.DomUtil.create('a', 'button action-button', this.pictogramsContainer) const closeButton = L.DomUtil.createButton(
closeButton.textContent = L._('Close') 'button action-button',
closeButton.href = '#' this.pictogramsContainer,
closeButton.style.display = 'block' L._('Close'),
closeButton.style.clear = 'both'
L.DomEvent.on(closeButton, 'click', L.DomEvent.stop).on(
closeButton,
'click',
function (e) { function (e) {
this.pictogramsContainer.innerHTML = '' this.pictogramsContainer.innerHTML = ''
this.udpatePreview() this.udpatePreview()
}, },
this this
) )
const customButton = L.DomUtil.create('a', '', this.pictogramsContainer) closeButton.style.display = 'block'
customButton.textContent = L._('Toggle direct input (advanced)') closeButton.style.clear = 'both'
customButton.href = '#'
customButton.style.display = 'block' const customButton = L.DomUtil.createButton(
customButton.style.clear = 'both' 'flat',
this.builder.map.help.button(customButton, 'formatIconSymbol') this.pictogramsContainer,
L.DomEvent.on(customButton, 'click', L.DomEvent.stop).on( L._('Toggle direct input (advanced)'),
customButton,
'click',
function (e) { function (e) {
this.input.type = this.input.type === 'text' ? 'hidden' : 'text' this.input.type = this.input.type === 'text' ? 'hidden' : 'text'
}, },
this this
) )
this.builder.map.help.button(customButton, 'formatIconSymbol')
}, },
fetchIconList: function (e) { fetchIconList: function (e) {
@ -733,7 +730,10 @@ L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
fetch: function () { fetch: function () {
let value = (this.backup = this.toHTML()) let value = (this.backup = this.toHTML())
if (!this.container.querySelector(`input[type="radio"][value="${value}"]`)) if (!this.container.querySelector(`input[type="radio"][value="${value}"]`))
value = typeof(this.options.default) !== 'undefined' ? this.options.default : this.default value =
typeof this.options.default !== 'undefined'
? this.options.default
: this.default
this.container.querySelector(`input[type="radio"][value="${value}"]`).checked = true this.container.querySelector(`input[type="radio"][value="${value}"]`).checked = true
}, },
@ -843,7 +843,9 @@ L.FormBuilder.Range = L.FormBuilder.FloatInput.extend({
}, },
value: function () { value: function () {
return L.DomUtil.hasClass(this.wrapper, 'undefined') ? undefined : L.FormBuilder.FloatInput.prototype.value.call(this) return L.DomUtil.hasClass(this.wrapper, 'undefined')
? undefined
: L.FormBuilder.FloatInput.prototype.value.call(this)
}, },
buildHelpText: function () { buildHelpText: function () {
@ -858,7 +860,9 @@ L.FormBuilder.Range = L.FormBuilder.FloatInput.extend({
const step = this.options.step || 1, const step = this.options.step || 1,
digits = step < 1 ? 1 : 0 digits = step < 1 ? 1 : 0
for (let i = this.options.min; i <= this.options.max; i += this.options.step) { for (let i = this.options.min; i <= this.options.max; i += this.options.step) {
options += `<option value="${i.toFixed(digits)}" label="${i.toFixed(digits)}"></option>` options += `<option value="${i.toFixed(digits)}" label="${i.toFixed(
digits
)}"></option>`
} }
datalist.innerHTML = options datalist.innerHTML = options
L.FormBuilder.Input.prototype.buildHelpText.call(this) L.FormBuilder.Input.prototype.buildHelpText.call(this)

View file

@ -1558,16 +1558,10 @@ L.U.Map.include({
}) })
limitBounds.appendChild(boundsBuilder.build()) limitBounds.appendChild(boundsBuilder.build())
const boundsButtons = L.DomUtil.create('div', 'button-bar half', limitBounds) const boundsButtons = L.DomUtil.create('div', 'button-bar half', limitBounds)
const setCurrentButton = L.DomUtil.add( L.DomUtil.createButton(
'a',
'button', 'button',
boundsButtons, boundsButtons,
L._('Use current bounds') L._('Use current bounds'),
)
setCurrentButton.href = '#'
L.DomEvent.on(
setCurrentButton,
'click',
function () { function () {
const bounds = this.getBounds() const bounds = this.getBounds()
this.options.limitBounds.south = L.Util.formatNum(bounds.getSouth()) this.options.limitBounds.south = L.Util.formatNum(bounds.getSouth())
@ -1580,11 +1574,10 @@ L.U.Map.include({
}, },
this this
) )
const emptyBounds = L.DomUtil.add('a', 'button', boundsButtons, L._('Empty')) L.DomUtil.createButton(
emptyBounds.href = '#' 'button',
L.DomEvent.on( boundsButtons,
emptyBounds, L._('Empty'),
'click',
function () { function () {
this.options.limitBounds.south = null this.options.limitBounds.south = null
this.options.limitBounds.west = null this.options.limitBounds.west = null
@ -1676,34 +1669,39 @@ L.U.Map.include({
const advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions')) const advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions'))
const advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions) const advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions)
if (this.permissions.isOwner()) { if (this.permissions.isOwner()) {
const del = L.DomUtil.create('a', 'button umap-delete', advancedButtons) L.DomUtil.createButton(
del.href = '#' 'button umap-delete',
del.title = L._('Delete map') advancedButtons,
del.textContent = L._('Delete') L._('Delete'),
L.DomEvent.on(del, 'click', L.DomEvent.stop).on(del, 'click', this.del, this) this.del,
const empty = L.DomUtil.create('a', 'button umap-empty', advancedButtons) this
empty.href = '#' )
empty.textContent = L._('Empty') L.DomUtil.createButton(
empty.title = L._('Delete all layers') 'button umap-empty',
L.DomEvent.on(empty, 'click', L.DomEvent.stop).on( advancedButtons,
empty, L._('Empty'),
'click',
this.empty, this.empty,
this this
) )
} }
const clone = L.DomUtil.create('a', 'button umap-clone', advancedButtons) L.DomUtil.createButton(
clone.href = '#' 'button umap-clone',
clone.textContent = L._('Clone') advancedButtons,
clone.title = L._('Clone this map') L._('Clone this map'),
L.DomEvent.on(clone, 'click', L.DomEvent.stop).on(clone, 'click', this.clone, this) this.clone,
const download = L.DomUtil.create('a', 'button umap-download', advancedButtons) this
download.href = '#' )
download.textContent = L._('Download') L.DomUtil.createButton(
download.title = L._('Open download panel') 'button umap-empty',
L.DomEvent.on(download, 'click', L.DomEvent.stop).on( advancedButtons,
download, L._('Delete all layers'),
'click', this.empty,
this
)
L.DomUtil.createButton(
'button umap-download',
advancedButtons,
L._('Open download panel'),
this.renderShareBox, this.renderShareBox,
this this
) )
@ -1767,38 +1765,25 @@ L.U.Map.include({
L.DomEvent.disableClickPropagation(container) L.DomEvent.disableClickPropagation(container)
this.permissions.addOwnerLink('span', container) this.permissions.addOwnerLink('span', container)
if (this.options.captionMenus) { if (this.options.captionMenus) {
const about = L.DomUtil.add( L.DomUtil.createButton(
'a',
'umap-about-link', 'umap-about-link',
container, container,
`${L._('About')}` `${L._('About')}`,
this.displayCaption,
this
) )
about.href = '#' L.DomUtil.createButton(
L.DomEvent.on(about, 'click', this.displayCaption, this)
const browser = L.DomUtil.add(
'a',
'umap-open-browser-link', 'umap-open-browser-link',
container, container,
` | ${L._('Browse data')}` ` | ${L._('Browse data')}`,
)
browser.href = '#'
L.DomEvent.on(browser, 'click', L.DomEvent.stop).on(
browser,
'click',
this.openBrowser, this.openBrowser,
this this
) )
if (this.options.facetKey) { if (this.options.facetKey) {
const filter = L.DomUtil.add( L.DomUtil.createButton(
'a',
'umap-open-filter-link', 'umap-open-filter-link',
container, container,
` | ${L._('Select data')}` ` | ${L._('Select data')}`,
)
filter.href = '#'
L.DomEvent.on(filter, 'click', L.DomEvent.stop).on(
filter,
'click',
this.openFacet, this.openFacet,
this this
) )

View file

@ -1273,16 +1273,10 @@ L.U.DataLayer = L.Evented.extend({
const advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions')) const advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions'))
const advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions) const advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions)
const deleteLink = L.DomUtil.create( const deleteLink = L.DomUtil.createButton(
'a',
'button delete_datalayer_button umap-delete', 'button delete_datalayer_button umap-delete',
advancedButtons advancedButtons,
) L._('Delete'),
deleteLink.textContent = L._('Delete')
deleteLink.href = '#'
L.DomEvent.on(deleteLink, 'click', L.DomEvent.stop).on(
deleteLink,
'click',
function () { function () {
this._delete() this._delete()
this.map.ui.closePanel() this.map.ui.closePanel()
@ -1290,22 +1284,18 @@ L.U.DataLayer = L.Evented.extend({
this this
) )
if (!this.isRemoteLayer()) { if (!this.isRemoteLayer()) {
const emptyLink = L.DomUtil.create('a', 'button umap-empty', advancedButtons) const emptyLink = L.DomUtil.createButton(
emptyLink.textContent = L._('Empty') 'button umap-empty',
emptyLink.href = '#' advancedButtons,
L.DomEvent.on(emptyLink, 'click', L.DomEvent.stop).on( L._('Empty'),
emptyLink,
'click',
this.empty, this.empty,
this this
) )
} }
const cloneLink = L.DomUtil.create('a', 'button umap-clone', advancedButtons) const cloneLink = L.DomUtil.createButton(
cloneLink.textContent = L._('Clone') 'button umap-clone',
cloneLink.href = '#' advancedButtons,
L.DomEvent.on(cloneLink, 'click', L.DomEvent.stop).on( L._('Clone'),
cloneLink,
'click',
function () { function () {
const datalayer = this.clone() const datalayer = this.clone()
datalayer.edit() datalayer.edit()
@ -1313,10 +1303,13 @@ L.U.DataLayer = L.Evented.extend({
this this
) )
if (this.umap_id) { if (this.umap_id) {
const download = L.DomUtil.create('a', 'button umap-download', advancedButtons) const download = L.DomUtil.createLink(
download.textContent = L._('Download') 'button umap-download',
download.href = this._dataUrl() advancedButtons,
download.target = '_blank' L._('Download'),
this._dataUrl(),
'_blank'
)
} }
this.map.ui.openPanel({ data: { html: container }, className: 'dark' }) this.map.ui.openPanel({ data: { html: container }, className: 'dark' })
}, },
@ -1344,16 +1337,14 @@ L.U.DataLayer = L.Evented.extend({
const date = new Date(parseInt(data.at, 10)) const date = new Date(parseInt(data.at, 10))
const content = `${date.toLocaleString(L.lang)} (${parseInt(data.size) / 1000}Kb)` const content = `${date.toLocaleString(L.lang)} (${parseInt(data.size) / 1000}Kb)`
const el = L.DomUtil.create('div', 'umap-datalayer-version', versionsContainer) const el = L.DomUtil.create('div', 'umap-datalayer-version', versionsContainer)
const a = L.DomUtil.create('a', '', el) const a = L.DomUtil.createButton(
L.DomUtil.add('span', '', el, content) '',
a.href = '#' el,
a.title = L._('Restore this version') L._('Restore this version'),
L.DomEvent.on(a, 'click', L.DomEvent.stop).on(
a,
'click',
() => this.restore(data.name), () => this.restore(data.name),
this this
) )
L.DomUtil.add('span', '', el, content)
} }
const versionsContainer = L.DomUtil.createFieldset(container, L._('Versions'), { const versionsContainer = L.DomUtil.createFieldset(container, L._('Versions'), {

View file

@ -116,12 +116,10 @@ L.U.MapPermissions = L.Class.extend({
L._('Advanced actions') L._('Advanced actions')
) )
const advancedButtons = L.DomUtil.create('div', 'button-bar', advancedActions) const advancedButtons = L.DomUtil.create('div', 'button-bar', advancedActions)
const download = L.DomUtil.create('a', 'button', advancedButtons) const download = L.DomUtil.createButton(
download.href = '#' 'button',
download.textContent = L._('Attach the map to my account') advancedButtons,
L.DomEvent.on(download, 'click', L.DomEvent.stop).on( L._('Attach the map to my account'),
download,
'click',
this.attach, this.attach,
this this
) )
@ -188,15 +186,17 @@ L.U.MapPermissions = L.Class.extend({
addOwnerLink: function (element, container) { addOwnerLink: function (element, container) {
if (this.options.owner && this.options.owner.name && this.options.owner.url) { if (this.options.owner && this.options.owner.name && this.options.owner.url) {
const ownerContainer = L.DomUtil.add( const ownerContainer = L.DomUtil.add(
element, element,
'umap-map-owner', 'umap-map-owner',
container, container,
` ${L._('by')} ` ` ${L._('by')} `
), )
owner = L.DomUtil.create('a') L.DomUtil.createLink(
owner.href = this.options.owner.url '',
owner.textContent = this.options.owner.name ownerContainer,
ownerContainer.appendChild(owner) this.options.owner.name,
this.options.owner.url
)
} }
}, },

View file

@ -107,7 +107,7 @@ L.U.PopupTemplate.Default = L.Class.extend({
properties properties
) )
content = L.Util.greedyTemplate(template, properties) content = L.Util.greedyTemplate(template, properties)
content = L.Util.toHTML(content, {target: target}) content = L.Util.toHTML(content, { target: target })
container.innerHTML = content container.innerHTML = content
return container return container
}, },

View file

@ -93,41 +93,36 @@ L.U.UI = L.Evented.extend({
if (timeoutID) window.clearTimeout(timeoutID) if (timeoutID) window.clearTimeout(timeoutID)
this.popAlert() this.popAlert()
} }
const closeLink = L.DomUtil.create('a', 'umap-close-link', this._alert) const closeButton = L.DomUtil.createButton(
closeLink.href = '#' 'umap-close-link',
L.DomUtil.add('i', 'umap-close-icon', closeLink) this._alert,
const label = L.DomUtil.create('span', '', closeLink) '',
label.title = label.textContent = L._('Close')
L.DomEvent.on(closeLink, 'click', L.DomEvent.stop).on(
closeLink,
'click',
close, close,
this this
) )
L.DomUtil.add('i', 'umap-close-icon', closeButton)
const label = L.DomUtil.create('span', '', closeButton)
label.title = label.textContent = L._('Close')
L.DomUtil.add('div', '', this._alert, e.content) L.DomUtil.add('div', '', this._alert, e.content)
if (e.actions) { if (e.actions) {
let action, el, input let action, el, input
const form = L.DomUtil.add('div', 'umap-alert-actions', this._alert)
for (let i = 0; i < e.actions.length; i++) { for (let i = 0; i < e.actions.length; i++) {
action = e.actions[i] action = e.actions[i]
if (action.input) { if (action.input) {
input = L.DomUtil.element( input = L.DomUtil.element(
'input', 'input',
{ className: 'umap-alert-input', placeholder: action.input }, { className: 'umap-alert-input', placeholder: action.input },
this._alert form
)
}
el = L.DomUtil.element('a', { className: 'umap-action' }, this._alert)
el.href = '#'
el.textContent = action.label
L.DomEvent.on(el, 'click', L.DomEvent.stop)
if (action.callback) {
L.DomEvent.on(
el,
'click',
action.callback,
action.callbackContext || this.map
) )
} }
el = L.DomUtil.createButton(
'umap-action',
form,
action.label,
action.callback,
action.callbackContext || this.map
)
L.DomEvent.on(el, 'click', close, this) L.DomEvent.on(el, 'click', close, this)
} }
} }
@ -139,20 +134,32 @@ L.U.UI = L.Evented.extend({
} }
}, },
tooltip: function (e) { tooltip: function (opts) {
this.TOOLTIP_ID = Math.random() this.TOOLTIP_ID = Math.random()
const id = this.TOOLTIP_ID const id = this.TOOLTIP_ID
L.DomUtil.addClass(this.parent, 'umap-tooltip') function showIt() {
if (e.anchor && e.position === 'top') this.anchorTooltipTop(e.anchor) if (opts.anchor && opts.position === 'top') {
else if (e.anchor && e.position === 'left') this.anchorTooltipLeft(e.anchor) this.anchorTooltipTop(opts.anchor)
else this.anchorTooltipAbsolute() } else if (opts.anchor && opts.position === 'left') {
this._tooltip.innerHTML = e.content this.anchorTooltipLeft(opts.anchor)
} else if (opts.anchor && opts.position === 'bottom') {
this.anchorTooltipBottom(opts.anchor)
} else {
this.anchorTooltipAbsolute()
}
L.DomUtil.addClass(this.parent, 'umap-tooltip')
this._tooltip.innerHTML = opts.content
}
function closeIt() { function closeIt() {
this.closeTooltip(id) this.closeTooltip(id)
} }
if (e.anchor) L.DomEvent.once(e.anchor, 'mouseout', closeIt, this) window.setTimeout(L.bind(showIt, this), opts.delay || 0)
if (e.duration !== Infinity) if (opts.anchor) {
window.setTimeout(L.bind(closeIt, this), e.duration || 3000) L.DomEvent.once(opts.anchor, 'mouseout', closeIt, this)
}
if (opts.duration !== Infinity) {
window.setTimeout(L.bind(closeIt, this), opts.duration || 3000)
}
}, },
anchorTooltipAbsolute: function () { anchorTooltipAbsolute: function () {
@ -174,6 +181,15 @@ L.U.UI = L.Evented.extend({
}) })
}, },
anchorTooltipBottom: function (el) {
this._tooltip.className = 'tooltip-bottom'
const coords = this.getPosition(el)
this.setTooltipPosition({
left: coords.left,
top: coords.bottom + 11,
})
},
anchorTooltipLeft: function (el) { anchorTooltipLeft: function (el) {
this._tooltip.className = 'tooltip-left' this._tooltip.className = 'tooltip-left'
const coords = this.getPosition(el) const coords = this.getPosition(el)
@ -185,7 +201,9 @@ L.U.UI = L.Evented.extend({
closeTooltip: function (id) { closeTooltip: function (id) {
if (id && id !== this.TOOLTIP_ID) return if (id && id !== this.TOOLTIP_ID) return
this._tooltip.className = ''
this._tooltip.innerHTML = '' this._tooltip.innerHTML = ''
this.setTooltipPosition({})
L.DomUtil.removeClass(this.parent, 'umap-tooltip') L.DomUtil.removeClass(this.parent, 'umap-tooltip')
}, },

View file

@ -42,7 +42,8 @@
} }
.leaflet-measure-control a, .leaflet-measure-control a,
.leaflet-control-locate a, .leaflet-control-locate a,
.umap-control a { .umap-control a,
.umap-control [type="button"] {
background-position: 50% 50%; background-position: 50% 50%;
background-repeat: no-repeat; background-repeat: no-repeat;
display: block; display: block;
@ -50,15 +51,19 @@
width: 36px; width: 36px;
line-height: 36px; line-height: 36px;
background-image: url('./img/24.svg'); background-image: url('./img/24.svg');
text-indent: -9999px;
margin-bottom: 0;
} }
.leaflet-control.display-on-more, .leaflet-control.display-on-more,
a.umap-control-less { .umap-control-less {
display: none; display: none;
} }
.umap-control-more, .umap-control-more,
.umap-control-less { .umap-control-less {
background-image: url('./img/24-white.svg'); background-image: url('./img/24-white.svg');
background-position: -72px -474px; background-position: -72px -474px;
text-indent: -9999px;
margin-bottom: 0;
} }
.umap-control-less { .umap-control-less {
background-position: -108px -476px; background-position: -108px -476px;
@ -70,13 +75,13 @@ a.umap-control-less {
.umap-more-controls .umap-control-more { .umap-more-controls .umap-control-more {
display: none; display: none;
} }
.leaflet-control-embed a { .leaflet-control-embed [type="button"] {
background-position: -72px -108px; background-position: -72px -108px;
} }
.leaflet-control-tilelayers a { .leaflet-control-tilelayers [type="button"] {
background-position: -72px 0; background-position: -72px 0;
} }
.leaflet-control-home a { .leaflet-control-home [type="button"] {
background-position: -122px -82px; background-position: -122px -82px;
} }
.leaflet-control-locate a { .leaflet-control-locate a {
@ -88,17 +93,17 @@ a.umap-control-less {
background-position: -72px -144px; background-position: -72px -144px;
box-shadow: 0 0 4px 0 black inset; box-shadow: 0 0 4px 0 black inset;
} }
.leaflet-control-star a { .leaflet-control-star [type="button"] {
background-position: -108px -144px; background-position: -108px -144px;
} }
.leaflet-control-star.starred a { .leaflet-control-star.starred [type="button"] {
background-position: -144px -144px; background-position: -144px -144px;
} }
.leaflet-control-search a { .leaflet-control-search [type="button"] {
background-position: -36px -108px; background-position: -36px -108px;
display: block; display: block;
} }
.leaflet-control-search a.loading { .leaflet-control-search [type="button"].loading {
background-image: url('./img/search.gif'); background-image: url('./img/search.gif');
} }
.umap-control-text { .umap-control-text {
@ -109,14 +114,15 @@ a.umap-control-less {
text-align: center; text-align: center;
font-size: 0.8em; font-size: 0.8em;
} }
.umap-control-text a { .umap-control-text [type="button"] {
float: right; float: right;
background-color: #666;
margin: 0; margin: 0;
width: 36px; width: 36px;
min-height: 23px;
height: 23px; height: 23px;
line-height: 23px;
} }
.leaflet-control-edit-enable a:before { .leaflet-control-edit-enable [type="button"]:before {
content: ' '; content: ' ';
width: 24px; width: 24px;
height: 24px; height: 24px;
@ -126,7 +132,7 @@ a.umap-control-less {
background-position: -52px -49px; background-position: -52px -49px;
} }
.leaflet-control-edit-enable a { .leaflet-control-edit-enable [type="button"] {
width: initial; width: initial;
padding: 0 20px; padding: 0 20px;
background-color: #353c3e; background-color: #353c3e;
@ -138,7 +144,7 @@ a.umap-control-less {
display: block; display: block;
} }
.leaflet-control-toolbar .leaflet-toolbar-icon.dark:hover, .leaflet-control-toolbar .leaflet-toolbar-icon.dark:hover,
.leaflet-control-edit-enable a:hover { .leaflet-control-edit-enable [type="button"]:hover {
background-color: #4d5759; background-color: #4d5759;
} }
.umap-permanent-credits-container { .umap-permanent-credits-container {
@ -320,6 +326,7 @@ ul.photon-autocomplete {
border: 1px solid #bbb; border: 1px solid #bbb;
border-radius: 4px; border-radius: 4px;
box-shadow: none; box-shadow: none;
background-color: white;
} }
.leaflet-measure-control a { .leaflet-measure-control a {
background-position: 0 -72px; background-position: 0 -72px;
@ -353,6 +360,7 @@ ul.photon-autocomplete {
} }
.umap-help-box .umap-close-link { .umap-help-box .umap-close-link {
float: right; float: right;
width: 100px;
} }
.umap-help-button { .umap-help-button {
display: inline-block; display: inline-block;
@ -362,15 +370,16 @@ ul.photon-autocomplete {
background-position: -4px -4px; background-position: -4px -4px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-image: url('./img/16.svg'); background-image: url('./img/16.svg');
background-color: #323737 !important;
vertical-align: middle; vertical-align: middle;
text-indent: -9999px;
min-height: inherit;
padding-top: 5px;
border: none !important;
} }
.dark .umap-help-button { .dark .umap-help-button {
background-image: url('./img/16-white.svg'); background-image: url('./img/16-white.svg');
} }
.umap-help-link {
float: right;
margin-right: 20px;
}
.umap-help-on .umap-help-box { .umap-help-on .umap-help-box {
visibility: visible; visibility: visible;
top: 100px; top: 100px;
@ -411,27 +420,37 @@ ul.photon-autocomplete {
/* ********************************* */ /* ********************************* */
/* Edit main toolbox */ /* Edit main toolbox */
/* ********************************* */ /* ********************************* */
.umap-main-edit-toolbox [type="button"] {
color: #fff;
font-size: 1.2em;
border: none;
background-color: #323737;
width: auto;
margin-bottom: 0;
}
.umap-main-edit-toolbox [type="button"]:hover {
text-decoration: underline;
}
.leaflet-container a.leaflet-control-edit-save, .leaflet-container .umap-help-link {
.leaflet-container a.leaflet-control-edit-cancel, font-size: 12px;
.leaflet-container a.leaflet-control-edit-disable { }
.leaflet-container .leaflet-control-edit-save,
.leaflet-container .leaflet-control-edit-cancel,
.leaflet-container .leaflet-control-edit-disable {
display: block; display: block;
border: none; border: none;
font-size: 11px; font-size: 12px;
margin-left: 10px;
float: right;
border-radius: 20px; border-radius: 20px;
color: #f8f8f8; color: #f8f8f8;
width: auto;
height: 36px; height: 36px;
line-height: 36px; line-height: 36px;
min-height: 36px; min-height: 36px;
padding: 0 20px; padding: 0 20px;
min-width: 100px;
} }
.leaflet-container a.leaflet-control-edit-disable:before, .leaflet-container .leaflet-control-edit-disable:before,
.leaflet-container a.leaflet-control-edit-save:before, .leaflet-container .leaflet-control-edit-save:before,
.leaflet-container a.leaflet-control-edit-cancel:before { .leaflet-container .leaflet-control-edit-cancel:before {
display: inline-block; display: inline-block;
width: 24px; width: 24px;
height: 24px; height: 24px;
@ -441,37 +460,40 @@ ul.photon-autocomplete {
vertical-align: middle; vertical-align: middle;
content: ' '; content: ' ';
} }
.leaflet-container a.leaflet-control-edit-save:before { .leaflet-container .leaflet-control-edit-save:before {
background-position: -2px -25px; background-position: -2px -25px;
} }
.leaflet-container a.leaflet-control-edit-disable:before { .leaflet-container .leaflet-control-edit-disable:before {
background-position: -26px -1px; background-position: -52px -25px;
} }
.leaflet-container a.leaflet-control-edit-cancel, .leaflet-container .leaflet-control-edit-cancel,
.leaflet-container a.leaflet-control-edit-disable { .leaflet-container .leaflet-control-edit-disable {
border: 1px solid #555; border: 1px solid #555;
} }
.leaflet-container a.leaflet-control-edit-save { .leaflet-container .leaflet-control-edit-save {
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;
background-color: #215d9c; background-color: #215d9c;
} }
.umap-is-dirty a.leaflet-control-edit-save { .umap-is-dirty .leaflet-control-edit-save {
opacity: 1; opacity: 1;
cursor: pointer; cursor: pointer;
} }
.leaflet-container a.leaflet-control-edit-save, .umap-is-dirty .leaflet-control-edit-save:hover {
.leaflet-container a.leaflet-control-edit-cancel, background-color: #215d9c;
.leaflet-container a.leaflet-control-edit-disable, }
.leaflet-container .leaflet-control-edit-save,
.leaflet-container .leaflet-control-edit-cancel,
.leaflet-container .leaflet-control-edit-disable,
.umap-edit-enabled .leaflet-control-edit-enable { .umap-edit-enabled .leaflet-control-edit-enable {
display: none; display: none;
} }
.umap-edit-enabled a.leaflet-control-edit-save, .umap-edit-enabled .leaflet-control-edit-save,
.umap-edit-enabled a.leaflet-control-edit-disable, .umap-edit-enabled .leaflet-control-edit-disable,
.umap-edit-enabled .umap-is-dirty a.leaflet-control-edit-cancel { .umap-edit-enabled .umap-is-dirty .leaflet-control-edit-cancel {
display: inline-block; display: inline-block;
} }
.umap-is-dirty a.leaflet-control-edit-disable { .umap-is-dirty .leaflet-control-edit-disable {
display: none; display: none;
} }
.umap-caption-bar { .umap-caption-bar {
@ -485,7 +507,7 @@ ul.photon-autocomplete {
right: 0; right: 0;
height: 46px; height: 46px;
background-color: #323737; background-color: #323737;
padding: 5px 10px; padding: 0 10px;
text-align: left; text-align: left;
line-height: 36px; line-height: 36px;
cursor: auto; cursor: auto;
@ -493,45 +515,56 @@ ul.photon-autocomplete {
z-index: 1000; z-index: 1000;
opacity: 0.98; opacity: 0.98;
color: #fff; color: #fff;
display: flex;
justify-content: space-between;
} }
.umap-left-edit-toolbox,
.umap-right-edit-toolbox {
display: flex;
column-gap: 10px;
}
.umap-right-edit-toolbox {
align-items: baseline;
}
.umap-main-edit-toolbox .logo { .umap-main-edit-toolbox .logo {
width: 39px;
height: 100%;
}
.umap-main-edit-toolbox .logo a {
background-image: url('./img/logo_small.svg'); background-image: url('./img/logo_small.svg');
background-position: 0 center; background-position: 0 center;
background-repeat: no-repeat; background-repeat: no-repeat;
width: 60px;
display: inline-block; display: inline-block;
width: 39px;
height: 100%; height: 100%;
vertical-align: middle; vertical-align: middle;
} text-indent: -9999px;
.umap-main-edit-toolbox a {
color: #fff;
font-size: 1.2em;
vertical-align: middle;
}
.umap-main-edit-toolbox a:hover {
text-decoration: underline;
} }
.umap-main-edit-toolbox .map-name { .umap-main-edit-toolbox .map-name {
display: inline-block; display: inline-block;
max-width: 200px;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
margin-right: 5px;
font-weight: bold; font-weight: bold;
text-align: left;
} }
a.map-name:after { .umap-main-edit-toolbox .share-status {
font-size: 1em;
font-style: italic;
overflow: hidden;
text-overflow: ellipsis;
}
.map-name:after {
content: '\00a0'; content: '\00a0';
padding-left: 3px; padding-left: 3px;
width: 1ch; width: 1ch;
display: inline-block; display: inline-block;
} }
.umap-is-dirty a.map-name:after { .umap-is-dirty .map-name:after {
content: '*'; content: '*';
} }
.umap-main-edit-toolbox .share-status {
margin: 0 20px;
}
.umap-edit-enabled .umap-main-edit-toolbox { .umap-edit-enabled .umap-main-edit-toolbox {
top: 0; top: 0;
} }
@ -543,12 +576,15 @@ a.map-name:after {
display: inline; display: inline;
} }
.umap-main-edit-toolbox .umap-user { .umap-main-edit-toolbox .umap-user {
margin-right: 20px; color: #fff;
float: right; }
.umap-main-edit-toolbox .umap-user:hover {
text-decoration: underline;
} }
.umap-main-edit-toolbox .umap-user:after { .umap-main-edit-toolbox .umap-user:after {
content: '|'; content: '|';
padding-left: 20px; padding-left: 20px;
display: inline-block; /* Prevents underline on hover. */
} }
.umap-edit-enabled .leaflet-top { .umap-edit-enabled .leaflet-top {
top: 48px; top: 48px;
@ -813,13 +849,14 @@ a.map-name:after {
.leaflet-control-browse .umap-browse-actions .off .layer-title { .leaflet-control-browse .umap-browse-actions .off .layer-title {
color: rgb(179, 179, 179); color: rgb(179, 179, 179);
} }
.leaflet-control-browse.expanded > a { .leaflet-control-browse.expanded > a,
.leaflet-control-browse.expanded > button {
display: none; display: none;
} }
.leaflet-control-browse.expanded .umap-browse-actions { .leaflet-control-browse.expanded .umap-browse-actions {
display: block; display: block;
} }
.leaflet-control-browse a.umap-browse-link { .leaflet-control-browse .umap-browse-link {
background-image: none; background-image: none;
background-color: rgb(68, 68, 68); background-color: rgb(68, 68, 68);
color: white; color: white;
@ -834,7 +871,7 @@ a.map-name:after {
border-radius: 2px; border-radius: 2px;
} }
a.add-datalayer:before, a.add-datalayer:before,
.leaflet-control-browse a.umap-browse-link:before { .leaflet-control-browse .umap-browse-link:before {
background-image: url('./img/16.svg'); background-image: url('./img/16.svg');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: -45px -96px; background-position: -45px -96px;
@ -848,7 +885,7 @@ a.add-datalayer:before {
background-position: -20px -20px; background-position: -20px -20px;
} }
a.add-datalayer:hover, a.add-datalayer:hover,
.leaflet-control-browse a.umap-browse-link:hover { .leaflet-control-browse .umap-browse-link:hover {
background-color: rgb(99, 99, 99); background-color: rgb(99, 99, 99);
} }
.umap-browse-data .off .feature { .umap-browse-data .off .feature {
@ -1513,14 +1550,12 @@ a.add-datalayer:hover,
@media all and (max-width: 980px) { @media all and (max-width: 980px) {
.leaflet-container a.leaflet-control-edit-save, .umap-main-edit-toolbox .umap-user span,
.leaflet-container a.leaflet-control-edit-disable, .leaflet-container .leaflet-control-edit-save span,
.leaflet-container a.leaflet-control-edit-cancel { .leaflet-container .leaflet-control-edit-disable span,
text-indent: calc(100% - 10px); .leaflet-container .leaflet-control-edit-cancel span {
width: 35px; display: none;
min-width: initial;
} }
.umap-main-edit-toolbox .umap-help-button { .umap-main-edit-toolbox .umap-help-button {
display: none; display: none;
} }
@ -1530,7 +1565,15 @@ a.add-datalayer:hover,
.umap-main-edit-toolbox .umap-user:after { .umap-main-edit-toolbox .umap-user:after {
display: none; display: none;
} }
}
@media all and (max-width: 640px) {
.umap-main-edit-toolbox .umap-user {
display: none;
}
.umap-main-edit-toolbox .map-name {
max-width: 150px;
}
} }
@media all and (max-width: 480px) { @media all and (max-width: 480px) {

View file

@ -205,7 +205,7 @@ describe('L.U.Choropleth', function () {
}) })
after(function () { after(function () {
this.server.restore() this.server.restore()
//resetMap() resetMap()
}) })
describe('#init()', function () { describe('#init()', function () {

View file

@ -78,7 +78,7 @@ describe('L.U.Controls', function () {
describe('#exportPanel()', function () { describe('#exportPanel()', function () {
it('should be opened at datalayer button click', function () { it('should be opened at datalayer button click', function () {
let button = qs('.leaflet-control-embed a') let button = qs('.leaflet-control-embed button')
assert.ok(button) assert.ok(button)
happen.click(button) happen.click(button)
assert.ok(qs('#umap-ui-container .umap-share')) assert.ok(qs('#umap-ui-container .umap-share'))

View file

@ -341,7 +341,7 @@ describe('L.U.DataLayer', function () {
happen.click( happen.click(
qs('#browse_data_toggle_' + L.stamp(this.datalayer) + ' .layer-edit') qs('#browse_data_toggle_' + L.stamp(this.datalayer) + ' .layer-edit')
) )
deleteLink = qs('a.delete_datalayer_button') deleteLink = qs('button.delete_datalayer_button')
assert.ok(deleteLink) assert.ok(deleteLink)
}) })

View file

@ -50,7 +50,7 @@ describe('L.U.Map', function () {
}) })
it('enable edit on click on toggle button', function () { it('enable edit on click on toggle button', function () {
var el = qs('div.leaflet-control-edit-enable a') var el = qs('div.leaflet-control-edit-enable button')
happen.click(el) happen.click(el)
assert.isTrue(L.DomUtil.hasClass(document.body, 'umap-edit-enabled')) assert.isTrue(L.DomUtil.hasClass(document.body, 'umap-edit-enabled'))
}) })
@ -109,7 +109,7 @@ describe('L.U.Map', function () {
var button = qs('a.update-map-settings') var button = qs('a.update-map-settings')
assert.ok(button, 'update map info button exists') assert.ok(button, 'update map info button exists')
happen.click(button) happen.click(button)
var deleteLink = qs('a.umap-delete') var deleteLink = qs('button.umap-delete')
assert.ok(deleteLink, 'delete map button exists') assert.ok(deleteLink, 'delete map button exists')
sinon.spy(window, 'confirm') sinon.spy(window, 'confirm')
this.server.respondWith('POST', path, JSON.stringify({ redirect: '#' })) this.server.respondWith('POST', path, JSON.stringify({ redirect: '#' }))
@ -301,7 +301,7 @@ describe('L.U.Map', function () {
}) })
it('should update title bar (umap format import)', function () { it('should update title bar (umap format import)', function () {
var title = qs('#map div.umap-main-edit-toolbox a.map-name') var title = qs('#map div.umap-main-edit-toolbox button.map-name')
assert.equal(title.innerHTML, 'Imported map') assert.equal(title.innerHTML, 'Imported map')
}) })

View file

@ -44,20 +44,20 @@ var resetMap = function () {
document.body.className = '' document.body.className = ''
} }
var enableEdit = function () { var enableEdit = function () {
happen.click(qs('div.leaflet-control-edit-enable a')) happen.click(qs('div.leaflet-control-edit-enable button'))
} }
var disableEdit = function () { var disableEdit = function () {
happen.click(qs('a.leaflet-control-edit-disable')) happen.click(qs('.leaflet-control-edit-disable'))
} }
var clickSave = function () { var clickSave = function () {
happen.click(qs('a.leaflet-control-edit-save')) happen.click(qs('.leaflet-control-edit-save'))
} }
var clickCancel = function () { var clickCancel = function () {
var _confirm = window.confirm var _confirm = window.confirm
window.confirm = function (text) { window.confirm = function (text) {
return true return true
} }
happen.click(qs('a.leaflet-control-edit-cancel')) happen.click(qs('button.leaflet-control-edit-cancel'))
happen.once(document.body, { type: 'keypress', keyCode: 13 }) happen.once(document.body, { type: 'keypress', keyCode: 13 })
window.confirm = _confirm window.confirm = _confirm
} }