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");
 | 
						||
    }
 | 
						||
} |