chore: move tooltip to a dedicated module

This commit is contained in:
Yohan Boniface 2024-05-22 10:40:37 +02:00
parent 8ddc570e23
commit 2ed9bc65ee
11 changed files with 191 additions and 196 deletions

View file

@ -756,69 +756,6 @@ input[type=hidden].blur + [type="button"] {
}
/* *********** */
/* Tooltip */
/* *********** */
#umap-tooltip-container {
line-height: 20px;
padding: 5px 10px;
width: auto;
position: absolute;
box-shadow: 0 1px 7px #999999;
display: none;
background-color: rgba(40, 40, 40, 0.8);
color: #eeeeec;
font-size: 0.8em;
border-radius: 2px;
z-index: 1011;
font-weight: normal;
max-width: 300px;
}
.umap-tooltip #umap-tooltip-container {
display: block;
}
#umap-tooltip-container.tooltip-top:after {
top: 100%;
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.8);
border-width: 11px;
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 {
left: 100%;
top: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(136, 183, 213, 0);
border-left-color: #333;
border-width: 11px;
margin-top: -10px;
}
/* *********** */
/* Various */
/* *********** */

View file

@ -0,0 +1,59 @@
#umap-tooltip-container {
line-height: 20px;
padding: 5px 10px;
width: auto;
position: absolute;
box-shadow: 0 1px 7px #999999;
display: none;
background-color: rgba(40, 40, 40, 0.8);
color: #eeeeec;
font-size: 0.8em;
border-radius: 2px;
z-index: 1011;
font-weight: normal;
max-width: 300px;
}
.umap-tooltip #umap-tooltip-container {
display: block;
}
#umap-tooltip-container.tooltip-top:after {
top: 100%;
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.8);
border-width: 11px;
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 {
left: 100%;
top: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(136, 183, 213, 0);
border-left-color: #333;
border-width: 11px;
margin-top: -10px;
}

View file

@ -4,6 +4,7 @@ import Facets from './facets.js'
import Caption from './caption.js'
import { Panel, EditPanel, FullPanel } from './panel.js'
import Alert from './ui/alert.js'
import Tooltip from './ui/tooltip.js'
import * as Utils from './utils.js'
import { SCHEMA } from './schema.js'
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
@ -23,6 +24,7 @@ window.U = {
Facets,
Panel,
Alert,
Tooltip,
EditPanel,
FullPanel,
Utils,

View file

@ -0,0 +1,116 @@
import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
import { translate } from '../i18n.js'
export default class Tooltip {
constructor(parent) {
this.parent = parent
this.container = DomUtil.create('div', 'with-transition', this.parent)
this.container.id = 'umap-tooltip-container'
DomEvent.disableClickPropagation(this.container)
DomEvent.on(this.container, 'contextmenu', DomEvent.stopPropagation) // Do not activate our custom context menu.
DomEvent.on(this.container, 'wheel', DomEvent.stopPropagation)
DomEvent.on(this.container, 'MozMousePixelScroll', DomEvent.stopPropagation)
}
open(opts) {
function showIt() {
if (opts.anchor && opts.position === 'top') {
this.anchorTop(opts.anchor)
} else if (opts.anchor && opts.position === 'left') {
this.anchorLeft(opts.anchor)
} else if (opts.anchor && opts.position === 'bottom') {
this.anchorBottom(opts.anchor)
} else {
this.anchorAbsolute()
}
L.DomUtil.addClass(this.parent, 'umap-tooltip')
this.container.innerHTML = U.Utils.escapeHTML(opts.content)
}
this.TOOLTIP_ID = window.setTimeout(L.bind(showIt, this), opts.delay || 0)
const id = this.TOOLTIP_ID
const closeIt = () => {
this.close(id)
}
if (opts.anchor) {
L.DomEvent.once(opts.anchor, 'mouseout', closeIt)
}
if (opts.duration !== Infinity) {
window.setTimeout(closeIt, opts.duration || 3000)
}
}
anchorAbsolute() {
this.container.className = ''
const left =
this.parent.offsetLeft +
this.parent.clientWidth / 2 -
this.container.clientWidth / 2,
top = this.parent.offsetTop + 75
this.setPosition({ top: top, left: left })
}
anchorTop(el) {
this.container.className = 'tooltip-top'
const coords = this.getPosition(el)
this.setPosition({
left: coords.left - 10,
bottom: this.getDocHeight() - coords.top + 11,
})
}
anchorBottom(el) {
this.container.className = 'tooltip-bottom'
const coords = this.getPosition(el)
this.setPosition({
left: coords.left,
top: coords.bottom + 11,
})
}
anchorLeft(el) {
this.container.className = 'tooltip-left'
const coords = this.getPosition(el)
this.setPosition({
top: coords.top,
right: document.documentElement.offsetWidth - coords.left + 11,
})
}
close(id) {
// Clear timetout even if a new tooltip has been added
// in the meantime. Eg. after a mouseout from the anchor.
window.clearTimeout(id)
if (id && id !== this.TOOLTIP_ID) return
this.container.className = ''
this.container.innerHTML = ''
this.setPosition({})
L.DomUtil.removeClass(this.parent, 'umap-tooltip')
}
getPosition(el) {
return el.getBoundingClientRect()
}
setPosition(coords) {
if (coords.left) this.container.style.left = `${coords.left}px`
else this.container.style.left = 'initial'
if (coords.right) this.container.style.right = `${coords.right}px`
else this.container.style.right = 'initial'
if (coords.top) this.container.style.top = `${coords.top}px`
else this.container.style.top = 'initial'
if (coords.bottom) this.container.style.bottom = `${coords.bottom}px`
else this.container.style.bottom = 'initial'
}
getDocHeight() {
const D = document
return Math.max(
D.body.scrollHeight,
D.documentElement.scrollHeight,
D.body.offsetHeight,
D.documentElement.offsetHeight,
D.body.clientHeight,
D.documentElement.clientHeight
)
}
}

View file

@ -394,7 +394,7 @@ U.EditControl = L.Control.extend({
enableEditing,
'mouseover',
function () {
map.ui.tooltip({
map.tooltip.open({
content: map.help.displayLabel('TOGGLE_EDIT'),
anchor: enableEditing,
position: 'bottom',
@ -693,7 +693,7 @@ const ControlsMixin = {
nameButton,
'mouseover',
function () {
this.ui.tooltip({
this.tooltip.open({
content: L._('Edit the title of the map'),
anchor: nameButton,
position: 'bottom',
@ -714,7 +714,7 @@ const ControlsMixin = {
shareStatusButton,
'mouseover',
function () {
this.ui.tooltip({
this.tooltip.open({
content: L._('Update who can see and edit the map'),
anchor: shareStatusButton,
position: 'bottom',
@ -763,7 +763,7 @@ const ControlsMixin = {
controlEditCancel,
'mouseover',
function () {
this.ui.tooltip({
this.tooltip.open({
content: this.help.displayLabel('CANCEL'),
anchor: controlEditCancel,
position: 'bottom',
@ -784,7 +784,7 @@ const ControlsMixin = {
controlEditDisable,
'mouseover',
function () {
this.ui.tooltip({
this.tooltip.open({
content: this.help.displayLabel('PREVIEW'),
anchor: controlEditDisable,
position: 'bottom',
@ -805,7 +805,7 @@ const ControlsMixin = {
controlEditSave,
'mouseover',
function () {
this.ui.tooltip({
this.tooltip.open({
content: this.help.displayLabel('SAVE'),
anchor: controlEditSave,
position: 'bottom',
@ -1249,7 +1249,7 @@ U.Editable = L.Editable.extend({
L.Editable.prototype.initialize.call(this, map, options)
this.on('editable:drawing:click editable:drawing:move', this.drawingTooltip)
this.on('editable:drawing:end', (e) => {
this.closeTooltip()
this.map.tooltip.close()
// Leaflet.Editable will delete the drawn shape if invalid
// (eg. line has only one drawn point)
// So let's check if the layer has no more shape
@ -1313,7 +1313,7 @@ U.Editable = L.Editable.extend({
drawingTooltip: function (e) {
if (e.layer instanceof L.Marker && e.type == 'editable:drawing:start') {
this.map.ui.tooltip({ content: L._('Click to add a marker') })
this.map.tooltip.open({ content: L._('Click to add a marker') })
}
if (!(e.layer instanceof L.Polyline)) {
// only continue with Polylines and Polygons
@ -1356,7 +1356,7 @@ U.Editable = L.Editable.extend({
}
}
if (content) {
this.map.ui.tooltip({ content: content })
this.map.tooltip.open({ content: content })
}
},

View file

@ -878,9 +878,9 @@ U.PathMixin = {
_onMouseOver: function () {
if (this.map.measureTools && this.map.measureTools.enabled()) {
this.map.ui.tooltip({ content: this.getMeasure(), anchor: this })
this.map.tooltip.open({ content: this.getMeasure(), anchor: this })
} else if (this.map.editEnabled && !this.map.editedFeature) {
this.map.ui.tooltip({ content: L._('Click to edit'), anchor: this })
this.map.tooltip.open({ content: L._('Click to edit'), anchor: this })
}
},

View file

@ -78,7 +78,7 @@ L.FormBuilder.Element.include({
info,
'mouseover',
function () {
this.builder.map.ui.tooltip({
this.builder.map.tooltip.open({
anchor: info,
content: this.options.helpTooltip,
position: 'top',

View file

@ -58,11 +58,11 @@ U.Map = L.Map.extend({
this.panel = new U.Panel(this)
this.alert = new U.Alert(this._controlContainer)
this.tooltip = new U.Tooltip(this._controlContainer)
if (this.hasEditMode()) {
this.editPanel = new U.EditPanel(this)
this.fullPanel = new U.FullPanel(this)
}
this.ui = new U.UI(this._container)
L.DomEvent.on(document.body, 'dataloading', (e) => this.fire('dataloading', e))
L.DomEvent.on(document.body, 'dataload', (e) => this.fire('dataload', e))
this.server = new U.ServerRequest(this.alert)

View file

@ -1,119 +0,0 @@
/*
* Modals
*/
U.UI = L.Evented.extend({
TOOLTIP_ID: null,
initialize: function (parent) {
this.parent = parent
this.container = L.DomUtil.create('div', 'leaflet-ui-container', this.parent)
L.DomEvent.disableClickPropagation(this.container)
L.DomEvent.on(this.container, 'contextmenu', L.DomEvent.stopPropagation) // Do not activate our custom context menu.
L.DomEvent.on(this.container, 'wheel', L.DomEvent.stopPropagation)
L.DomEvent.on(this.container, 'MozMousePixelScroll', L.DomEvent.stopPropagation)
this._tooltip = L.DomUtil.create('div', '', this.container)
this._tooltip.id = 'umap-tooltip-container'
},
tooltip: function (opts) {
function showIt() {
if (opts.anchor && opts.position === 'top') {
this.anchorTooltipTop(opts.anchor)
} else if (opts.anchor && opts.position === 'left') {
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 = U.Utils.escapeHTML(opts.content)
}
this.TOOLTIP_ID = window.setTimeout(L.bind(showIt, this), opts.delay || 0)
const id = this.TOOLTIP_ID
function closeIt() {
this.closeTooltip(id)
}
if (opts.anchor) {
L.DomEvent.once(opts.anchor, 'mouseout', closeIt, this)
}
if (opts.duration !== Infinity) {
window.setTimeout(L.bind(closeIt, this), opts.duration || 3000)
}
},
anchorTooltipAbsolute: function () {
this._tooltip.className = ''
const left =
this.parent.offsetLeft +
this.parent.clientWidth / 2 -
this._tooltip.clientWidth / 2,
top = this.parent.offsetTop + 75
this.setTooltipPosition({ top: top, left: left })
},
anchorTooltipTop: function (el) {
this._tooltip.className = 'tooltip-top'
const coords = this.getPosition(el)
this.setTooltipPosition({
left: coords.left - 10,
bottom: this.getDocHeight() - coords.top + 11,
})
},
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) {
this._tooltip.className = 'tooltip-left'
const coords = this.getPosition(el)
this.setTooltipPosition({
top: coords.top,
right: document.documentElement.offsetWidth - coords.left + 11,
})
},
closeTooltip: function (id) {
// Clear timetout even if a new tooltip has been added
// in the meantime. Eg. after a mouseout from the anchor.
window.clearTimeout(id)
if (id && id !== this.TOOLTIP_ID) return
this._tooltip.className = ''
this._tooltip.innerHTML = ''
this.setTooltipPosition({})
L.DomUtil.removeClass(this.parent, 'umap-tooltip')
},
getPosition: function (el) {
return el.getBoundingClientRect()
},
setTooltipPosition: function (coords) {
if (coords.left) this._tooltip.style.left = `${coords.left}px`
else this._tooltip.style.left = 'initial'
if (coords.right) this._tooltip.style.right = `${coords.right}px`
else this._tooltip.style.right = 'initial'
if (coords.top) this._tooltip.style.top = `${coords.top}px`
else this._tooltip.style.top = 'initial'
if (coords.bottom) this._tooltip.style.bottom = `${coords.bottom}px`
else this._tooltip.style.bottom = 'initial'
},
getDocHeight: function () {
const D = document
return Math.max(
D.body.scrollHeight,
D.documentElement.scrollHeight,
D.body.offsetHeight,
D.documentElement.offsetHeight,
D.body.clientHeight,
D.documentElement.clientHeight
)
},
})

View file

@ -30,4 +30,5 @@
<link rel="stylesheet" href="{% static 'umap/map.css' %}" />
<link rel="stylesheet" href="{% static 'umap/css/panel.css' %}" />
<link rel="stylesheet" href="{% static 'umap/css/alert.css' %}" />
<link rel="stylesheet" href="{% static 'umap/css/tooltip.css' %}" />
<link rel="stylesheet" href="{% static 'umap/theme.css' %}" />

View file

@ -60,5 +60,4 @@
<script src="{% static 'umap/js/umap.importer.js' %}" defer></script>
<script src="{% static 'umap/js/umap.share.js' %}" defer></script>
<script src="{% static 'umap/js/umap.js' %}" defer></script>
<script src="{% static 'umap/js/umap.ui.js' %}" defer></script>
<script src="{% static 'umap/js/components/fragment.js' %}" defer></script>