| By Coach Wei | Article Rating: |
|
| May 21, 2007 11:00 AM EDT | Reads: |
10,633 |
This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs for the special pre-order price, click here for more information. Aimed at everyone from enterprise developers to self-taught scripters, Real-World AJAX: Secrets of the Masters is the perfect book for anyone who wants to start developing AJAX applications.
The Code
The AjaxWord client consists of JavaScript and HMTL code. The application's user interface is defined in HTML. Client-side logic written in JavaScript defi nes the behavior of the user interface by leveraging a generic JavaScript/DHTML toolkit that's built from scratch. From a Model-View-Controller perspective, the HTML files are "Views" and the JavaScript code acts as "Controllers."
The JavaScript/DHTML toolkit defi nes all the UI widgets. By separating UI widgets from the application, it's easier to develop and maintain the application code. Because of the level of richness required by AjaxWord and the limited availability of AJAX toolkits in the late 1990s, this entire toolkit was written from scratch. It would have been easier to build AjaxWord today by leveraging some of the available toolkits that have emerged in the last 12 months.
A Generic DHTML/JavaScript Toolkit
The AjaxWord DHTML/JavaScript toolkit is a generic toolkit that contains a list of rich user interface components, event management, and code for doing asynchronous communications.
In Figure 15.10, the left items are available with Web browsers. All other items aren't available in browsers and have to be built from scratch. In addition to UI elements, the toolkit provides a systematic way of managing UI events and doing asynchronous communications. When the application was written, the popular XmlHttpRequest object wasn't available in browsers, so AjaxWord actually uses hidden frames to asynchronously communicate.
Instead of elaborating on how each component is built, we will use the "window" object as an example. The window object that we are referring to is a draggable, resizable window that resides inside a standard browser window, giving the look-and-feel of a multiple document interface. It is a basic component for desktop application user interfaces, but isn't available for Web applications.
Creating a "Window" Widget
Figure 15.11 shows how an AjaxWord UI Toolkit window is running inside a browser alongside some HTML text. We'll explain how to define its view and its behavior below.
Defining the View
The view is defined using HTML. To mimic a window look, the view defines 14 different areas of a "window" user interface: the four corners, the four edges, the window content, the title bar, and the four window control areas (close, maximize, minimize, and the window icon). Figure 15.12 shows how a window user interface is split into 14 different regions.
Each window area is defined by a "DIV" tag. For the four corners and four edges, each DIV tag contains an image. Each of the four window controls also contain an image. When necessary, these images can be changed according to style requirements. Some of DIV tags have event handlers defined too so that the window can respond to events. The view definition code is shown in Listing 15.1.
Listing 15.1
<DIV ID="wctl" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/corner-tl.gif); CLIP: rect(0px 16px 16px 0px);
CURSOR: move; HEIGHT: 16px; LEFT: 0px; POSITION: absolute; TOP: 0px; VISIBILITY: visible;
WIDTH: 16px; repeat: no"></DIV>
<DIV ID="wctr" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/corner-tr.gif); CLIP: rect(0px 16px 16px 0px);
CURSOR: move; HEIGHT: 16px; LEFT: 284px; POSITION: absolute; TOP: 0px; VISIBILITY:
visible; WIDTH: 16px; repeat: no"></DIV>
<DIV ID="wcbl" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/corner-bl.gif); CLIP: rect(0px 16px 16px 0px);
CURSOR: move; HEIGHT: 16px; LEFT: 0px; POSITION: absolute; TOP: 184px; VISIBILITY:
visible; WIDTH: 16px; repeat: no"></DIV>
<DIV ID="wcbr" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/corner-br.gif); CLIP: rect(0px 16px 16px 0px);
CURSOR: move; HEIGHT: 16px; LEFT: 284px; POSITION: absolute; TOP: 184px; VISIBILITY:
visible; WIDTH: 16px; repeat: no"></DIV>
<DIV ID="wEdgeLeft" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/border-v.gif); CLIP: rect(0px 6px 168px 0px);
CURSOR: w-resize; HEIGHT: 168px; LEFT: 0px; POSITION: absolute; TOP: 16px; VISIBILITY:
visible; WIDTH: 6px; repeat: yes"></DIV>
<DIV ID="wEdgeTop" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/border-h.gif); CLIP: rect(0px 268px 6px 0px);
CURSOR: n-resize; HEIGHT: 6px; LEFT: 16px; POSITION: absolute; TOP: 0px; VISIBILITY:
visible; WIDTH: 268px; repeat: yes"></DIV>
<DIV ID="wEdgeBtm" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/border-h.gif); CLIP: rect(0px 268px 6px 0px);
CURSOR: s-resize; HEIGHT: 6px; LEFT: 16px; POSITION: absolute; TOP: 194px; VISIBILITY:
visible; WIDTH: 268px; repeat: yes"></DIV>
<DIV ID="wEdgeRight" onmousedown=_nwWindowMouseDown(this)
onselectstart="event.cancelBubble=true;return true;"
STYLE="BACKGROUND-IMAGE: url(../images/border-v.gif); CLIP: rect(0px 6px 168px 0px);
CURSOR: e-resize; HEIGHT: 168px; LEFT: 294px; POSITION: absolute; TOP: 16px; VISIBILITY:
visible; WIDTH: 6px; repeat: yes"></DIV>
<iframe id="wContentFrame" NAME="wContentFrame"
STYLE="BACKGROUND-COLOR: #76efb1; CLIP: rect(0px 288px 142px 0px); HEIGHT: 142px;
LEFT: 6px; POSITION: absolute; TOP: 31px; VISIBILITY: visible; WIDTH: 288px"
SRC="about:blank"></iframe>
<DIV ID="wTitleBar"
onselectstart="event.cancelBubble=true;return false;"
STYLE="CLIP: rect(0px 288px 24px 0px); CURSOR: default; HEIGHT: 24px; LEFT: 6px; POSITION:
absolute; TOP: 6px; VISIBILITY: visible; WIDTH: 288px">
<DIV ID="wClose" onmouseup="_nwWindowMouseDown(this)"
title="click here to close the window"
STYLE="CLIP: rect(0px 20px 20px 0px); HEIGHT: 20px; LEFT: 268px; POSITION: absolute;
TOP: 0px; VISIBILITY: visible; WIDTH: 20px"><A
href="JavaScript://"><IMG border=0 id=wCloseImg
onselectstart="event.cancelBubble=true;return false;"
src="../images/close0.gif" width="20" height="20"></img></a></DIV>
<DIV ID="wMax" onmouseup="_nwWindowMouseDown(this)"
title="click here to maximize the window"
STYLE="CLIP: rect(0px 20px 20px 0px); HEIGHT: 20px; LEFT: 248px; POSITION: absolute;
TOP: 0px; VISIBILITY: visible; WIDTH: 20px"><A
href="JavaScript://"><IMG border=0 id=wMaxImg
onselectstart="event.cancelBubble=true;return false;"
src="../images/max0.gif" width="20" height="20"></a></DIV>
<DIV ID="wMin" onmouseup="_nwWindowMouseDown(this)"
title="click here to minimize the window"
STYLE="CLIP: rect(0px 20px 20px 0px); HEIGHT: 20px; LEFT: 228px; POSITION: absolute;
TOP: 0px; VISIBILITY: visible; WIDTH: 20px"><A
href="JavaScript://"><IMG border=0 id=wMinImg
onselectstart="event.cancelBubble=true;return false;"
src="../images/min0.gif" width="20" height="20"></a></DIV>
<nobr>
<DIV ID="wTitle" onselectstart="event.cancelBubble=true;return false;"
STYLE="CLIP: rect(0px 208px 24px 0px); FONT-FAMILY: Arial; FONT-SIZE: 14px; FONTWEIGHT:
bold; HEIGHT: 24px; LEFT: 20px; POSITION: absolute; TOP: 0px; VISIBILITY: visible;
WIDTH: 208px"> <SPAN
ID="wTitleText" onselectstart="event.cancelBubble=true;return false;">Loading...</
SPAN></DIV>
</nobr>
<DIV ID="wIcon"
STYLE="CLIP: rect(0px 20px 20px 0px); HEIGHT: 20px; LEFT: 0px; POSITION: absolute;
TOP: 0px; VISIBILITY: visible; WIDTH: 20px"><A
href="JavaScript://"><IMG border=0 id=wIconImg
onselectstart="event.cancelBubble=true;return false;"
src="../images/icon.gif" width="20" height="20"></a></DIV>
</DIV>
<DIV ID="wTitleSep"
STYLE="BACKGROUND-COLOR: #62659c; CLIP: rect(0px 288px 1px 0px); CURSOR: default;
HEIGHT: 1px; LEFT: 6px; POSITION: absolute; TOP: 30px; VISIBILITY: visible; WIDTH:
288px"></DIV>
<nobr>
<DIV ID="wStatus" onselectstart="event.cancelBubble=true;return false;"
STYLE="BACKGROUND-COLOR: #e2e2e2; CLIP: rect(0px 288px 20px 0px); CURSOR: default;
FONT-FAMILY: Arial; FONT-SIZE: 12px; HEIGHT: 20px; LEFT: 6px; POSITION: absolute; TOP:
174px; VISIBILITY: visible; WIDTH: 288px"> <SPAN
ID="wStatusText" onselectstart="event.cancelBubble=true;return false;">Status</SPAN></
DIV>
</nobr>
<DIV ID="wStatusSep"
STYLE="BACKGROUND-COLOR: #62659c; CLIP: rect(0px 288px 1px 0px); HEIGHT: 1px; LEFT:
6px; POSITION: absolute; TOP: 173px; VISIBILITY: visible; WIDTH: 288px"></DIV>
Defining the Controller
The controller logic of a window widget is defined using JavaScript. The JavaScript file "NWindow.js" is one of the controllers that define the basic behavior of a window widget.
Window Initialization
When a window is created, "NWindow.js" initializes it by connecting the JavaScript object with the "view" object (HTML code), hooking up event handlers and initializing object properties. Here is the initialization code:
Listing 15.2
function NWindow(title,parentLayer,x,y,w,h,pwin,windowDefinitionFile)
{
this.jPanel=JPanel;
this.jPanel(parentLayer,x,y,w,h,null,true,null,true,true,pwin);
objectManager.add(this);
if(!windowDefinitionFile)
windowDefinitionFile="../client_lib/windowTemplate.html";
this.load(windowDefinitionFile);
this.title=title;
this.titleBarHeight=24;
this.statusBarHeight=20;
this.statusText="Copyright(C)1996-2005, Coach Wei (<a href='http://www.coachwei.
com'>blog</a>). Open Source licensed.";
this.borderWidth=6;
this.iconWidth=20;
this.iconLength=200;
this.iconized=false;
this.winIcon="../images/icon.gif";
this.corner=16;
this.separator=1;
this.color = new Object();
this.color.titleUnfocused = '#cdceff';
this.color.titleFocused='#00ffff';
this.color.iconFocused='#aaffff';
this.color.iconUnfocused="#bbbbbb";
this.color.tileTextUnfocused="menu";
this.color.titleTextFocused="highlighttext";
this.className="NWindow";
this.initWindow=_nWindowInitWindow;
this.onMouseDown=_nwWindowMouseDown;
this.onMouseUp=_nWindowOnMouseUp;
this.onFocus=_nWindowOnFocus;
this.onBlur=_nWindowOnBlur;
this.repaintResize=_nWindowRePaintResize;
this.addToTaskbar=_nWindowAddToTaskbar;
this.startResize=_nwWindowStartResize;
this.resize=_nWindowSetSize;
this.iconize=_nWindowIconize;
this.onClose=_nWindowOnClose;
this.onMaximize=_nWindowOnMaximize;
this.onMinimize=_nWindowOnMinimize;
this.setTitle=_nWindowSetTitle;
this.setIcon=_nWindowSetIcon;
this.setStatus=_nWindowSetStatus;
this.sizeContent=_nWindowSizeContent;
this.loadContent=_nWindowLoad;
this.getWindowSize=_getBrowserWindowSize;
}
function _nWindowInitWindow(win)
{
if(!win||!win.document) return;
this.doc=win.document;
this.wctl=this.getJPanelFor("wctl",win);
this.wctl.domObj.parentCtrl=this;
this.wctr=this.getJPanelFor("wctr",win);
this.wctr.domObj.parentCtrl=this;
this.wcbr=this.getJPanelFor("wcbr",win);
this.wcbr.domObj.parentCtrl=this;
this.wcbl=this.getJPanelFor("wcbl",win);
this.wcbl.domObj.parentCtrl=this;
this.wEdgeTop=this.getJPanelFor("wEdgeTop",win);
this.wEdgeTop.domObj.parentCtrl=this;
this.wEdgeBtm=this.getJPanelFor("wEdgeBtm",win);
this.wEdgeBtm.domObj.parentCtrl=this;
this.wEdgeLeft=this.getJPanelFor("wEdgeLeft",win);
this.wEdgeLeft.domObj.parentCtrl=this;
this.wEdgeRight=this.getJPanelFor("wEdgeRight",win);
this.wEdgeRight.domObj.parentCtrl=this;
this.wTitleBar=this.getJPanelFor("wTitleBar",win);
this.wTitleBar.domObj.parentCtrl=this;
this.wIcon=this.getJPanelFor("wIcon",win);
this.wTitle=this.getJPanelFor("wTitle",win);
this.wTitle.domObj.parentCtrl=this;
this.wClose=this.getJPanelFor("wClose",win);
this.wClose.domObj.parentCtrl=this;
this.wMax=this.getJPanelFor("wMax",win);
this.wMax.domObj.parentCtrl=this;
this.wMin=this.getJPanelFor("wMin",win);
this.wMin.domObj.parentCtrl=this;
this.wTitleSep=this.getJPanelFor("wTitleSep",win);
this.wStatus=this.getJPanelFor("wStatus",win);
this.wStatusSep=this.getJPanelFor("wStatusSep",win);
this.wContent=this.getJPanelFor("wContentFrame",win,false,true);
if(this.wContent.domObj) this.wContent.domObj.parentCtrl=this;
this.wTitleText=win.document.all["wTitleText"];
this.wStatusText=win.document.all["wStatusText"];
this.wIconImg=win.document.all["wIconImg"];
this.setDragable(true);
top.dragManager.setGrab(this,this.borderWidth,this.borderWidth,this.getWidth()-
3*this.iconWidth-2*this.borderWidth,this.titleBarHeight);
if(this.resize) this.resize(this.w,this.h);
if(top._initSystemEvent)
{
top._initSystemEvent(win);
top._initSystemEvent(this.wContent.iframe.frame);
}
}
This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs, click here to order.
Published May 21, 2007 Reads 10,633
Copyright © 2007 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Coach Wei
Coach Wei is the Founder and Chairman of Nexaweb (www.nexaweb.com), developers of the leading software platform for building and deploying Web 2.0 and AJAX applications. Previously, he played a key role at EMC Corporation in the development of a new generation of storage network management software. Wei has his master's degree from MIT, holds several patents, is the author of several technology publications including JDJ, Web 2.0 Journal, and AJAXWorld Magazine, and is an industry advocate for the proliferation of open standards.
![]() |
gnerse 11/13/08 04:50:54 PM EST | |||
Dear Sir, |
||||
- Practical Approaches for Optimizing Website Performance
- SQL Anywhere Server and AJAX
- The Difference Between Web Hosting and Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Cloud Computing on Gartner's Top 10 List and SYS-CON Events' 2010 Calendar
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- US Post Office Hops a Ride on NetSuite’s Cloud
- Gang of Four Creates Cloud BI Stack
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Confessions of a Ulitzer Addict
- AJAX World RIA Conference & Expo Kicks Off in New York City
- An Introduction to Abbot
- What is Web 3.0?
- AJAXWorld RIA Conference & Expo 2009 West: Call for Papers
- Interviewing Java Developers With Tears in My Eyes
- Adobe Enters Cloud Computing with LiveCycle
- REA Is Where RIA Becomes the Norm
- RIAs for Web 3.0 Using the Microsoft Platform
- Practical Approaches for Optimizing Website Performance
- Social Media Terrorists
- Building a Drag-and-Drop Shopping Cart with AJAX
- What Is AJAX?
- Google Maps! AJAX-Style Web Development Using ASP.NET
- Flashback to January 2006: Exclusive SYS-CON.TV Interviews on "OpenAjax Alliance" Announcement
- AJAXWorld Conference & Expo to Take Place October 2-4, 2006, at the Santa Clara Convention Center, California
- AJAX Sponsor Webcasts Are Now Available at AJAXWorld Website
- How and Why AJAX, Not Java, Became the Favored Technology for Rich Internet Applications
- "Real-World AJAX" One-Day Seminar Arrives in Silicon Valley
- AJAXWorld University Announces AJAX Developer Bootcamp
- AJAX Support In JadeLiquid WebRenderer v3.1



































