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

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

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
5 Free as in freedom, and free as in free-beer (beer not included).
6 All in one html/js file at
7 You can copy and paste this post into a new .html file and start your
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-->
    <title>Web Windows</title>

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

        <!-- Scripts to control the desktop: -->
            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
            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);;return el;}
            function $del(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); name; el.type= type; el.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
            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);}
            function Left(id){return pxVal($(id).style.left);}

            // Write these values more quickly:
            function WidthIs(id, newwidth)
            function HeightIs(id, newheight)
            function TopIs(id, newtop)
            function LeftIs(id, newleft)
            XIs = LeftIs; YIs = TopIs; // Some aliases

            // Increase the height, width, top (y), or left (x) properties of
            function AddToHeight(id, pixels) {HeightIs(id,
            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)

            // 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) -
                    ExtraHeight = Top(CurrentObject)+Height(CurrentObject) -
                    if (ExtraWidth > 0) WidthIs("desktop", Width("desktop")+
                    if (ExtraHeight > 0) HeightIs("desktop", Height("desktop")+
                    $("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,
                    if (xdiff < 0) XIs(CurrentObject, StartObjectX + xdiff);
                    if (ydiff < 0) YIs(CurrentObject, StartObjectY + ydiff);
                else if (SizingType == "in")
                    WinSize(CurrentObject, StartObjectWidth-Math.abs(xdiff),
                    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"))
            function SetMouseMoving(e) {StartMouseX = e.clientX; StartMouseY =
e.clientY;    }
            function StartMoving(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 =
                if ($(ObjectID+"_iframe")) hide(ObjectID+"_iframe");

            function StartSizing(ObjectID, type)
                SizingType = type;

            function hide(id)
            function show(id)

            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
                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.onmousedown = function (){StartSizing(id, "in");}
       = "ew-resize";
                return sizeinbutton;

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

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

            // Size northwest
            function sizenwbutton(id)
                var sizenwbutton = $make("button"); PutIn($text("<^"),
                sizenwbutton.onmousedown = function (){StartSizing(id, "nw");}
       = "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);
       = ++TopZIndex; // This is used to put windows on
       = "absolute";
                nw.onclick = function(){if (TopZIndex ==0) TopZIndex = Windows; = ++TopZIndex;}//.position = "absolute";
       = IfNo(height, 300);

       = IfNo(width, 400);
       = IfNo(top, 60);
       = IfNo(left, 90);

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

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

                // 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 ()
       = "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
      "100%"; // offset by the nowrap properties of
other cells
       = "move";
                PutIn(titletext, tb);

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

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

                var appdiv = $make("div");
       = id+"_div";
       = IfNo(height, 300);
       = IfNo(width, 400);

                var row1 = $make("tr"); var row2 = $make("tr");

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

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

                // The moving form:
                var mf = $make("form");"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()
                tb.onmouseup = function()

                // 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,
                // the window into the desktop
                PutIn(tablebody, nw); PutIn(nw, $("desktop"));

        <!-- The Desktop-Navigation box scripts-->
            function gotosection(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",
                else {Overlap = (x+Width("navbox")) - Width("desktop");
XIs("navbox", x-Overlap);}

                if (y+Height("navbox")+NavBoxY < Height("desktop")) YIs("navbox",
                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.


        <!-- the desktop gui object -->
        <div id='desktop'
                onmousedown ='SetMouseMoving(event)'

            <!-- the navigation box -->
            <div id='navbox'  onclick=';'
                <table border=1 width=100% height=100%>
                    <tr style='vertical-align:top;'>
                        <td colspan=2 style='cursor:move;'
                            <table border=0 width="100%"> <tr><td>Desktop</td>
                                <td align=right id='fetchbox'> <a
onclick='MakeWindowList()'> Fetch Window: ...</a></td></tr>

                        <!-- the navigation grid -->
                        <td id='desktopgrid'>
                                function MakeNavGrid()
                                    navtable = $make("table");
                                    tablebody = $make("tbody");
                                    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.onclick = function ()
                                            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

                                function FetchWindow(list, e)  // Get a window according to a
                                    var winid = list[list.selectedIndex].value;
                                    WinMove(winid, Left("navbox"), Top("navbox"));//XIs(winid,
Left("navbox")); YIs(winid, Top("navbox"));
                                    AddToHeight("navbox", -200);
                                function MakeWindowList()  // show all windows on navbox.
                                    // Delete it if it's already there.
                                    if ($("WindowList"))
                                        AddToHeight("navbox", -200);
                                        var WindowList= $make("select","WindowList");
                                        var tables = document.getElementsByTagName('table');
                                        for (table in tables)
                                            id = tables[table].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;
                               = "block";
                                        WindowList.onclick = function(){FetchWindow(this,
                                        PutIn(WindowList, $("fetchbox"));
                                        AddToHeight("navbox", 200);

                                function SizeDesktop() // resize the desktop according to the
                                    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");
                        <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
                                <font style='font-weight:bold;'>Height</font><br><input
type='text'value='10000' size=3 id='desktopheight' />pixels
                                <input type='submit' value='Set' />
                        <td colspan=2>
                                <font style='font-size:10;'>
                                    Go to a section, resize, or stretch the desktop by dragging
any window past its edges

            <!-- desktop background controls -->
            <table border=0
                        [<a style='cursor:pointer;color:blue;'
onclick='toggle("helpbox");XIs("helpbox", 40);YIs("helpbox",
                        [<a style='cursor:pointer;color:blue;' onclick='XIs("navbox",
450);YIs("navbox", 60);show("navbox");'>Navbox</a>]
                    <td align=right> Load URL:
                        <form style='display:inline;' onsubmit='return LoadUrl();'>
                                function LoadUrl() // grab the url from the form and load it in
a new window.
                                    WindowsNow++;CreateWindow($("newurl").value, undefined,
                                    return false;
                            <input type='text' style='font-size:10;' size=40 id='newurl'
value='' />
                            <input type='text' style='font-size:10;' id='newtitle'
value='New Title' />
                            <input type='submit' style='cursor:pointer;' value='<-Open' />
            <br>Execute Javascript [<a
            <div style="display:block;" id="codeboxes">
                <textarea id='code' ACCESSKEY='C' rows=4 cols=40
                <textarea id='codememory' rows=4 cols=40

            <!-- the help box -->
            <table onclick=';' id="helpbox"
                    <td  onmousedown="StartMoving('helpbox');" style='cursor:move;'>
                            <font style='color:005500;font-weight:bold;'>Help</font></td>
                        <ul style='overflow:auto;
                            <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
                                    <li>$(id); <font style='color:green;'>//
                                    <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
                                    <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>

            <!-- this will execute as the page finishes loading -->
                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;",
                    else if(Code.toUpperCase() != "")
                        LastCommand = CodeBox.value;

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

                $("code").focus(); // set focus to the javascript code box

Site Timeline