Complete dhtml windowing-system in 600 lines (24kb)*

D

darwinist

1 Works in a browser as customisable web-interface or,
2 Use with apache to make window-based, dhtml-apps
3 Rename/retitle open windows
4 Arbitrary virtual desktop size with easy navigation (default
10000x10000)
5 Free as in freedom, and free as in free-beer (beer not included).
6 All in one html/js file at
http://darwinist.googlepages.com/webwindows.html
7 You can copy and paste this post into a new .html file and start your
own
8 Tested on firefox 1.5 and ie 6
9 Left and right window padding too fat on ie. Very hard. Please help.
*(With comments, whitespace, and api reference)

Please copy or contribute:

<!-- dhtml windowing-system-->
<html>
<title>Web Windows</title>

<body style='font-family:arial;'>

<!-- Scripts to control the desktop: -->
<script>
var CurrentObject =""; // Which object is being dragged (moved)
right now.
var AreMoving = false; // Is an object being dragged.
var AreSizing = false; // Are we sizing any objects right now
var SizingType = ""; // Which kind of sizing
var StartMouseX = 0; // Mouse x when dragging started
var StartMouseY = 0; // Mouse y when dragging started
var StartObjectX = 0; // element x when dragging started
var StartObjectY = 0; // element y when dragging started
var StartObjectHeight = 0; // element y when dragging started
var StartObjectWidth = 0; // element y when dragging started
var Windows = 0; // total windows created
var WindowsNow = 0; // Number of windows currently open
var TopZIndex = 0; // TopMostWindow

// Show debug information (9 keystrokes shorter than window.alert
and
debugon=true; // controllable with debugon flag)
function msg(text){if (debugon) window.alert(text);}

// Strip the "px" from the style values of gui objects, if it's
there, and return as number.
function pxVal(val) {
return val.substring(val.length-2)=="px" ?
val.substring(0, val.length-2) *1
: val *1;
}

// Create a new object and give it an id
function $make(type, id) {el =
document.createElement(type);el.id=id;return el;}
function $del(id){$(id).parentNode.removeChild($(id));} // remove an
item from html document.
function $text(text) { return document.createTextNode(text);} //
Make a text node

// Make an input with type, name and optional value and id (which is
the same as name if not specified
// or not used if set to false
function $input(type, name, value, id)
{
if (id == undefined) id = name; if (id == false) id = undefined;
el = $make("input", id); el.name= name; el.type= type; el.value=
value;
return el;
}

// return a default value if the desired parameter is undefined;
otherwise the parameter.
// Only works from inside functions
function IfNo(targetvar, defaultval)
{return targetvar == undefined ? defaultval : targetvar; }

// Get an object by id (22 keystrokes shorter than
document.getElementById)
function $(id){return document.getElementById(id);}

// Get some values quicker; read-only.
function Width(id){return pxVal($(id).style.width);}
function Height(id){return pxVal($(id).style.height);}
function Top(id){return pxVal($(id).style.top);}
function Left(id){return pxVal($(id).style.left);}

// Write these values more quickly:
function WidthIs(id, newwidth){$(id).style.width=newwidth;}
function HeightIs(id, newheight){$(id).style.height=newheight;}
function TopIs(id, newtop){$(id).style.top=newtop;}
function LeftIs(id, newleft){$(id).style.left=newleft;}
XIs = LeftIs; YIs = TopIs; // Some aliases

// Increase the height, width, top (y), or left (x) properties of
elements:
function AddToHeight(id, pixels) {HeightIs(id,
(Height(id)+pixels));}
function AddToWidth(id, pixels) {WidthIs(id, (Width(id)+pixels));}
function AddToX(id, pixels) {LeftIs(id, Left(id)+pixels);}
function AddToY(id, pixels) {TopIs(id, Top(id)+pixels);}
// X and Y are shorter than Left and Top, but you might forget
AddToLeft = AddToX; AddToTop = AddToY; // aliases

// Put an object in a a container object (at its end) both passed by
reference, not id
function PutIn(targetobject, newcontainer)
{newcontainer.appendChild(targetobject);}

// If we're meant to be moving a window, move it according to start
and current positions
function MoveIfMoving(e)
{
if (AreMoving)
{
NewX = StartObjectX + (e.clientX - StartMouseX);
NewY = StartObjectY + (e.clientY - StartMouseY);
if (NewX > 0) XIs(CurrentObject, NewX);
if (NewY > 0) YIs(CurrentObject, NewY);

ExtraWidth = Left(CurrentObject)+Width(CurrentObject) -
Width("desktop");
ExtraHeight = Top(CurrentObject)+Height(CurrentObject) -
Height("desktop");
if (ExtraWidth > 0) WidthIs("desktop", Width("desktop")+
(ExtraWidth));
if (ExtraHeight > 0) HeightIs("desktop", Height("desktop")+
(ExtraHeight));
$("desktopheight").value = Height("desktop");
$("desktopwidth").value = Width("desktop");
}
// Also we might be sizing instead
else if (AreSizing) SizeObject(e);
}

// executed for sizing buttons, not a low-level function.
function SizeObject(e)
{
xdiff = e.clientX - StartMouseX;
ydiff = e.clientY - StartMouseY;

if (SizingType == "out") // make window bigger, no matter what
direction you move mouse.
{
WinSize(CurrentObject, Math.abs(xdiff)+StartObjectWidth,
Math.abs(ydiff)+StartObjectHeight);
if (xdiff < 0) XIs(CurrentObject, StartObjectX + xdiff);
if (ydiff < 0) YIs(CurrentObject, StartObjectY + ydiff);
}
else if (SizingType == "in")
{
WinSize(CurrentObject, StartObjectWidth-Math.abs(xdiff),
StartObjectHeight-Math.abs(ydiff));
if (xdiff > 0) XIs(CurrentObject, StartObjectX + xdiff);
if (ydiff > 0) YIs(CurrentObject, StartObjectY + ydiff);
}
else if (SizingType == "se") // south east
WinSize(CurrentObject, StartObjectWidth + xdiff, StartObjectHeight
+ ydiff);
else if (SizingType == "nw") // north west
{
XIs(CurrentObject, StartObjectX + xdiff);
YIs(CurrentObject, StartObjectY + ydiff);
WinSize(CurrentObject, StartObjectWidth - xdiff, StartObjectHeight
- ydiff);
}
}

// Start and stop moving objects around the screen when you press or
unpress the mouse
function StopMoving() {AreMoving=false;ShowObjectFrame(); }
function StopSizing() {AreSizing=false; ShowObjectFrame();}
function ShowObjectFrame(){if ($(CurrentObject+"_iframe"))
show(CurrentObject+"_iframe");}
function SetMouseMoving(e) {StartMouseX = e.clientX; StartMouseY =
e.clientY; }
function StartMoving(ObjectID)
{
AreMoving=true;
AreSizing=false;
CatchObjectState(ObjectID);
}

// Find out about what state an object was in at start of dragging
or sizing.
function CatchObjectState(ObjectID)
{
CurrentObject = ObjectID;
StartObjectX = Left(ObjectID); StartObjectY = Top(ObjectID);
StartObjectHeight = Height(ObjectID); StartObjectWidth =
Width(ObjectID);
if ($(ObjectID+"_iframe")) hide(ObjectID+"_iframe");
}

function StartSizing(ObjectID, type)
{
CatchObjectState(ObjectID);
AreSizing=true;
SizingType = type;
AreMoving=false;
}

function hide(id) {$(id).style.display='none';}
function show(id)
{$(id).style.display='';$(id).style.zIndex=++TopZIndex;}
function toggle(id){if ($(id).style.display == "none") show(id);
else hide(id);}
function ToTop(id) {}//$(id).style.zIndex = -1;}

function WinSize(id, x, y)
{
if (x <1) x=1; if (y <1) y=1;
HeightIs(id, y);WidthIs(id, x);
HeightIs(id+"_div", y);WidthIs(id+"_div", x);
HeightIs(id+"_iframe", y);WidthIs(id+"_iframe", x);
}

function WinMove(id, x, y)
{
if (x<1) x=1; if (y<1) y=1;
// if position is further than desktop's size, increase desktop
accordingly
if (x+Width(id) > Width("desktop")) AddToWidth("desktop", ((x -
Width("desktop")) + Width(id)));
if (y+Height(id) > Height("desktop")) AddToHeight("desktop", ((y -
Height("desktop")) + Height(id)));
XIs(id, x); YIs(id, y);
ShowDesktopSize(); // Update the size numbers on the navbox
}

// The sizing buttons, as we need two per window of each.
function sizeinbutton(id)
{
var sizeinbutton = $make("button"); PutIn($text("> <"),
sizeinbutton);
sizeinbutton.onmousedown = function (){StartSizing(id, "in");}
sizeinbutton.style.cursor = "ew-resize";
return sizeinbutton;
}

function sizeoutbutton(id)
{
// The size bigger button
var sizeoutbutton = $make("button"); PutIn($text("< >"),
sizeoutbutton);
sizeoutbutton.onmousedown = function (){StartSizing(id, "out");}
sizeoutbutton.style.cursor = "ew-resize";
return sizeoutbutton;
}

// Size southeast
function sizesebutton(id)
{
var sizesebutton = $make("button"); PutIn($text("v>"),
sizesebutton);
sizesebutton.onmousedown = function (){StartSizing(id, "se");}
sizesebutton.style.cursor = "se-resize";
return sizesebutton;
}

// Size northwest
function sizenwbutton(id)
{
var sizenwbutton = $make("button"); PutIn($text("<^"),
sizenwbutton);
sizenwbutton.onmousedown = function (){StartSizing(id, "nw");}
sizenwbutton.style.cursor = "se-resize";
return sizenwbutton;
}

// For processing move forms, not to be confused with the lower
level WinMove();
function MoveWindow(id)
{
x = $(id+"_x").value;
y = $(id+"_y").value;
WinMove(id, x, y);
}

// Create a window for this windowing system, it's a table with a
title bar and an iframe
// and some borders
function CreateWindow(src, id, title, height, width, top, left)
{
var id = IfNo(id, "Window_"+Windows++);
while ($(id)) id = "Window_"+Windows++;
var nw = $make("table", id);
nw.style.zIndex = ++TopZIndex; // This is used to put windows on
top
nw.style.position = "absolute";
nw.onclick = function(){if (TopZIndex ==0) TopZIndex = Windows;
this.style.zIndex = ++TopZIndex;}//.position = "absolute";
nw.style.height = IfNo(height, 300);

nw.style.width = IfNo(width, 400);
nw.style.top = IfNo(top, 60);
nw.style.left = IfNo(left, 90);
nw.style.backgroundColor="white";
nw.border=1;

// the title bar, one cell;
var tb = $make("td");
tb.style.cursor = "move"; tb.style.width="100%"; tb.align="left";
tb.style.backgroundColor="ddddee";

// now the control bar, another cell;
var ctlb = $make("td"); ctlb.align="left"; ctlb.width="80px";
ctlb.style.whiteSpace="nowrap";

// Sizing in and out buttons.
var TopSizeIn = sizeinbutton(id);
var BottomSizeIn = sizeinbutton(id);
var TopSizeOut = sizeoutbutton(id);
var BottomSizeOut = sizeoutbutton(id);

// The close bar has just the close button
var cb = $make("td"); cb.align = "right"; cb.width="1px";
var closebutton = $make("button"); PutIn($text("x"), closebutton);
closebutton.onclick = function (){$del(id);WindowsNow--}
closebutton.style.cursor = "crosshair";
PutIn(closebutton, cb);

// Put the controls in the control box;
PutIn(sizenwbutton(id), ctlb); PutIn(TopSizeOut, ctlb);
PutIn(TopSizeIn, ctlb);
titletext = $input("text", id+"_Title", (IfNo(title, "Title Bar
"+id))); // Title bar text
titletext.style.width="100%"; // offset by the nowrap properties of
other cells
titletext.style.cursor = "move";
PutIn(titletext, tb);

// The main application section, an iframe in a div in a cell
var appframe = $make("iframe", id+"_iframe");
appframe.style.height = IfNo(height, 300);
appframe.style.width = IfNo(width, 400);
appframe.src = IfNo(src, "http://localhost");
appframe.style.borderStyle="none";//src = IfNo(src,
"http://localhost");
appframe.style.whiteSpace="nowrap";

if (src == "") appframe.src = "http://localhost";

var appdiv = $make("div");
appdiv.id = id+"_div";
appdiv.style.height = IfNo(height, 300);
appdiv.style.width = IfNo(width, 400);
appdiv.style.borderStyle="solid"; appdiv.style.borderColor="black";

var row1 = $make("tr"); var row2 = $make("tr");
row1.style.verticalAlign="top";row1.height="10";

// Now the table cell to contain the div with the iframe.
var appcell = $make("td");appcell.colSpan =3;
appcell.align="center";

// The third row
var row3 = $make("tr");
var row3cell = $make("td"); row3cell.colSpan=3;
row3cell.align="right";

// The moving form:
var mf = $make("form"); mf.style.display="inline";
mf.onsubmit = function() {MoveWindow(id); return false;}
PutIn($text("x: "), mf);
xmov = $input("text", id+"_x", 10000); xmov.size=5;
ymov = $input("text", id+"_y", 10000); ymov.size=5;
movbutn = $input("submit", id+"_mov", "<- Move");
PutIn(xmov, mf);PutIn($text(", y: "), mf);PutIn(ymov, mf);
PutIn(movbutn, mf); PutIn(mf, row3cell);

// Sizing buttons for row 3.
PutIn(BottomSizeIn, row3cell); PutIn(BottomSizeOut, row3cell);
PutIn(sizesebutton(id), row3cell); PutIn(row3cell, row3);

// Now make the moving events:
tb.onmousedown = function(){StartMoving(id);}
tb.onmouseup = function(){show(id+"_iframe");}

// Put the frame in the cell
PutIn(appframe, appdiv); PutIn(appdiv, appcell);
// The appcell in the sceond row, the title bar in the first
PutIn(appcell, row2);
// control box, title box, close box
PutIn(ctlb, row1);PutIn(tb, row1); PutIn(cb, row1);
//the three rows into the table (window)
tablebody = $make("tbody"); // ie is fussy about this
PutIn(row1, tablebody); PutIn(row2, tablebody);PutIn(row3,
tablebody);
// the window into the desktop
PutIn(tablebody, nw); PutIn(nw, $("desktop"));
}
</script>

<!-- The Desktop-Navigation box scripts-->
<script>
function gotosection(section)
{
//msg(section);
if (section < 11) yoffset = 0;
else if (section < 21) yoffset = 1;
else if (section < 31) yoffset = 2;
else if (section < 41) yoffset = 3;
else if (section < 51) yoffset = 4;
else if (section < 61) yoffset = 5;
else if (section < 71) yoffset = 6;
else if (section < 81) yoffset = 7;
else if (section < 91) yoffset = 8;
else yoffset = 9;

x = (Width("desktop")/10)*((section-1)-yoffset*10);
y = (Height("desktop")/10)*(yoffset);

NavBoxX = 450; // Offset values to display the navbox after moving.
NavBoxY = 60;

// Move navbar to some visible area:
if (x+Width("navbox")+NavBoxX < Width("desktop")) XIs("navbox",
x+NavBoxX);
else {Overlap = (x+Width("navbox")) - Width("desktop");
XIs("navbox", x-Overlap);}

if (y+Height("navbox")+NavBoxY < Height("desktop")) YIs("navbox",
y+NavBoxY);
else {Overlap = (y+Height("navbox")) - Height("desktop");
YIs("navbox", y-Overlap);}

window.scrollTo(x,y); // scroll the window to the start of the
desired hundredth square.
}

</script>

<!-- the desktop gui object -->
<div id='desktop'
style='padding:5;position:absolute;top:1;left:1;width:10000;height:10000;
overflow:hidden;border-style:solid;background-color:ddeeff;border-width:1;'
onmouseup='StopMoving();StopSizing();'
onmousedown ='SetMouseMoving(event)'
onmousemove='MoveIfMoving(event)'>

<!-- the navigation box -->
<div id='navbox' onclick='this.style.zIndex=++TopZIndex;'
style="border-width:1;border-style:solid;
border-style:solid;border-width:1;background-color:ffffff;width:230;
height:260;
top:60;left:450;position:absolute;overflow:visible;">
<table border=1 width=100% height=100%>
<tr style='vertical-align:top;'>
<td colspan=2 style='cursor:move;'
onmousedown='StartMoving("navbox")'>
<table border=0 width="100%"> <tr><td>Desktop</td>
<td align=right id='fetchbox'> <a
style='cursor:pointer;font-size:12;text-decoration:underline;color:blue'
onclick='MakeWindowList()'> Fetch Window: ...</a></td></tr>
</table>
</tr>
<tr>

<!-- the navigation grid -->
<td id='desktopgrid'>
<script>
function MakeNavGrid()
{
navtable = $make("table");
tablebody = $make("tbody");
navtable.border=1;
for (rows=1;rows<11;rows++)
{
var row = $make("tr");
for (cols=1;cols<11;cols++)
{
var cell = $make("td");
Section = ((rows-1)*10) + cols;
cell.id=Section;
cell.style.fontSize="9";
cell.onclick = function (){gotosection(this.id);}
cell.style.cursor ="pointer";
cell.onmouseover=function(){this.style.backgroundColor='ccddee';}
cell.onmouseout=function(){this.style.backgroundColor='ffffff';}
PutIn($text(" "+Section+" "), cell);
PutIn(cell, row);
}
PutIn(row, tablebody);
}
PutIn(tablebody, navtable);
PutIn(navtable, $("desktopgrid"));
}

MakeNavGrid(); // Make a nav grid, it knows where to put
itself.

function FetchWindow(list, e) // Get a window according to a
list-click
{
var winid = list[list.selectedIndex].value;
WinMove(winid, Left("navbox"), Top("navbox"));//XIs(winid,
Left("navbox")); YIs(winid, Top("navbox"));
$del("WindowList");
AddToHeight("navbox", -200);
}
function MakeWindowList() // show all windows on navbox.
{
// Delete it if it's already there.
if ($("WindowList"))
{
AddToHeight("navbox", -200);
$del("WindowList");
}
else
{
var WindowList= $make("select","WindowList");
var tables = document.getElementsByTagName('table');
for (table in tables)
{
id = tables
.id ;
if (id != undefined)
{
// if there's an iframe it's one of ours
if ($(id+"_iframe"))
{
option = $make("option");
option.value = id;
PutIn($text($(id+"_Title").value), option);
PutIn(option, WindowList);
}
}
}

WindowList.size = 10;
WindowList.style.display = "block";
WindowList.onclick = function(){FetchWindow(this,
window.event);}
PutIn(WindowList, $("fetchbox"));
AddToHeight("navbox", 200);
}
}

function SizeDesktop() // resize the desktop according to the
navbox
{
HeightIs("desktop", $("desktopheight").value);
WidthIs("desktop", $("desktopwidth").value);
return false;
}

function ShowDesktopSize() // reset the navbox values according
to the desktop
{
$("desktopheight").value = Height("desktop");
$("desktopwidth").value = Width("desktop");
}
</script>
</td>
<td style='vertical-align:top;font-size:11;'>
<form onsubmit='return SizeDesktop()' style='display:inline;'>
<font style='font-weight:bold;'>Width</font><br><input
type='text' value='10000' size=3 id='desktopwidth' /><br> pixels
<br><br>
<font style='font-weight:bold;'>Height</font><br><input
type='text'value='10000' size=3 id='desktopheight' />pixels
<br><br>
<input type='submit' value='Set' />
</form>
</td>
</tr>
<tr>
<td colspan=2>
<font style='font-size:10;'>
Go to a section, resize, or stretch the desktop by dragging
any window past its edges
</font>
</td>
</tr>
</table>
</div>

<!-- desktop background controls -->
<table border=0
style='width:650;border-style:dashed;border-width:1;'>
<tr>
<td>
[<a style='cursor:pointer;color:blue;'
onclick='toggle("helpbox");XIs("helpbox", 40);YIs("helpbox",
100);'>Help</a>]
[<a style='cursor:pointer;color:blue;' onclick='XIs("navbox",
450);YIs("navbox", 60);show("navbox");'>Navbox</a>]
</td>
<td align=right> Load URL:
<form style='display:inline;' onsubmit='return LoadUrl();'>
<script>
function LoadUrl() // grab the url from the form and load it in
a new window.
{
WindowsNow++;CreateWindow($("newurl").value, undefined,
$("newtitle").value)
return false;
}
</script>
<input type='text' style='font-size:10;' size=40 id='newurl'
value=' http://www.google.com/search?q= ' />
<input type='text' style='font-size:10;' id='newtitle'
value='New Title' />
<input type='submit' style='cursor:pointer;' value='<-Open' />
</form>
</td>
</tr>
</table>
<br>Execute Javascript [<a
style='cursor:pointer;text-decoration:underline;color:blue;'
onclick='toggle("codeboxes");$("helpbox").style.display=$("codeboxes").style.display;'
>...</a>]:
<div style="display:block;" id="codeboxes">
<textarea id='code' ACCESSKEY='C' rows=4 cols=40
onfocus='this.value=""'
onblur='ExecuteJavascript(this);'></textarea><br>
<textarea id='codememory' rows=4 cols=40
onfocus='GetCode();'></textarea><br>
</div>

<!-- the help box -->
<table onclick='this.style.zIndex=++TopZIndex;' id="helpbox"
style='background-color:white;border-style:solid;border-width:1;border-color:black;
position:absolute;left:40;top:100;'>
<tr>
<td onmousedown="StartMoving('helpbox');" style='cursor:move;'>
<font style='color:005500;font-weight:bold;'>Help</font></td>
</tr>
<tr>
<td>
<ul style='overflow:auto;
height:300;width:350;font-size:12;'>
<li>Press tab in top textbox to execute its contents </li>
<li>Alt+C to set focus to the code box</li>
<li>L(+tab) to show last code</li>
<li>Javascript will be copied to the second box regardless</li>
<li>Commands provided by this system:
<ul style='font-family:courier;'>
<li>CreateWindow(url, id, title, height, width, top, left);
<font style='color:green;'>// Like the "open" button. Only url
is necessary.</font></li>
<li>WinMove(id, x, y); <font style='color:green;'> // Move a
window by id,
resize desktop accordingly</font></li>
<li>WinSize(id, x, y); <font style='color:green;'> // Doesn't
resize the desktop</font></li>
<li>msg(text); <font style='color:green;'>// shortcut to
window.alert();</font></li>
<li>$(id); <font style='color:green;'>//
document.getElementById();</font></li>
<li>$make(tagtype, id); <font style='color:green;'>// return a
new html element</font></li>
<li>$del(id); <font style='color:green;'>// remove element
from document tree </font></li>
<li>$text(text); <font style='color:green;'>// returns a text
node with text in it </font></li>
<li>$input(type, name, value, id); <font
style='color:green;'>// returns a form input. Type and name are
required</font></li>
<li>AddToHeight(id, pixels); <font style='color:green;'>// Add
to an elements height, must already have a pixel value</font></li>
<li>AddToWidth(id, pixels);</li>
<li>AddToTop(id, pixels); <font style='color:green;'>// Can
also use AddToY();</font></li>
<li>AddToLeft(id, pixels); <font style='color:green;'>// Can
also use AddToX();</font></li>
</ul>
</li>
<ul>
</td>
</tr>
</table>

<!-- this will execute as the page finishes loading -->
<script>
LastCommand=""; // The last code executed from the javascript box

function ExecuteJavascript(CodeBox)
{
var Code = CodeBox.value;
if (Code.toUpperCase() == "L") // in a fraction of a second, show
last command
setTimeout("$('code').focus();$('code').value = LastCommand;",
1);
else if(Code.toUpperCase() != "")
{
LastCommand = CodeBox.value;
eval(LastCommand);
}
}

// Use to add the executed code to a buffer, (the second text box).
function GetCode()
{
var Code = $("code").value;
if (Code.toUpperCase() != "L" && Code !="")
{
$("codememory").value+=$("code").value;
$("codememory").value+="\n";
}
}

$("code").focus(); // set focus to the javascript code box
</script>
<div>
</body>
</html>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top