293 lines
9.9 KiB
JavaScript
293 lines
9.9 KiB
JavaScript
export default class DWindow extends EventTarget {
|
||
static allWindows = []; // açık pencereler
|
||
static zCounter = 1; // global sayaç
|
||
static normalizeThreshold = 9999; // yeniden sıfırlama eşiği
|
||
/** @type {JQuery<HTMLElement>} */ panel = null;
|
||
/** @type {JQuery<HTMLElement>} */ title = null;
|
||
/** @type {JQuery<HTMLElement>} */ content = null;
|
||
/** @type {JQuery<HTMLElement>} */ headtext = null;
|
||
|
||
constructor() {
|
||
super();
|
||
this.initpanel();
|
||
this.enableFocus();
|
||
DWindow.allWindows.push(this);
|
||
this.bringToFront();
|
||
requestAnimationFrame(()=>{
|
||
this.enableDragging();
|
||
this.enableResize();
|
||
})
|
||
}
|
||
activeDragging = true;
|
||
activeResizing = true;
|
||
|
||
initpanel() {
|
||
this.panel = $(`<div></div>`).css({
|
||
width: 450,
|
||
//height: 500,
|
||
position: "fixed",
|
||
left: (Math.random() * 300 | 0) + 100,
|
||
top: (Math.random() * 100 | 0) + 100,
|
||
boxShadow: "black 0px 0px 20px -10px",
|
||
borderRadius: "10px",
|
||
backgroundColor: "#3333335b",
|
||
backdropFilter: "blur(3px)",
|
||
border: "solid 1px #a2a2a2",
|
||
display: "flex",
|
||
flexDirection: "column",
|
||
outlineOffset: "-5px",
|
||
//overflow: "hidden",
|
||
userSelect: "none",
|
||
minWidth: "max-content",
|
||
minHeight: "max-content"
|
||
});
|
||
$("body").append(this.panel);
|
||
|
||
this.title = $(`<div></div>`).css({
|
||
display: "flex",
|
||
flex: "0 0 auto",
|
||
flexDirection: "row",
|
||
lineHeight: "2em",
|
||
backgroundColor: "#333333",
|
||
color: "white",
|
||
paddingLeft: "10px",
|
||
cursor: "move",
|
||
borderTopLeftRadius: "10px",
|
||
borderTopRightRadius: "10px",
|
||
});
|
||
|
||
this.content = $(`<div></div>`).css({
|
||
flex: "1 1 auto",
|
||
overflow: "auto",
|
||
borderBottomRightRadius: "10px",
|
||
borderBottomLeftRadius: "10px",
|
||
padding: "20px"
|
||
});
|
||
|
||
this.panel.append(this.title, this.content);
|
||
this.initTitle();
|
||
}
|
||
|
||
initTitle() {
|
||
this.headtext = $("<div>Başlıksız pencere</div>");
|
||
const divider = $("<div style='flex:1 1 auto'></div>");
|
||
this.exitbtn = $("<div><span class='btn btn-sm material-symbols-outlined text-white'>close</span></div>");
|
||
this.exitbtn.on('click',()=>{
|
||
this.dispatchEvent(new Event("close"));
|
||
})
|
||
this.title.append(
|
||
this.headtext,
|
||
divider,
|
||
this.exitbtn
|
||
);
|
||
}
|
||
|
||
enableDragging() {
|
||
let isDragging = false;
|
||
let startX, startY, startLeft, startTop;
|
||
|
||
this.title.on("mousedown", (e) => {
|
||
if(this.activeDragging == false){
|
||
return;
|
||
}
|
||
let isInput = $(e.target).closest("button, input, select, textarea,.btn");
|
||
if (isInput.length) return;
|
||
e.preventDefault();
|
||
isDragging = true;
|
||
startX = e.pageX;
|
||
startY = e.pageY;
|
||
startLeft = parseFloat(this.panel.css("left"));
|
||
startTop = parseFloat(this.panel.css("top"));
|
||
$("body").css("user-select", "none");
|
||
this.dispatchEvent(new Event("dragging"));
|
||
this.panel.css("box-shadow","black 0px 0px 40px -20px");
|
||
this.panel.css("backdrop-filter","blur(10px)");
|
||
});
|
||
|
||
$(document).on("mousemove", (e) => {
|
||
if (!isDragging) return;
|
||
const dx = e.pageX - startX;
|
||
const dy = e.pageY - startY;
|
||
|
||
this.panel.css({
|
||
left: startLeft + dx,
|
||
top: startTop + dy,
|
||
});
|
||
});
|
||
|
||
$(document).on("mouseup", () => {
|
||
if (isDragging) {
|
||
isDragging = false;
|
||
this.panel.css("box-shadow","black 0px 0px 20px -10px");
|
||
this.panel.css("backdrop-filter","blur(3px)");
|
||
$("body").css("user-select", "auto");
|
||
this.dispatchEvent(new Event("draggingend"));
|
||
}
|
||
});
|
||
}
|
||
enableResize() {
|
||
const offset = 5; // panelin dışından 5px alan
|
||
let resizing = false;
|
||
let resizeDir = "";
|
||
let startX, startY, startW, startH, startL, startT;
|
||
const minW = 200, minH = 150;
|
||
|
||
// overlay divleri oluştur
|
||
const handles = {};
|
||
const names = ["n","s","e","w","ne","nw","se","sw"];
|
||
names.forEach(n => {
|
||
handles[n] = $('<div></div>').css({
|
||
position: "absolute",
|
||
zIndex: 1000,
|
||
background: "transparent",
|
||
cursor: n + "-resize",
|
||
transition: "all 0.5s all",
|
||
outlineOffset: "3px"
|
||
}).appendTo(this.panel);
|
||
});
|
||
|
||
// boyut ve pozisyonlarını ayarla
|
||
const updateHandles = () => {
|
||
const w = this.panel.outerWidth();
|
||
const h = this.panel.outerHeight();
|
||
// kenarlar
|
||
handles.n.css({ top: -offset, left: 0, width: w, height: offset*2 });
|
||
handles.s.css({ bottom: -offset, left: 0, width: w, height: offset*2 });
|
||
handles.w.css({ top: 0, left: -offset, width: offset*2, height: h });
|
||
handles.e.css({ top: 0, right: -offset, width: offset*2, height: h });
|
||
// köşeler
|
||
handles.nw.css({ top: -offset, left: -offset, width: offset*2, height: offset*2 });
|
||
handles.ne.css({ top: -offset, right: -offset, width: offset*2, height: offset*2 });
|
||
handles.sw.css({ bottom: -offset, left: -offset, width: offset*2, height: offset*2 });
|
||
handles.se.css({ bottom: -offset, right: -offset, width: offset*2, height: offset*2 });
|
||
};
|
||
updateHandles();
|
||
|
||
$(window).on("resize", updateHandles);
|
||
|
||
let activeDir = null;
|
||
|
||
// resize eventleri
|
||
names.forEach(dir => {
|
||
handles[dir].on("mousedown", (e) => {
|
||
if(this.activeResizing == false){
|
||
return;
|
||
}
|
||
activeDir = e.target;
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
resizing = true;
|
||
resizeDir = dir;
|
||
startX = e.pageX;
|
||
startY = e.pageY;
|
||
startW = this.panel.outerWidth();
|
||
startH = this.panel.outerHeight();
|
||
startL = parseFloat(this.panel.css("left"));
|
||
startT = parseFloat(this.panel.css("top"));
|
||
this.dispatchEvent(new Event("resizing"));
|
||
$("body").css("user-select","none");
|
||
});
|
||
});
|
||
|
||
$(document).on("mousemove", (e) => {
|
||
if (!resizing) return;
|
||
const dx = e.pageX - startX;
|
||
const dy = e.pageY - startY;
|
||
let newW = startW;
|
||
let newH = startH;
|
||
let newL = startL;
|
||
let newT = startT;
|
||
|
||
if (resizeDir.includes("e")) newW = Math.max(minW, startW + dx);
|
||
if (resizeDir.includes("w")) { newW = Math.max(minW, startW - dx); newL = startL + (startW - newW); }
|
||
if (resizeDir.includes("s")) newH = Math.max(minH, startH + dy);
|
||
if (resizeDir.includes("n")) { newH = Math.max(minH, startH - dy); newT = startT + (startH - newH); }
|
||
|
||
this.panel.css({ width: newW, height: newH, left: newL, top: newT });
|
||
updateHandles();
|
||
$(activeDir).css("outline", "solid 2px #00ff00");
|
||
});
|
||
|
||
$(document).on("mouseup", () => {
|
||
if (resizing) {
|
||
resizing = false;
|
||
$("body").css("user-select","auto");
|
||
$(activeDir).css("outline", "solid 0px #00ff00");
|
||
this.dispatchEvent(new Event("resizingend"));
|
||
}
|
||
});
|
||
}
|
||
enableFocus() {
|
||
this.panel.on("mousedown", () => {
|
||
this.bringToFront();
|
||
});
|
||
}
|
||
|
||
bringToFront() {
|
||
if (DWindow.zCounter > DWindow.normalizeThreshold) {
|
||
DWindow.normalizeZ();
|
||
}
|
||
DWindow.zCounter++;
|
||
this.panel.css("z-index", DWindow.zCounter);
|
||
}
|
||
showing = true;
|
||
show(){
|
||
this.dispatchEvent(new Event("show"));
|
||
this.panel.show();
|
||
this.showing = true;
|
||
}
|
||
hide(){
|
||
this.dispatchEvent(new Event("hide"));
|
||
this.panel.hide();
|
||
this.showing = false;
|
||
}
|
||
toggle(){
|
||
this.showing ? this.hide() : this.show();
|
||
}
|
||
exit(){
|
||
this.dispatchEvent(new Event("exit"));
|
||
this.panel.remove();
|
||
}
|
||
/** @type {DWindow} */
|
||
parent = null;
|
||
/** @param {DWindow} parent */
|
||
enableDialog(parent){
|
||
this.parent = parent;
|
||
this.parent.activeDragging = false;
|
||
this.parent.activeResizing = false;
|
||
this.parent.panel.css('pointer-events',"none");
|
||
this.parent.panel.css('filter',"grayscale(1)");
|
||
|
||
let [{
|
||
left: parentL,
|
||
top: parentT,
|
||
width: parentW,
|
||
height: parentH
|
||
}] = this.parent.panel[0].getClientRects();
|
||
|
||
let [{
|
||
width: childW,
|
||
height: childH
|
||
}] = this.panel[0].getClientRects();
|
||
|
||
let newLeft = parentL + (parentW - childW) / 2;
|
||
let newTop = parentT + (parentH - childH) / 2;
|
||
debugger;
|
||
newLeft = Math.max(newLeft, 20);
|
||
newTop = Math.max(newTop, 20);
|
||
newLeft = Math.min(newLeft, screen.availWidth - 100);
|
||
newTop = Math.min(newTop, screen.availHeight - 100);
|
||
|
||
Object.assign(this.panel[0].style, {
|
||
left: `${Math.round(newLeft)}px`,
|
||
top: `${Math.round(newTop)}px`
|
||
});
|
||
}
|
||
/** @param {DWindow} parent */
|
||
disableDialog(){
|
||
this.parent.activeDragging = true;
|
||
this.parent.activeResizing = true;
|
||
this.parent.panel.css('pointer-events',"all");
|
||
this.parent.panel.css('filter',"initial");
|
||
}
|
||
} |