235 lines
6.1 KiB
HTML
235 lines
6.1 KiB
HTML
|
|
|
|
|
|
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<title>Ma Page</title>
|
|
</head>
|
|
<body>
|
|
<h1>Titre de la page</h1>
|
|
|
|
<style>
|
|
.dialog {
|
|
position: absolute;
|
|
background: #f9f9f9;
|
|
border: 1px solid #999;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 10px rgba(0,0,0,0.2);
|
|
overflow: hidden;
|
|
resize: none;
|
|
z-index: 10;
|
|
}
|
|
|
|
.dialog-bar {
|
|
height: 30px;
|
|
background: #2979ff;
|
|
color: white;
|
|
line-height: 30px;
|
|
padding: 0 8px;
|
|
font-weight: bold;
|
|
cursor: move;
|
|
user-select: none;
|
|
position: relative;
|
|
}
|
|
|
|
.dialog-close {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
width: 30px;
|
|
height: 30px;
|
|
line-height: 30px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
font-size: 20px;
|
|
}
|
|
.dialog-close:hover {
|
|
background: rgba(255,255,255,0.2);
|
|
}
|
|
|
|
.dialog-content {
|
|
width: 100%;
|
|
height: calc(100% - 30px);
|
|
overflow: auto;
|
|
padding: 8px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* Resizers */
|
|
.resizer {
|
|
position: absolute;
|
|
background: transparent;
|
|
}
|
|
.resizer-n, .resizer-s {
|
|
height: 6px; width: 100%; cursor: ns-resize;
|
|
}
|
|
.resizer-e, .resizer-w {
|
|
width: 6px; height: 100%; cursor: ew-resize;
|
|
}
|
|
.resizer-n { top: -3px; left: 0; }
|
|
.resizer-s { bottom: -3px; left: 0; }
|
|
.resizer-e { right: -3px; top: 0; }
|
|
.resizer-w { left: -3px; top: 0; }
|
|
|
|
/* corners */
|
|
.resizer-ne, .resizer-nw, .resizer-se, .resizer-sw {
|
|
width: 10px; height: 10px;
|
|
position: absolute;
|
|
background: transparent;
|
|
}
|
|
.resizer-ne { top: -3px; right: -3px; cursor: nesw-resize; }
|
|
.resizer-nw { top: -3px; left: -3px; cursor: nwse-resize; }
|
|
.resizer-se { bottom: -3px; right: -3px; cursor: nwse-resize; }
|
|
.resizer-sw { bottom: -3px; left: -3px; cursor: nesw-resize; }
|
|
|
|
</style>
|
|
<script>
|
|
|
|
|
|
class Dialog {
|
|
constructor(box, title, content) {
|
|
this._id = 'dialog_' + Date.now();
|
|
this._box = box;
|
|
this._title = title;
|
|
this._content = content;
|
|
|
|
this.createDialog();
|
|
}
|
|
|
|
createDialog() {
|
|
// --- conteneur principal ---
|
|
this.el = document.createElement('div');
|
|
this.el.className = 'dialog';
|
|
Object.assign(this.el.style, {
|
|
top: this._box.top + 'px',
|
|
left: this._box.left + 'px',
|
|
width: this._box.width + 'px',
|
|
height: this._box.height + 'px'
|
|
});
|
|
|
|
// --- barre de titre ---
|
|
const bar = document.createElement('div');
|
|
bar.className = 'dialog-bar';
|
|
bar.textContent = this._title;
|
|
|
|
const close = document.createElement('span');
|
|
close.className = 'dialog-close';
|
|
close.innerHTML = '×';
|
|
bar.appendChild(close);
|
|
this.el.appendChild(bar);
|
|
|
|
// --- conteneur contenu ---
|
|
const container = document.createElement('div');
|
|
container.className = 'dialog-content';
|
|
if (typeof this._content === 'string')
|
|
container.innerHTML = this._content;
|
|
else
|
|
container.appendChild(this._content);
|
|
this.el.appendChild(container);
|
|
|
|
document.body.appendChild(this.el);
|
|
|
|
// --- interactions ---
|
|
this.makeDraggable(bar);
|
|
this.makeResizable();
|
|
close.addEventListener('click', () => this.close());
|
|
}
|
|
|
|
makeDraggable(bar) {
|
|
let isDragging = false;
|
|
let offsetX, offsetY;
|
|
|
|
bar.addEventListener('mousedown', (e) => {
|
|
isDragging = true;
|
|
const rect = this.el.getBoundingClientRect();
|
|
offsetX = e.clientX - rect.left;
|
|
offsetY = e.clientY - rect.top;
|
|
document.body.style.userSelect = 'none';
|
|
});
|
|
|
|
document.addEventListener('mouseup', () => {
|
|
isDragging = false;
|
|
document.body.style.userSelect = '';
|
|
});
|
|
|
|
document.addEventListener('mousemove', (e) => {
|
|
if (!isDragging) return;
|
|
this.el.style.left = (e.clientX - offsetX) + 'px';
|
|
this.el.style.top = (e.clientY - offsetY) + 'px';
|
|
});
|
|
}
|
|
|
|
makeResizable() {
|
|
const sides = ['n', 'e', 's', 'w', 'ne', 'nw', 'se', 'sw'];
|
|
sides.forEach(side => {
|
|
const r = document.createElement('div');
|
|
r.className = 'resizer resizer-' + side;
|
|
this.el.appendChild(r);
|
|
r.addEventListener('mousedown', (e) => this.startResize(e, side));
|
|
});
|
|
}
|
|
|
|
startResize(e, side) {
|
|
e.preventDefault();
|
|
const startX = e.clientX;
|
|
const startY = e.clientY;
|
|
const rect = this.el.getBoundingClientRect();
|
|
|
|
const startWidth = rect.width;
|
|
const startHeight = rect.height;
|
|
const startLeft = rect.left;
|
|
const startTop = rect.top;
|
|
|
|
const onMove = (ev) => {
|
|
const dx = ev.clientX - startX;
|
|
const dy = ev.clientY - startY;
|
|
|
|
if (side.includes('e'))
|
|
this.el.style.width = (startWidth + dx) + 'px';
|
|
if (side.includes('s'))
|
|
this.el.style.height = (startHeight + dy) + 'px';
|
|
if (side.includes('w')) {
|
|
this.el.style.width = (startWidth - dx) + 'px';
|
|
this.el.style.left = (startLeft + dx) + 'px';
|
|
}
|
|
if (side.includes('n')) {
|
|
this.el.style.height = (startHeight - dy) + 'px';
|
|
this.el.style.top = (startTop + dy) + 'px';
|
|
}
|
|
};
|
|
|
|
const onUp = () => {
|
|
document.removeEventListener('mousemove', onMove);
|
|
document.removeEventListener('mouseup', onUp);
|
|
};
|
|
|
|
document.addEventListener('mousemove', onMove);
|
|
document.addEventListener('mouseup', onUp);
|
|
}
|
|
|
|
close() {
|
|
if (this.el && this.el.parentElement)
|
|
this.el.parentElement.removeChild(this.el);
|
|
}
|
|
} ;
|
|
|
|
// --- helper de création ---
|
|
function createDialog(box, title, content) {
|
|
return new Dialog(box, title, content);
|
|
}
|
|
|
|
|
|
function lancerAuDemarrage() {
|
|
createDialog({ top: 100, left: 100, width: 400, height: 300 }, "Exemple Texte",
|
|
"<p>Bonjour 👋</p><p>Tu peux redimensionner et déplacer cette fenêtre.</p>"
|
|
);
|
|
}
|
|
|
|
// Appel direct de la fonction
|
|
lancerAuDemarrage();
|
|
</script>
|
|
</body>
|
|
</html> |