Section V.4. Cross-Platform Position Scripting


V.4. Cross-Platform Position Scripting

Reconciling the differences among scriptable, CSS-enabled browsers is far easier than in the days when Navigator 4 was a part of the equation. In fact, if you prefer to support only those browsers that use W3C DOM element and CSS property referencing syntax, your primary job is fashioning your code so that the basic content of your page or application is available to all visitors, while the positioning features are available only on browsers that support your needed scripting features.

Introducing positioned elements into a document can make non-CSS browsers do strange things with those elements. If positioned elements contain mission-critical information, you should pay attention to the source code order of your elements so that if CSS is not implemented in a visitor's browser, the element flow is logical enough for the visitor to figure out what's in the document.

Another, more friendly, option is to deliver the HTML with non-positioned elements in the markup, and use scripting to literally create the positioned elements immediately after the page has loaded. See Online Section IV for W3C DOM element creation techniques.

With positioned elements in the document tree, you may need some scripting to make those elements dynamicchanging the kinds of CSS properties discussed earlier in this chapter. As you've seen, there are enough differences in the W3C and IE implementations to make it necessary to perform occasional branching based on the browser's capabilities.

V.4.1. Using a Custom Positioning API

If you are doing a serious amount of scripted positioning, a custom API (Application Program Interface) lets you push the ugly branching code off to the side in an external library. In essence, you create a metalanguage that gives you control over the specific syntax used in both browsers. A custom API requires a lot more work up front, but once the API code is debugged, the API simplifies not only the current scripting job, but any subsequent pages that need the same level of scriptability.

A custom API can take care of the "grunt" work for common position-scripting tasks, such as moving, hiding, showing, and resizing elements, as well as setting background colors or patterns. When you define a custom API library, the functions you write become the interface between your application's scripts and various positioning tasks.

Positioning APIs (or libraries or frameworks) come in all shapes and sizes. Some, like the ones in earlier editions of this book, are collections of functions that you link into your pages from an external .js file. Or you can take a more object-oriented approach to help minimize potential conflicts between your custom function names and other global identifiers in your HTML documents.

V.4.2. A Sample Positioning API

Example V-1 gives you a sample of what an element positioning API library might look like. This version is implemented as a single JavaScript object, whose code exists in its own .js file. The only item occupying global identifier space is the object I've named DHTMLAPI. All calls to its functions are made through the object, such as DHTMLAPI.moveTo( ). Several methods of the object rely on a set of internal property values that must be initialized after the HTML page has loadedtheir value settings need to refer to document nodes that don't exist until the page has loaded its body element. Therefore, your document's onload event handler must invoke DHTMLAPI.init( ) before your scripts can invoke any the object's methods.[*]

[*] You can also use load event queueing across all of your pages, described in Online Section VI, to let the library essentially initialize itself.

In keeping with the spirit of earlier versions of this API, this one continues the tradition of supporting both Internet Explorer 4 and Netscape Navigator 4, even though those browsers do not adhere to W3C standards of referencing elements. Adding support for these dinosaur browsers adds surprisingly little overhead to the entire API object.

The initialization routine sets properties of a DHTMLAPI.browserClass object, which is intended to be used internally within the object (i.e., as "private"). The Boolean properties ("flags," if you will) help various methods know what general capabilities the current browser has, such as whether the browser supports scriptable CSS, W3C DOM element referencing, or only Netscape 4 layers.

Several methods are also intended to be "private" to support other "public" methods that you are encouraged to invoke from your scripts. The API defines the following "public" methods:


moveTo( elementReference, x, y)

Moves a positioned element to a coordinate point within its positioning context


moveBy( elementReference, deltaX, deltaY)

Moves a positioned element by the specified number of pixels in the X and Y axes of the object's positioning context


setZIndex( elementReference, zOrder)

Sets the z-index value of the positioned element


setBGColor( elementReference, color)

Sets the background color of the positioned element


show( elementReference)

Makes the positioned element visible


hide( elementReference)

Makes the positioned element invisible


getComputedStyle( elementReference, CSSPropertyName)

Returns the value of the computed style property of an element (not limited to positioned elements)


getElementLeft( elementReference)

Returns the left pixel coordinate of the positioned element within its positioning context


getElementTop( elementReference)

Returns the top pixel coordinate of the positioned element within its positioning context


getElementWidth( elementReference)

Returns the width, in pixels, of the element[*]

[*] The API does not distinguish between IE's quirks and standards-compatible modes in IE 6 or later for Windows. For IE/Windows operating in standards-compatible mode (see the <!DOCTYPE> element in Chapter 1 in Dynamic HTML, Third Edition), the methods return only the content dimensions; for all other versions of IE/Windows, the values include margins, borders, if any, but not padding.


getElementHeight( elementReference)

Returns the height, in pixels, of the element[*]

Additional helper functions for determining the height and width of the browser window's content region assist with many positioning tasks relative to the window (rather than the document). Example V-1 provides a custom API for positionable elements.

Example V-1. A custom API for positionable elements

 // DHTMLapi3.js custom API for cross-platform // object positioning by Danny Goodman (http://www.dannyg.com). // Release 3.0. Supports NN4, IE, and W3C DOMs. var DHTMLAPI = {     browserClass : new Object( ),     init : function ( ) {         this.browserClass.isCSS = ((document.body && document.body.style) ? true : false);         this.browserClass.isW3C =             ((this.browserClass.isCSS && document.getElementById) ? true : false),         this.browserClass.isIE4 = ((this.browserClass.isCSS && document.all) ? true :         false),         this.browserClass.isNN4 = ((document.layers) ? true : false),         this.browserClass.isIECSSCompat =             ((document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true :            false)     },     // Seek nested NN4 layer from string name     seekLayer : function (doc, name) {         var elem;         for (var i = 0; i < doc.layers.length; i++) {             if (doc.layers[i].name == name) {                 elem = doc.layers[i];                 break;             }             // dive into nested layers if necessary             if (doc.layers[i].document.layers.length > 0) {                 elem = this.seekLayer(doc.layers[i].document, name);                 if (elem) {break;}             }         }         return elem;     },     // Convert element name string or object reference     // into a valid element object reference     getRawObject : function (elemRef) {         var elem;         if (typeof elemRef == "string") {             if (this.browserClass.isW3C) {                 elem = document.getElementById(elemRef);             } else if (this.browserClass.isIE4) {                 elem = document.all(elemRef);             } else if (this.browserClass.isNN4) {                 elem = this.seekLayer(document, elemRef);             }         } else {             // pass through object reference             elem = elemRef;         }         return elem;     },     // Convert element name string or object reference     // into a valid style (or NN4 layer) object reference     getStyleObject : function (elemRef) {         var elem = this.getRawObject(elemRef);         if (elem && this.browserClass.isCSS) {             elem = elem.style;         }         return elem;     },     // Position an element at a specific pixel coordinate     moveTo : function (elemRef, x, y) {         var elem = this.getStyleObject(elemRef);         if (elem) {             if (this.browserClass.isCSS) {                 // equalize incorrect numeric value type                 var units = (typeof elem.left == "string") ? "px" : 0;                 elem.left = x + units;                 elem.top = y + units;             } else if (this.browserClass.isNN4) {                 elem.moveTo(x,y);             }         }     },     // Move an element by x and/or y pixels     moveBy : function (elemRef, deltaX, deltaY) {         var elem = this.getStyleObject(elemRef);         if (elem) {             if (this.browserClass.isCSS) {                 // equalize incorrect numeric value type                 var units = (typeof elem.left == "string") ? "px" : 0;                 elem.left = this.getElementLeft(elemRef) + deltaX + units;                 elem.top = this.getElementTop(elemRef) + deltaY + units;             } else if (this.browserClass.isNN4) {                 elem.moveBy(deltaX, deltaY);             }         }     },     // Set the z-order of an object     setZIndex : function (obj, zOrder) {         var elem = this.getStyleObject(obj);         if (elem) {             elem.zIndex = zOrder;         }     },     // Set the background color of an object     setBGColor : function (obj, color) {         var elem = this.getStyleObject(obj);         if (elem) {             if (this.browserClass.isCSS) {                 elem.backgroundColor = color;             } else if (this.browserClass.isNN4) {                 elem.bgColor = color;             }         }     },     // Set the visibility of an object to visible     show : function (obj) {         var elem = this.getStyleObject(obj);         if (elem) {             elem.visibility = "visible";         }     },     // Set the visibility of an object to hidden     hide : function (obj) {         var elem = this.getStyleObject(obj);         if (elem) {             elem.visibility = "hidden";         }     },     // return computed value for an element's style property     getComputedStyle : function (elemRef, CSSStyleProp) {         var elem = this.getRawObject(elemRef);         var styleValue, camel;         if (elem) {             if (document.defaultView) {                 // W3C DOM version                 var compStyle = document.defaultView.getComputedStyle(elem, "");                 styleValue = compStyle.getPropertyValue(CSSStyleProp);             } else if (elem.currentStyle) {                 // make IE style property camelCase name from CSS version                 var IEStyleProp = CSSStyleProp;                 var re = /-\D/;                 while (re.test(IEStyleProp)) {                     camel = IEStyleProp.match(re)[0].charAt(1).toUpperCase( );                     IEStyleProp = IEStyleProp.replace(re, camel);                 }                 styleValue = elem.currentStyle[IEStyleProp];             }         }         return (styleValue) ? styleValue : null;     },     // Retrieve the x coordinate of a positionable object     getElementLeft : function (elemRef)  {         var elem = this.getRawObject(elemRef);         var result = null;         if (this.browserClass.isCSS || this.browserClass.isW3C) {             result = parseInt(this.getComputedStyle(elem, "left"));         } else if (this.browserClass.isNN4) {             result = elem.left;         }         return result;     },     // Retrieve the y coordinate of a positionable object     getElementTop : function (elemRef)  {         var elem = this.getRawObject(elemRef);         var result = null;         if (this.browserClass.isCSS || this.browserClass.isW3C) {             result = parseInt(this.getComputedStyle(elem, "top"));         } else if (this.browserClass.isNN4) {             result = elem.top;         }         return result;     },     // Retrieve the rendered width of an element     getElementWidth : function (elemRef)  {         var result = null;         var elem = this.getRawObject(elemRef);         if (elem) {             // W3C DOM supporters             result = parseInt(this.getComputedStyle(elemRef, "width"));             // others, including "auto" results             if (result == null || isNaN(parseInt(result))) {                 if (elem.offsetWidth) {                     if (elem.scrollWidth && (elem.offsetWidth != elem.scrollWidth)) {                         result = elem.scrollWidth;                     } else {                         result = elem.offsetWidth;                     }                 } else if (elem.clip && elem.clip.width) {                     // Netscape 4 positioned elements                     result = elem.clip.width;                 }             }         }         return result;     },     // Retrieve the rendered height of an element     getElementHeight : function (elemRef)  {         var result = null;         var elem = this.getRawObject(elemRef);         if (elem) {             // W3C DOM supporters             result = parseInt(this.getComputedStyle(elemRef, "height"));             // others, including "auto" results             if (result == null || isNaN(parseInt(result))) {                 if (elem.offsetHeight) {                     result = elem.offsetHeight;                 } else if (elem.clip && elem.clip.height) {                     result = elem.clip.height;                 }                 return parseInt(result);             }         }         return result;     },     // Return the available content width space in browser window     getInsideWindowWidth : function ( ) {         if (window.innerWidth) {             return window.innerWidth;         } else if (this.browserClass.isIECSSCompat) {             // measure the html element's clientWidth             return document.body.parentElement.clientWidth;         } else if (document.body && document.body.clientWidth) {             return document.body.clientWidth;         }         return null;     },     // Return the available content height space in browser window     getInsideWindowHeight : function ( ) {         if (window.innerHeight) {             return window.innerHeight;         } else if (this.browserClass.isIECSSCompat) {             // measure the html element's clientHeight             return document.body.parentElement.clientHeight;         } else if (document.body && document.body.clientHeight) {             return document.body.clientHeight;         }         return null;     } } 

Notice that every function call in the API invokes the geTRawObject( ) function. If the parameter passed to a function is already an element object, the object reference is passed through to the function's other statements. But it also accepts a string value for an element ID (or Navigator 4 layer name).

You can use the custom API in Example V-1 as-is or as a foundation for your own extensions that fit the kinds of positioning tasks your applications require. Your version will probably grow over time, as you further enhance the positioning techniques used in your applications.

When you write a custom API, save the code in a file with any filename that uses the .js extension. Then, link the library into an HTML document with the following tag pair in the head portion of the document:

 <script language="JavaScript" type="text/javascript" src="/books/2/570/1/html/2/myAPI.js"></script> 

Once you do this and invoke the DHTMLAPI.init( ) method, all the methods in the custom API library become immediately available to all script statements in the HTML document.




Dynamic HTML. The Definitive Reference
Dynamic HTML: The Definitive Reference
ISBN: 0596527403
EAN: 2147483647
Year: 2004
Pages: 120
Authors: Danny Goodman

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net