/* xbdhtml.js (Cross-Browser Nav4/Gecko/IE DHTML API) 14 May 98, Eric Krock, Copyright Netscape Communications Permission is granted to reuse, redistribute, and modify without charge. Updated 18 July 2000 by Vladimir Ermakov, Netscape Communications, and Marcell Ortutay, Plugged in Enterprises, to include support of the new Netscape Gecko layout engine. Updated 15 of February 2001 by Vladimir Ermakov, Netscape Communications: New Features -showElt/hideElt -convenience functions to use insead of setEltVisibility -setEltWidth/setEltHeight -Set the width/height of a layer -getEltPageLeft/getEltPageTop -XBrowser version of Nav4 pageX/pageY -stringToNumber -Returns 0 instead of NaN Improved: -getEltWidth/getEltHeight -Return offsetWidth if width not specified. -Also, where possible, replaced detection by browser with detection by property Updated October 02, 2001 by Bob Clary, Netscape Communications Misc - changed reference to Ultimate Browser Sniffer on mozilla.org Bugs Fixed - hideElt -fixed missing argument to setEltVisibility - getEltPageTop -added marginTop for IE5/Mac Makes CSSP functionality and properties of positioned, named elements accessible from JavaScript in Netscape 4.x, IE and user agents implementing Gecko layout engine offering a single set of functions which can be used on both browsers, bridging DOM differences. Allows you to do these things from JavaScript on Nav4+/IE4+/Gecko: - get element object by specifying its name - hide/show element - get/set X, Y, Z position of element - get element height/width - get/set clipping area (visible area) of element - get/set background color and background image of element Also includes simplified JavaScript client sniffer and functions to ease dynamic, conditional generation of HTML markup via document.write() statements. Design goals: - forwardly compatible with future DOM enhancements - redefinable stub function API - coexist peacefully with other libraries - no function name conflicts with cbdhtml.js, etc. - keep # of functions reasonable and use parameters to specify values - naming convention for functions easy to learn and remember - make as short as possible to type - loadable (though not executable!) without error on Nav3 since Nav3 sometimes loads */ // This is a simplified version of the JavaScript Client Sniffer code // found at http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html function Is () { // convert all characters to lowercase to simplify testing var agt=navigator.userAgent.toLowerCase() // --- BROWSER VERSION --- this.major = stringToNumber(navigator.appVersion) this.minor = parseFloat(navigator.appVersion) this.nav = ((agt.indexOf('mozilla')!=-1) && ((agt.indexOf('spoofer')==-1) && (agt.indexOf('compatible') == -1))) this.nav2 = (this.nav && (this.major == 2)) this.nav3 = (this.nav && (this.major == 3)) this.nav4 = (this.nav && (this.major == 4)) //Netscape 6 this.nav5 = (this.nav && (this.major == 5)) this.nav6 = (this.nav && (this.major == 5)) this.gecko = (this.nav && (this.major >= 5)) this.ie = (agt.indexOf("msie") != -1) this.ie3 = (this.ie && (this.major == 2)) this.ie4 = (this.ie && (this.major == 3)) this.ie5 = (this.ie && (this.major == 4)) this.opera = (agt.indexOf("opera") != -1) this.nav4up = this.nav && (this.major >= 4) this.ie4up = this.ie && (this.major >= 4) } var is = new Is(); // Convenience functions to ease dynamic/conditional markup // generation depending upon browser vendor/version/OS. // convenience function to save typing out document.write("STRING"); // if optional second argument minVersion passed in, // only write if >= that version; // if optional third argument maxVersion passed in, // only execute if <= that version; function dw(str, minVersion, maxVersion) { if ( ((dw.arguments.length < 3) || (is.major <= maxVersion)) && ((dw.arguments.length < 2) || (is.major >= minVersion))) document.write(str) } // document write boolean // convenience function to save typing out // if (aBoolean) document.write("STRING"); // if optional second argument aBoolean passed in, only write if // aBoolean is true. function dwb (str, aBoolean) { if ((dwb.arguments.length < 2) || aBoolean) document.write(str) } // string version: // convenience function to return str or "" depending on version; // if optional second argument version passed in, // only return str if >= that version; // if optional third argument maxVersion passed in, // only return str if <= that version; function sv(str, minVersion, maxVersion) { if ( ((sv.arguments.length < 3) || (is.major <= maxVersion)) && ((sv.arguments.length < 2) || (is.major >= minVersion))) return str; else return ""; } // string boolean // convenience function to save typing out // (aBoolean)?"STRING":"" // if optional second argument aBoolean passed in, only return // str if aBoolean is true, else return "". function sb (str, aBoolean) { if ((sb.arguments.length < 2) || aBoolean) return str; else return ""; } /* The following stub function API for cross-browser HTML element positioning and visibility (CSSP access) was derived from Mike Hall's excellent CBDHTML API. Thanks also to Danny Goodman (http://www.dannyg.com/) and Dan Steinman (http://members.xoom.com/dynduo/). USAGE NOTE: when using the functions which get element CSSP properties [getEltLeft, getEltTop, etc.], keep in mind the following IE4 CSSP property initialization problem: if you initialize a property value by CSSP markup, e.g.: #foo { left: 100px } rather than initializing them from JavaScript, e.g.: var fooElt = getElt ("foo"); setEltLeft (fooElt, 100); ... the property value for the element's JavaScript style object (i.e. document.all.foo.style.left) is not set to the initial value! This is true for a number of IE4 style object properties including left, top, and clip. Before you get one of these properties in IE4, you must first set it from JavaScript. Workaround: set the property via JavaScript instead of CSSP markup, or set it from both to the same value. */ /* functions genElt, writeElt, and layerClipOrder Sometimes dynamically generating markup which is optimized for the current browser will simplify development. genElt will generate a named DIV on IE4 and Netscape6, and a LAYER/ILAYER tag on Nav4 as a string. writeElt will create the same string and write it out. These three functions must be reused as a group. writeElt calls genElt, and those two both call layerClipOrder. ARGUMENTS OF FUNCTIONS genElt AND writeElt genElt and writeElt have identical argument lists. The first argument, name, is required. All of the other arguments default to false and can be explicitly set to false or omitted. Those properties will be hard coded into the HTML markup if the argument is provided, and left unset if the argument is set to false or omitted. For example, both of these function calls have the same effect. They will generate a named, positioned element but not specify any of the properties, and will write out the element and content even on Nav3/IE3 and earlier: writeElt ("foo"); writeElt ("foo", false, false, false); name STRING. Name of element's ID. content STRING. Content written within element. left INTEGER. Left edge of element in pixels. top INTEGER. Top edge of element in pixels. z INTEGER. z-index of element. width INTEGER. width in pixels. height INTEGER. height in pixels. visibility STRING. "visible", "hidden", or "inherit". backgroundColor STRING. Background color of element. backgroundImage STRING. Background image of element. clip STRING. Comma-delimited list (no spaces!) of 4 integers in top-right-bottom-left order. Sets clip. relative BOOLEAN. If true, position relatively, else absolutely. On Nav4, this determines whether LAYER (absolute) or ILAYER (relative) is generated. hideEltOnOlderBrowsers BOOLEAN. If true, return '' on Nav3, IE3, and older. useDivInsteadOfLayer BOOLEAN. If true, generate DIV on Nav4 not I/LAYER. classname STRING. CLASS attribute value for element. 'genElt' is short for 'generate element markup'. */ /* maps css order ,,, to LAYER CLIP= order ,,, */ function layerClipOrder (cssClipString) { var commaPos = cssClipString.lastIndexOf(","); return (cssClipString.substring(commaPos+1) + "," + cssClipString.substring(0,commaPos)); } function genElt (name, content, left, top, z, width, height, visibility, backgroundColor, backgroundImage, clip, relative, hideEltOnOlderBrowsers, useDivInsteadOfLayer, classname) { var markup = ""; if (is.gecko) { markup = '
' + ((content)?content:'') + '
'; } else if (is.nav && (is.major == 4 || !hideEltOnOlderBrowsers) && !useDivInsteadOfLayer) { var tagname = (relative)?'ILAYER':'LAYER'; if (visibility && (visibility!='')) { if (visibility=="hidden") visibility = "hide"; else if (visibility=="visible") visibility = "show"; } markup = '<' + tagname + ' ID="' + name + '"' + ((classname)?' CLASS="' + classname + '"':'') + ((left)?' LEFT="' + left + '"':'') + ((top)?' TOP="' + top + '"':'') + ((width)?' WIDTH="' + width + '"':'') + ((height)?' HEIGHT="' + height + '"':'') + ((visibility && (visibility!='')) ? ' VISIBILITY="' + visibility + '"' : '') + ((z)?' Z-INDEX="' + z + '"':'') + ((backgroundColor)?' BGCOLOR="' + backgroundColor + '"':'') + ((backgroundImage)?' BACKGROUND="' + backgroundImage + '"':'') + ((clip)?' CLIP="' + layerClipOrder(clip) + '"':'') + '>' + ((content)?content:'') + ''; } else if ((is.ie || (is.nav && useDivInsteadOfLayer)) && (is.major>=4 || !hideEltOnOlderBrowsers)) { markup = '
' + ((content)?content:'') + '
'; } return markup; } function writeElt (name, content, left, top, z, width, height, visibility, backgroundColor, backgroundImage, clip, relative, hideEltOnOlderBrowsers, useDivInsteadOfLayer, classname) { if (writeElt.arguments.length < 15) classname = false; if (writeElt.arguments.length < 14) useDivInsteadOfLayer = false; if (writeElt.arguments.length < 13) hideEltOnOlderBrowsers = false; if (writeElt.arguments.length < 12) relative = false; if (writeElt.arguments.length < 11) clip = false; if (writeElt.arguments.length < 10) backgroundImage = false; if (writeElt.arguments.length < 9) backgroundColor = false; if (writeElt.arguments.length < 8) visibility = false; if (writeElt.arguments.length < 7) height = false; if (writeElt.arguments.length < 6) width = false; if (writeElt.arguments.length < 5) z = false; if (writeElt.arguments.length < 4) top = false; if (writeElt.arguments.length < 3) left = false; if (writeElt.arguments.length < 2) content = false; document.write (genElt (name, content, left, top, z, width, height, visibility, backgroundColor, backgroundImage, clip, relative, hideEltOnOlderBrowsers, useDivInsteadOfLayer, classname)); } /* CALLING SYNTAX: each Name is a string which is an element's ID attribute value or a LAYER tag's NAME attribute value. getElt (topLevelElementName, childElementName, grandchildElementName ... targetElementName) Example of getting a top-level element: var fooElement = getElt ("foo") Example of getting a nested element: var fooElement = getElt ("bar", "baz", "foo") ... where baz is foo's containing parent, and bar is a top-level element which is baz's containing parent. */ function getElt () { if (is.nav4) { var currentLayer = document.layers[getElt.arguments[0]]; for (var i=1; i