forked from FroSteel/Planification
v2026.5.19 — Drag-and-drop des popups épinglés
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Planification",
|
"name": "Planification",
|
||||||
"version": "2026.5.18",
|
"version": "2026.5.19",
|
||||||
"description": "Vue claire et rapide du planning des techniciens EasyVista. Regroupe interventions et réservations par tech, affiche horaires, contact, lieu, catégorie et statut en un coup d'œil.",
|
"description": "Vue claire et rapide du planning des techniciens EasyVista. Regroupe interventions et réservations par tech, affiche horaires, contact, lieu, catégorie et statut en un coup d'œil.",
|
||||||
"permissions": ["activeTab", "scripting", "storage", "tabs", "alarms"],
|
"permissions": ["activeTab", "scripting", "storage", "tabs", "alarms"],
|
||||||
"host_permissions": [
|
"host_permissions": [
|
||||||
|
|||||||
+72
-28
@@ -2590,46 +2590,39 @@ header.topbar::before {
|
|||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
v2026.5.17 : mode Minimisé (popup flottant compact, juste la ref)
|
v2026.5.17 : mode Minimisé (popup flottant compact, juste la ref)
|
||||||
v2026.5.18 : fix affichage — on masque TOUT sauf la ref et la topbar
|
v2026.5.19 : refonte — élément .pinned-popup-minref créé à la volée
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
.pinned-popup.pinned-popup-minimized {
|
.pinned-popup.pinned-popup-minimized {
|
||||||
min-width: 180px !important;
|
min-width: 180px !important;
|
||||||
max-width: 260px !important;
|
max-width: 260px !important;
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
padding-top: 28px !important;
|
min-height: 60px !important;
|
||||||
padding-bottom: 8px !important;
|
padding: 28px 10px 10px 10px !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: var(--bg-elevated) !important;
|
||||||
|
border: 1px solid var(--border) !important;
|
||||||
}
|
}
|
||||||
/* Masquer tous les descendants sauf ceux qu'on veut voir */
|
/* Masquer tous les enfants directs du popup minimisé */
|
||||||
.pinned-popup.pinned-popup-minimized * {
|
.pinned-popup.pinned-popup-minimized > *:not(.pinned-popup-topbar):not(.pinned-popup-dragbar):not(.pinned-popup-minref) {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
/* Réafficher la topbar et ses boutons */
|
/* L'élément ref dédié, centré et gros */
|
||||||
.pinned-popup.pinned-popup-minimized .pinned-popup-topbar,
|
.pinned-popup-minref {
|
||||||
.pinned-popup.pinned-popup-minimized .pinned-popup-topbar * {
|
display: block;
|
||||||
display: flex !important;
|
text-align: center;
|
||||||
}
|
padding: 6px 8px;
|
||||||
/* Réafficher la dragbar */
|
font-family: var(--mono, monospace);
|
||||||
.pinned-popup.pinned-popup-minimized .pinned-popup-dragbar {
|
font-size: 14px;
|
||||||
display: block !important;
|
font-weight: 700;
|
||||||
}
|
color: var(--text);
|
||||||
/* Réafficher la ref (peut être dans une row imbriquée) */
|
|
||||||
.pinned-popup.pinned-popup-minimized .iv-ref-header {
|
|
||||||
display: block !important;
|
|
||||||
text-align: center !important;
|
|
||||||
padding: 6px 12px !important;
|
|
||||||
grid-column: unset !important;
|
|
||||||
font-size: 14px !important;
|
|
||||||
font-weight: 700 !important;
|
|
||||||
color: var(--text) !important;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background 0.12s;
|
||||||
}
|
}
|
||||||
/* Et si la ref est dans une row grid, reshowrow pour qu'elle s'affiche */
|
.pinned-popup-minref:hover {
|
||||||
.pinned-popup.pinned-popup-minimized .intervention-v2,
|
background: var(--bg-muted);
|
||||||
.pinned-popup.pinned-popup-minimized .tt-ref-cell {
|
|
||||||
display: block !important;
|
|
||||||
grid-template: none !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
@@ -2790,3 +2783,54 @@ header.topbar::before {
|
|||||||
background: var(--bg-muted);
|
background: var(--bg-muted);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
v2026.5.19 : nouveaux éléments
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/* Bouton Actualiser (↻) dans la topbar du popup épinglé — animation spin */
|
||||||
|
.pinned-popup-refresh {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.pinned-popup-refresh.spinning {
|
||||||
|
animation: pinned-popup-refresh-spin 0.6s linear infinite;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
@keyframes pinned-popup-refresh-spin {
|
||||||
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pendant le drag d'un popup, ignorer les hover sur les cartes pour ne pas
|
||||||
|
ouvrir des tooltips parasites */
|
||||||
|
body.popup-dragging .intervention-v2,
|
||||||
|
body.popup-dragging .card {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
/* Mais garder les popups épinglés cliquables */
|
||||||
|
body.popup-dragging .pinned-popup {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pastille dock à 2 lignes : ref (gras) + date (petit) */
|
||||||
|
.pinned-popup-dock-pill {
|
||||||
|
flex-direction: column !important;
|
||||||
|
align-items: center !important;
|
||||||
|
padding: 4px 14px !important;
|
||||||
|
line-height: 1.1;
|
||||||
|
gap: 1px !important;
|
||||||
|
}
|
||||||
|
.pinned-popup-dock-pill-ref {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: var(--mono, monospace);
|
||||||
|
}
|
||||||
|
.pinned-popup-dock-pill-date {
|
||||||
|
display: block;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
opacity: 0.85;
|
||||||
|
font-family: var(--mono, monospace);
|
||||||
|
}
|
||||||
|
|||||||
@@ -6094,6 +6094,11 @@ let bulleState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function showTooltip(e, iv, rowEl) {
|
function showTooltip(e, iv, rowEl) {
|
||||||
|
// v2026.5.19 : pendant qu'un popup épinglé est en cours de drag, on ignore
|
||||||
|
// les mouseenter sur les cartes — sinon en survolant une carte on déclenche
|
||||||
|
// l'ouverture d'un nouveau tooltip par-dessus ce qu'on est en train de bouger.
|
||||||
|
if (state._popupDragging) return;
|
||||||
|
|
||||||
// v4.1.15 : si la bulle est épinglée sur une autre iv, on NE REMPLACE PAS
|
// v4.1.15 : si la bulle est épinglée sur une autre iv, on NE REMPLACE PAS
|
||||||
// son contenu (l'user veut garder la fiche épinglée même en survolant
|
// son contenu (l'user veut garder la fiche épinglée même en survolant
|
||||||
// d'autres cartes).
|
// d'autres cartes).
|
||||||
@@ -6485,6 +6490,9 @@ function pinTooltip() {
|
|||||||
popup.dataset.ref = iv.ref || "";
|
popup.dataset.ref = iv.ref || "";
|
||||||
popup.dataset.colorKey = (typeof deriveColorKey === "function" ? deriveColorKey(iv) : "autre") || "autre";
|
popup.dataset.colorKey = (typeof deriveColorKey === "function" ? deriveColorKey(iv) : "autre") || "autre";
|
||||||
|
|
||||||
|
// v2026.5.19 : mémoriser aussi la date pour l'afficher sur la pastille dock
|
||||||
|
popup.dataset.originDate = state.currentDate || "";
|
||||||
|
|
||||||
// v2026.5.17 : masquer l'icône 📌 du contenu cloné (redondante car le
|
// v2026.5.17 : masquer l'icône 📌 du contenu cloné (redondante car le
|
||||||
// popup a sa propre topbar avec le bouton "désépingler" 📍 explicite)
|
// popup a sa propre topbar avec le bouton "désépingler" 📍 explicite)
|
||||||
const oldPin = popup.querySelector('.tooltip-pinbtn[data-action="pin"]');
|
const oldPin = popup.querySelector('.tooltip-pinbtn[data-action="pin"]');
|
||||||
@@ -6522,6 +6530,26 @@ function pinTooltip() {
|
|||||||
});
|
});
|
||||||
topbar.appendChild(minBtn);
|
topbar.appendChild(minBtn);
|
||||||
|
|
||||||
|
// v2026.5.19 : Bouton Actualiser (icône ↻)
|
||||||
|
// Re-fetch la fiche de l'intervention pour mettre à jour les infos (statut,
|
||||||
|
// commentaires, action text) sans recharger le planning entier.
|
||||||
|
const refreshBtn = document.createElement("button");
|
||||||
|
refreshBtn.type = "button";
|
||||||
|
refreshBtn.className = "pinned-popup-btn pinned-popup-refresh";
|
||||||
|
refreshBtn.innerHTML = "↻";
|
||||||
|
refreshBtn.title = "Actualiser les informations de cette intervention";
|
||||||
|
refreshBtn.addEventListener("click", async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (refreshBtn.classList.contains("spinning")) return;
|
||||||
|
refreshBtn.classList.add("spinning");
|
||||||
|
try {
|
||||||
|
await _refreshPinnedPopupIv(popup, iv);
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => refreshBtn.classList.remove("spinning"), 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
topbar.appendChild(refreshBtn);
|
||||||
|
|
||||||
// Bouton Désépingler (icône épingle plantée)
|
// Bouton Désépingler (icône épingle plantée)
|
||||||
const unpinBtn = document.createElement("button");
|
const unpinBtn = document.createElement("button");
|
||||||
unpinBtn.type = "button";
|
unpinBtn.type = "button";
|
||||||
@@ -6614,6 +6642,44 @@ function _closePinnedPopup(el) {
|
|||||||
el.remove();
|
el.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v2026.5.19 : re-fetch les infos d'une intervention et met à jour le contenu
|
||||||
|
* du popup épinglé correspondant. Utilise fetchAndUpdateIntervention qui fait
|
||||||
|
* xhr2 + fiche, puis régénère le HTML du tooltip avec buildTooltipHTML.
|
||||||
|
*/
|
||||||
|
async function _refreshPinnedPopupIv(popup, iv) {
|
||||||
|
if (!popup || !iv) return;
|
||||||
|
try {
|
||||||
|
// Forcer le refetch : on invalide les flags qui disent "déjà fetché"
|
||||||
|
iv.xhr2Fetched = false;
|
||||||
|
iv.xhr2Fetching = false;
|
||||||
|
iv.ficheFetched = false;
|
||||||
|
iv.ficheFetching = false;
|
||||||
|
|
||||||
|
// Token de refresh actuel (pour que fetchAndUpdateIntervention ne soit
|
||||||
|
// pas abortée par les checks isRefreshAborted)
|
||||||
|
const token = (typeof currentRefreshToken !== "undefined") ? currentRefreshToken : 0;
|
||||||
|
|
||||||
|
await fetchAndUpdateIntervention(iv, token);
|
||||||
|
|
||||||
|
// Régénérer le HTML du tooltip avec les nouvelles infos.
|
||||||
|
// On doit réinjecter juste le contenu, en gardant la topbar et la dragbar
|
||||||
|
// (qui ne sont PAS dans le tooltip source, elles sont propres au popup).
|
||||||
|
const topbar = popup.querySelector(".pinned-popup-topbar");
|
||||||
|
const dragbar = popup.querySelector(".pinned-popup-dragbar");
|
||||||
|
const newHtml = buildTooltipHTML(iv);
|
||||||
|
popup.innerHTML = newHtml;
|
||||||
|
// Virer aussi la vieille icône 📌 si elle revient dans le rebuild
|
||||||
|
const oldPin = popup.querySelector('.tooltip-pinbtn[data-action="pin"]');
|
||||||
|
if (oldPin) oldPin.remove();
|
||||||
|
// Remettre topbar et dragbar
|
||||||
|
if (topbar) popup.appendChild(topbar);
|
||||||
|
if (dragbar) popup.appendChild(dragbar);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("[refresh-popup]", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Désépinglage "mou" : la popup n'est plus considérée épinglée (elle n'est
|
* Désépinglage "mou" : la popup n'est plus considérée épinglée (elle n'est
|
||||||
* plus dans pinnedPopups, donc le comptage pour Ctrl×2 etc. ignore) mais on
|
* plus dans pinnedPopups, donc le comptage pour Ctrl×2 etc. ignore) mais on
|
||||||
@@ -6686,12 +6752,16 @@ function _softUnpinPopup(el) {
|
|||||||
/**
|
/**
|
||||||
* Passe un popup épinglé en mode Minimisé : on ne montre plus que la ref,
|
* Passe un popup épinglé en mode Minimisé : on ne montre plus que la ref,
|
||||||
* dans un petit cadre flottant toujours drag-able.
|
* dans un petit cadre flottant toujours drag-able.
|
||||||
|
*
|
||||||
|
* v2026.5.19 : au lieu de masquer tout le contenu via CSS et tenter de
|
||||||
|
* réafficher la ref (fragile), on crée un élément dédié `.pinned-popup-minref`
|
||||||
|
* qui contient juste la ref + la date. Cet élément est ajouté/retiré au besoin.
|
||||||
*/
|
*/
|
||||||
function _minimizePinnedPopup(popup) {
|
function _minimizePinnedPopup(popup) {
|
||||||
if (!popup) return;
|
if (!popup) return;
|
||||||
popup.classList.add("pinned-popup-minimized");
|
popup.classList.add("pinned-popup-minimized");
|
||||||
|
|
||||||
// Adapter les boutons topbar : [_] devient [⬆] (agrandir)
|
// Adapter les boutons topbar : [▭] devient [⬆] (agrandir)
|
||||||
const minBtn = popup.querySelector(".pinned-popup-minimize");
|
const minBtn = popup.querySelector(".pinned-popup-minimize");
|
||||||
if (minBtn) {
|
if (minBtn) {
|
||||||
minBtn.innerHTML = "⬆";
|
minBtn.innerHTML = "⬆";
|
||||||
@@ -6705,20 +6775,22 @@ function _minimizePinnedPopup(popup) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clic sur la ref (dans iv-ref-header) = agrandir aussi
|
// Créer un élément dédié pour afficher la ref en mode minimisé
|
||||||
const refEl = popup.querySelector(".iv-ref-header");
|
let minRef = popup.querySelector(".pinned-popup-minref");
|
||||||
if (refEl) {
|
if (!minRef) {
|
||||||
refEl.style.cursor = "pointer";
|
minRef = document.createElement("div");
|
||||||
refEl.title = "Cliquer pour agrandir";
|
minRef.className = "pinned-popup-minref";
|
||||||
refEl.addEventListener("click", _onMinimizedRefClick);
|
const refText = popup.dataset.ref || "(sans ref)";
|
||||||
|
minRef.textContent = refText;
|
||||||
|
minRef.title = "Cliquer pour agrandir";
|
||||||
|
minRef.addEventListener("click", (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
_expandPinnedPopup(popup);
|
||||||
|
});
|
||||||
|
popup.appendChild(minRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onMinimizedRefClick(e) {
|
|
||||||
const popup = e.currentTarget.closest(".pinned-popup");
|
|
||||||
if (popup) _expandPinnedPopup(popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repasse un popup minimisé en mode Normal (complet).
|
* Repasse un popup minimisé en mode Normal (complet).
|
||||||
*/
|
*/
|
||||||
@@ -6739,13 +6811,9 @@ function _expandPinnedPopup(popup) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retirer listener du clic-agrandir sur la ref
|
// Retirer l'élément ref dédié (s'il existe)
|
||||||
const refEl = popup.querySelector(".iv-ref-header");
|
const minRef = popup.querySelector(".pinned-popup-minref");
|
||||||
if (refEl) {
|
if (minRef) minRef.remove();
|
||||||
refEl.style.cursor = "";
|
|
||||||
refEl.title = "";
|
|
||||||
refEl.removeEventListener("click", _onMinimizedRefClick);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6778,12 +6846,26 @@ function _reducePinnedPopup(popup) {
|
|||||||
// Créer la pastille dock
|
// Créer la pastille dock
|
||||||
// v2026.5.18 : le fond de la pastille prend la couleur de catégorie
|
// v2026.5.18 : le fond de la pastille prend la couleur de catégorie
|
||||||
// (via la classe color-XXX déjà utilisée ailleurs dans le CSS)
|
// (via la classe color-XXX déjà utilisée ailleurs dans le CSS)
|
||||||
|
// v2026.5.19 : pastille à 2 lignes — ref (gras) + date origine (petit)
|
||||||
const pill = document.createElement("button");
|
const pill = document.createElement("button");
|
||||||
pill.type = "button";
|
pill.type = "button";
|
||||||
pill.className = "pinned-popup-dock-pill color-" + colorKey;
|
pill.className = "pinned-popup-dock-pill color-" + colorKey;
|
||||||
pill.textContent = label;
|
|
||||||
pill.title = "Cliquer pour agrandir";
|
pill.title = "Cliquer pour agrandir";
|
||||||
|
|
||||||
|
const pillRef = document.createElement("span");
|
||||||
|
pillRef.className = "pinned-popup-dock-pill-ref";
|
||||||
|
pillRef.textContent = label;
|
||||||
|
pill.appendChild(pillRef);
|
||||||
|
|
||||||
|
// Date d'origine (ex: "21.04")
|
||||||
|
const originDate = popup.dataset.originDate || "";
|
||||||
|
if (originDate) {
|
||||||
|
const pillDate = document.createElement("span");
|
||||||
|
pillDate.className = "pinned-popup-dock-pill-date";
|
||||||
|
pillDate.textContent = _formatDateShort(originDate);
|
||||||
|
pill.appendChild(pillDate);
|
||||||
|
}
|
||||||
|
|
||||||
// Mémoriser la position/taille du popup avant de le masquer
|
// Mémoriser la position/taille du popup avant de le masquer
|
||||||
const rect = popup.getBoundingClientRect();
|
const rect = popup.getBoundingClientRect();
|
||||||
popup.dataset.prevLeft = popup.style.left || (rect.left + "px");
|
popup.dataset.prevLeft = popup.style.left || (rect.left + "px");
|
||||||
@@ -6811,7 +6893,7 @@ function _reducePinnedPopup(popup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* v2026.5.18 : réduit TOUS les popups épinglés actuellement ouverts (en mode
|
* v2026.5.19 : réduit TOUS les popups épinglés actuellement ouverts (en mode
|
||||||
* normal ou minimisé) dans la taskbar du bas. Appelé au changement de date.
|
* normal ou minimisé) dans la taskbar du bas. Appelé au changement de date.
|
||||||
*/
|
*/
|
||||||
function _reduceAllPinnedPopups() {
|
function _reduceAllPinnedPopups() {
|
||||||
@@ -6821,6 +6903,16 @@ function _reduceAllPinnedPopups() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v2026.5.19 : ISO date (YYYY-MM-DD) → format court "DD.MM" pour le dock.
|
||||||
|
*/
|
||||||
|
function _formatDateShort(iso) {
|
||||||
|
if (!iso) return "";
|
||||||
|
const m = String(iso).match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||||
|
if (!m) return iso;
|
||||||
|
return `${m[3]}.${m[2]}`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* v2026.5.18 : ajoute (ou met à jour) le bouton "Fermer tous" dans le dock
|
* v2026.5.18 : ajoute (ou met à jour) le bouton "Fermer tous" dans le dock
|
||||||
* quand au moins 2 popups épinglés existent (réduits OU affichés).
|
* quand au moins 2 popups épinglés existent (réduits OU affichés).
|
||||||
@@ -6997,6 +7089,11 @@ function _attachPopupDragHandler(popup, dragbar) {
|
|||||||
popup.classList.remove("dragging");
|
popup.classList.remove("dragging");
|
||||||
document.removeEventListener("mousemove", onMouseMove);
|
document.removeEventListener("mousemove", onMouseMove);
|
||||||
document.removeEventListener("mouseup", onMouseUp);
|
document.removeEventListener("mouseup", onMouseUp);
|
||||||
|
// v2026.5.19 : retirer la classe body et le flag global après un petit
|
||||||
|
// délai pour laisser le temps au mouseleave de la carte de se propager
|
||||||
|
// sans déclencher de tooltip parasite.
|
||||||
|
document.body.classList.remove("popup-dragging");
|
||||||
|
setTimeout(() => { state._popupDragging = false; }, 50);
|
||||||
|
|
||||||
// Mettre à jour le rect mémorisé pour la détection de chevauchement
|
// Mettre à jour le rect mémorisé pour la détection de chevauchement
|
||||||
const entry = pinnedPopups.find(p => p.el === popup);
|
const entry = pinnedPopups.find(p => p.el === popup);
|
||||||
@@ -7019,6 +7116,11 @@ function _attachPopupDragHandler(popup, dragbar) {
|
|||||||
startLeft = parseFloat(popup.style.left) || 0;
|
startLeft = parseFloat(popup.style.left) || 0;
|
||||||
startTop = parseFloat(popup.style.top) || 0;
|
startTop = parseFloat(popup.style.top) || 0;
|
||||||
popup.classList.add("dragging");
|
popup.classList.add("dragging");
|
||||||
|
// v2026.5.19 : flag global pour que showTooltip ignore les mouseenter
|
||||||
|
// pendant le drag. Ajout d'une classe sur <body> qui désactive les
|
||||||
|
// pointer-events sur les cartes.
|
||||||
|
state._popupDragging = true;
|
||||||
|
document.body.classList.add("popup-dragging");
|
||||||
document.addEventListener("mousemove", onMouseMove);
|
document.addEventListener("mousemove", onMouseMove);
|
||||||
document.addEventListener("mouseup", onMouseUp);
|
document.addEventListener("mouseup", onMouseUp);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user