Beta Version

Description

This script creates a DHTML popup window that can be moved around the screen, resized, and closed. Multiple windows may also be used, and the layer presidence will be set by the last window to have been clicked on. It will also degrade well, by continuing to work in older browsers, and browsers that do not have JavaScript enabled. One day, I'll document it better, but until then, just look at what I've done, and do the same thing. ;)

Demonstration

Open Web Dev FAQs -- possibly opens below the visible screen (see known bugs)
Open W3C

Known Bugs

The popup will "stick" to the cursor when you try to move it in Opera 7, and there is no way to close it. In other browsers, a centered popup will open in the middle of the document, rather than the visible window.

Implementation

Here is the code used to open the popup in the two example above:
<a href="http://www.webdevfaqs.com" onclick="openpopup(this.href,'','','','','center'); return false;">Open Web Dev FAQs</a>
<a href="http://www.w3c.org" onclick="openpopup(this.href,'600','400','100','100',''); return false;">Open W3C</a>

This part: openpopup(this.href,'600','400','100','100','center'); works in this order:

The link to open (current links href)
The width
The height
The position from the left
The position from the top
Center the window

Code

<script type="text/javascript">

/*#####################################################
# This script is Copyright 2003, Infinity Web Design  #
# Written by Ryan Brill - ryan@infinitypages.com      #
# All Rights Reserved - Do not remove this notice     #
#####################################################*/

x = 50; //z-index var
mainwin = new Array(); //array for popups

function beginDrag(elementToDrag, event) {
	
	for (i=0; i<mainwin.length; i++) { // loop through the windows
		if (x<mainwin[i].style.zIndex) { //  if x is less than the current z-index of the window it is currently looping through
			x = mainwin[i].style.zIndex; // set x to the highest z-index of the windows
		}
	}
	elementToDrag.style.zIndex = x+1; // set z-index to be one more than highest z-index for windows

	elementToDrag.childNodes[1].style.display = "block";
	
	var deltaX = event.clientX - parseInt(elementToDrag.style.left);
	var deltaY = event.clientY - parseInt(elementToDrag.style.top);

	if (document.addEventListener) {	
		document.addEventListener("mousemove", moveHandler, true);
		document.addEventListener("mouseup", upHandler, true);
	}
	else if (document.attachEvent) {
		document.attachEvent("onmousemove", moveHandler);
		document.attachEvent("onmouseup", upHandler);
	}
	else {
		var oldmovehandler = document.onmousemove;
		var olduphandler = document.onmouseup;
		document.onmousemove = moveHandler;
		document.onmouseup = upHandler;
	}
	
	if (event.stopPropagation) event.stopPropagation();
	else event.cancelBubble = true;
	
	if (event.preventDefault) event.preventDefault();
	else event.returnValue = false;
	
	function moveHandler(e) {
		if (!e) e = window.event;
		
		winwidth = document.body.scrollWidth;
		winheight = document.body.scrollHeight;
		
		if (e.clientX - deltaX < 2) { //don't allow past left of screen
			leftpos = 2;
		}				
		else if (e.clientX - deltaX > winwidth - parseInt(elementToDrag.style.width)) { //don't allow past right of screen
			leftpos = winwidth - parseInt(elementToDrag.style.width) - 3;
		}
		else {
			leftpos = e.clientX - deltaX;
		}
		
		if (e.clientY - deltaY < 2) { //don't allow past top of screen
			toppos = 2;
		}
		else if (e.clientY - deltaY > winheight - parseInt(elementToDrag.style.height)) { // don't allow past bottom of screen
			toppos = winheight - parseInt(elementToDrag.style.height) - 3;
		}
		else {
			toppos = e.clientY - deltaY;
		}
		
		elementToDrag.style.left = leftpos + "px"; //set left position of div
		elementToDrag.style.top = toppos + "px"; //set top position of div
		return false;
		if (e.stopPropagation) e.stopPropagation();
		else e.cancelBubble = true;
	}

	function upHandler(e) {
		if (!e) e = window.event;
		if (document.removeEventListener) {
			document.removeEventListener ("mouseup", upHandler, true);
			document.removeEventListener ("mousemove", moveHandler, true);
		}
		else if (document.detachEvent) {
			document.detachEvent ("onmouseup", upHandler);
			document.detachEvent ("onmousemove", moveHandler);
		}
		else {
			document.onmouseup = olduphandler;
			docuemnt.onmousemove = oldmovehandler;
		}
		if (e.stopPropagation) e.stopPropagation();
		else e.cancelBubble = true;
		
		elementToDrag.childNodes[1].style.display = "none";
	}
}

function beginResize(elementToResize, event) {

	elementToResize.childNodes[1].style.display = "block";
	
	var deltaX = event.clientX - parseInt(elementToResize.style.width);
	var deltaY = event.clientY - parseInt(elementToResize.style.height);

	if (document.addEventListener) {	
		document.addEventListener("mousemove", resizeHandler, true);
		document.addEventListener("mouseup", resizeUpHandler, true);
	}
	else if (document.attachEvent) {
		document.attachEvent("onmousemove", resizeHandler);
		document.attachEvent("onmouseup", resizeUpHandler);
	}
	else {
		var oldresizehandler = document.onmousemove;
		var oldresizeuphandler = document.onmouseup;
		document.onmousemove = resizeHandler;
		document.onmouseup = resizeUpHandler;
	}
	
	if (event.stopPropagation) event.stopPropagation();
	else event.cancelBubble = true;
	
	if (event.preventDefault) event.preventDefault();
	else event.returnValue = false;

	function resizeHandler(e) {
		if (!e) e = window.event;
		
		elementToResize.style.width = (e.clientX - deltaX) + "px"; //set width of div
		elementToResize.style.height = (e.clientY - deltaY) + "px"; //set height of div
		elementToResize.childNodes[1].style.width = (e.clientX - deltaX - 2) + "px";
		elementToResize.childNodes[1].style.height = (e.clientY - deltaY - 32) + "px";
		elementToResize.childNodes[2].style.width = (e.clientX - deltaX - 2) + "px";
		elementToResize.childNodes[2].style.height = (e.clientY - deltaY - 32) + "px";
		return false;
		if (e.stopPropagation) e.stopPropagation();
		else e.cancelBubble = true;	
	}
	
	function resizeUpHandler(e) {
		if (!e) e = window.event;
		if (document.removeEventListener) {
			document.removeEventListener ("mouseup", resizeUpHandler, true);
			document.removeEventListener ("mousemove", resizeHandler, true);
		}
		else if (document.detachEvent) {
			document.detachEvent ("onmouseup", resizeUpHandler);
			document.detachEvent ("onmousemove", resizeHandler);
		}
		else {
			document.onmouseup = oldresizeuphandler;
			docuemnt.onmousemove = oldresizehandler;
		}
		if (e.stopPropagation) e.stopPropagation();
		else e.cancelBubble = true;
		
		elementToResize.childNodes[1].style.display = "none";
	}
}

function openpopup(url,winwidth,winheight,winleft,wintop,center) {

	if (document.layers) { //NN
		windowwidth = window.innerWidth; //get window width
		windowheight = window.innerHeight; //get window height
	}
	else { //IE
		windowwidth = document.body.clientWidth; //get window width
		windowheight = document.body.clientHeight; //get window height
	}

	if (winwidth == undefined || winwidth == "") {
		winwidth = "400";
	}
	if (winheight == undefined || winheight == "") {
		winheight = "300";
	}
	if (wintop == undefined || wintop == "") {
		wintop = "0";
	}
	if (winleft == undefined || winleft == "") {
		winleft = "0";
	}
	if (center == "center") {
		wintop = (windowheight/2) - (winheight/2);
		winleft = (windowwidth/2) - (winwidth/2);
	}	
	
	for (i=0; i<mainwin.length; i++) { // loop through the windows
		if (x<mainwin[i].style.zIndex) { //  if x is less than the current z-index of the window it is currently looping through
			x = mainwin[i].style.zIndex; // set x to the highest z-index of the windows
		}
	}

	mainwin[mainwin.length] = document.createElement("div");
	mainwin[mainwin.length-1].style.position = "absolute";
	mainwin[mainwin.length-1].style.top = wintop +"px";
	mainwin[mainwin.length-1].style.left = winleft +"px";
	mainwin[mainwin.length-1].style.width = winwidth +"px";
	mainwin[mainwin.length-1].style.height = winheight +"px";
	mainwin[mainwin.length-1].style.border = "1px solid";
	mainwin[mainwin.length-1].style.zIndex = x+1;
	
	document.body.appendChild(mainwin[mainwin.length-1]);
	
	mainwin[mainwin.length-1].innerHTML = ""+
	"<div style=\"background:#dddddd;\" onmousedown=\"beginDrag(this.parentNode, event);\">"+
		"<span style=\"padding-left: 5px; cursor:default; font-family: verdana; font-weight: bold;\">"+
			"<span style=\"font-size: 12px;\">"+url+""+
			"</span>"+
		"</span>"+
		"<span style=\"position: relative; top: -19px; float: right; background: transparent;\" onclick=\"closepopup(this.parentNode.parentNode);\">"+
			"<img src=\"required/close.png\" name=\"closebutton\" onmouseover=\"document.closebutton.src='required/closeon.png';\" onmouseout=\"document.closebutton.src='required/close.png';\">"+
		"</span>"+
	"</div>"+
	"<div style=\"position: absolute; top: 18px; height: "+(winheight-32)+"px; width: "+(winwidth - 2)+"px; z-index:2; background-image:url(fake.gif); display:none;\">"+
	"</div>"+
	"<iframe src=\""+url+"\" style=\"position: absolute; top: 18px; height: "+(winheight-32)+"px; width: "+(winwidth - 2)+"px; overflow:auto; z-index:1\">"+
	"</iframe>"+
	"<span style=\"position: absolute; bottom: 0px; width: 100%; background: #dddddd; color: white; font-family: arial; font-weight: bold; z-index:3;\" onmouseover=\"this.style.cursor='nw-resize';\" onmousedown=\"beginResize(this.parentNode, event);\">"+
		"<span style=\"float:right;\"><img src=\"required/resize.png\"></span>"+
	"</span>";
}

function closepopup(elementToClose) {
	mainwin.splice(elementToClose,1);
	document.body.removeChild(elementToClose);
}

</script>

Comments:

Tested in: IE6, Opera 7, NN4.7, NN7, and Mozilla 1.4.
Works or degrades well in: IE6, NN4.7, NN7, and Mozilla 1.4.
Doesn't or doesn't degrade work in: Opera 7
Comments: Works best in Mozilla, as this is the most DOM compliant browser.

Copyright© 2003, Infinity Web Design