Scripting for 5th Generation Browsers - Part 2
Creating Elements
Another powerful tool in the web developer’s arsenal is the document.createElement() method. This method allows developers to create tags on the fly. Essentially, you create a whole document complete with images, text, and whatever else you can think of . However, what is essential to understand when using this method is that what occurs is the creation of a tag, but the tag itself does not have any attributes. For example.
ifrm = document.createElement("IFRAME");
creates an IFrame tag, but it does not define its src attribute or its width and height, nor does it tell it where to place the IFrame in the document body. In order to achieve all the above we can use some of the things that we have learnt previously and create an IFrame from thin air complete with its attributes.
In the following script example we use:
· createElement()
· setAttribute()
· style attributes
· appendChild()
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Creating an IFRAME</title>
<script language="JavaScript" type="text/javascript">
function makeFrame() {
ifrm = document.createElement("IFRAME");
ifrm.setAttribute("src", "http://dhtmlnirvana.com/");
ifrm.style.width = 640+"px";
ifrm.style.height = 480+"px";
document.body.appendChild(ifrm);
}
</script>
</head>
<body bgcolor="#000000">
<p><a href="#" onMouseDown="makeFrame()"> Lets make an iframe </a></p>
</body>
</html>
appendChild()
The DOM node method appendChild() is something we have not covered as yet, so lets try and understand its purpose. The purpose of this node method is to give the IFrame a place to reside in the document.
document.body.appendChild(ifrm);
If we follow the logic of the above line of script from a layman’s perspective, this line translates into find the body of the document and place the IFrame in the body. The body is actually a node within the html document so it is important to retrieve it, because this is where all our elements will be displayed.
CSS Dynamic Manipulation
One of the more functional abilities of the new generation browsers is the ability to dynamically manipulate CSS properties by utilizing the DOM. It is just cause to celebrate, because it eases the burden for web developers in a number of ways. Instead of having to use workarounds like document.write to modify CSS properties, finally we can use a standard way of coding that works in 5th generation browsers and above.
Lets begin by exploring a few text effects. First cab of the rank is the ability to dynamically alter letter spacing.
<script language="JavaScript" type="text/javascript">
function spaceLetter(id, amount) {
document.getElementById(id).style.letterSpacing = amount;
}
</script>
We begin by creating a function spaceLetter() and use two arguments id and amount, which we can then use to define attributes later at the event handler point. The id argument is used in what should now be the familiar document.getElementById(). Then we script the wordSpacing style and give it the same value as our second argument amount.
document.getElementById(id).style.letterSpacing = amount;
This function is then called from an event handler which allows for the manipulation of any elements letter spacing by identifying what the id is ( in this case contentLayer) and the amount that the letters should be spaced to (in this instance 8 ).
<a href="javascript:" onMouseOver="spaceLetter('contentLayer','8')"> Space the Letters </a>
Here is a complete working example to work from:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Letter Spacing Example</title>
<script language="JavaScript" type="text/javascript">
function spaceLetter(id, amount) {
document.getElementById(id).style.letterSpacing = amount;
}
</script>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<a href="javascript:" onMouseOver="spaceLetter('contentLayer','8')"
onMouseOut="spaceLetter('contentLayer','1')"> Space the Letters </a>
<div id="contentLayer" style="position:absolute; width:470px; height:39px; z-index:1;
left: 33px; top: 57px; visibility: visible">DHTML
NIRVANA </div>
</body>
</html>
The same type of scripting method can be applied to many CSS properties. For example, let us suppose we want to dynamically alter the font face, we could use the following script:
<script language="JavaScript" type="text/javascript">
function fontName(id,fontName) {
document.getElementById(id).style.fontFamily = fontName;
}
</script>
and use the following at the event handler point.
<a href="javascript:" onMouseOver="fontName('contentLayer','Verdana')"
onMouseOut="fontName('contentLayer','Courier')"> Change The Font </a>
or if we wanted to dynamically alter a fonts color we could use
<script language="JavaScript" type="text/javascript">
function fontColor(id,color) {
document.getElementById(id).style.color = color;
}
</script>
I think you get the idea. We can of course do a whole lot more than just play around with fonts and that’s what makes coding for the newer generation browsers both intriguing and fun. There are many instances where we do not have to use JavaScript but can just use CSS declarations. Let us imagine we wanted to add OS scroll bars to a <p> element in Internet Explorer 5+ and Netscape 6.
All we need to do is redefine the tag via a CSS declaration as shown below and the <p> tag takes on scrollbars:
<style type="text/css">
p {display: block; overflow: scroll; font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12px; position: absolute; height: 100px; width: 200px; left: 400px; top: 10px}
</style>
Object Constructors
Thus far we have focused upon standalone examples to highlight a few of the things that can be achieved by using standards based coding. While useful to illustrate some of the potential of the new generation browsers, in practical web page building terms there are even more useful techniques that can be applied to web page building.
As a way of introduction to more comprehensive articles focused on DOM based web page building techniques, let us take a look at a couple of the primary techniques I often use when building Dynamic HTML web pages.
These techniques include the following:
· Object Constructors
· Object Orientated Browser Sniffer
· Positioning Layers By Browser Dimensions.
Let’s Get Going: In another article at webreference I demonstrated how to dynamically resize images. In keeping with the notion of creating liquid web pages that dynamically accommodate different browser dimensions, let us utilize this opportunity to build on that previous article and demonstrate how to position layers by browser dimensions from a DOM based coding perspective. Specifically, let us learn how to dynamically center a layer across varying browser sizes.
First off our browser sniffer script:
function Is() {
agent = navigator.userAgent.toLowerCase();
this.major = parseInt(navigator.appVersion);
this.minor = parseFloat(navigator.appVersion);
this.ns = ((agent.indexOf('mozilla') != -1) &&
((agent.indexOf('spoofer') == -1) && (agent.indexOf('compatible') == -1)));
this.ns4 = (this.ns && (this.major == 4));
this.ns6 = (this.ns && (this.major >= 5));
this.ie = (agent.indexOf("msie") != -1);
this.ie3 = (this.ie && (this.major < 4));
this.ie4 = (this.ie && (this.major == 4) && (agent.indexOf("msie 5.0") == -1));
this.ie5 = (this.ie && (this.major == 4) && (agent.indexOf("msie 5.0") != -1));
this.ie55 = (this.ie && (this.major == 4) && (agent.indexOf("msie 5.5") != -1));
this.ie6 = (this.ie && (agent.indexOf("msie 6.0")!=-1) );
}
var is = new Is();
The purpose of this script is to be able to detect which browser the client is using. In reality, we could use direct object detection here, instead of browser detection, but in many instances, object detection is not strict enough, particularly if we want to build a complex backward compatible web page or at a minimum redirect users to an alternate page or pass an alert.
The browser sniffer is composed of JavaScript objects that converts the user agent string into an object to use later in the script as a variable by using the var is = new Is(); statement . As long as the variable is associated with the correct user agent string, we should not run into many problems.
From the browser sniffer script we need to use the 6 variables that cover the major DHTML capable browsers: is.ns4, is.ns6, is.ie4, is.ie5, is.ie55 and is.ie6. The easiest way to understand these variables is to think of them as taking the form of a question posed to the browser.
if (is.ie5|| is.ie55|| is.ie6|| is.ns6){
do the script here
Asks the question is this either Internet Explorer 5 and above or alternatively Netscape 6. If the answer to the question is yes, then run this portion of the script. Since this condition forms the basis of coding for the W3C DOM where ever possible it takes priority in the conditional logic. If the answer is no, then go to the next question and see if the answer is yes.
} else if(is.ie4) {
do the script here
Asks the question is this Internet Explorer 4. As before, if the answer to the question is yes then run this portion of the script, if the answer is no then go to the next question.
} else if(is.ns4) {
do the script here
We could also build in other variables, which detect for Opera, WebTV and so on and could either redirect users to an alternate page or pass an alert.
Object Constructors: Having worked our way through the basic premise of detection routines and if/else statements, lets begin to build our JavaScript object construction routine. The purpose of this section of the script is to convert CSS layers into JavaScript objects that can be easily dynamically manipulated later on in the scripting routine.
function layerObject(id,position,left,top,visibility) {
if (is.ie5|| is.ie55||is.ie6|| is.ns6){
this.obj = document.getElementById(id).style;
this.obj.position = position;
this.obj.left = left;
this.obj.top = top;
this.obj.visibility = visibility;
return this.obj;
}
}
The script is dedicated to creating attributes for JavaScript objects. A good way to think of this is to conceptualize a CSS layer written in the body section of your document, note how the initial positioning is set to 0 and visibility to hidden. Later on we will dynamically position the layer and also toggle its visibility to visible.
<div id="centerLayer" style="position: absolute; width:200px; height:24px; left: 0px; top: 0px; z-index: 6; visibility: hidden;"></div>
You will notice that in the div tag we have an id attribute. Similarly, in our layer object we also assign an id attribute. The reasoning behind this is that what we are attempting to achieve is a JavaScript replication of the CSS layer attributes. Following this course of logic, we then assign more CSS layer attributes to the layerObject script. We assign, position, top, left and visibility. More attributes could be assigned as needed, for instance we could include z-index, height and width and so on. The object constructor can become very detailed and thus ideally open itself to a myriad of dynamic manipulations. Indeed in later articles, we will be utilizing object constructors a fair bit, so it is important to understand the basic premise of what these allow us to do. For the purposes of this article, lets stick with just a couple of basic attributes to get accustomed to the concepts presented here.
It is important to note, that in reality our object constructor has not really created anything. All we have done is prepared our documents for the creation of new layer objects. Therefore, we need to focus our attention on actually creating new layer objects. This is achieved with the layerSetup() script.
function layerSetup() {
centerLyr=new layerObject('centerLayer','absolute',page_width/2-100,page_height/2-12,'visible')
}
The first line defines the functions name. The second line does quite a few things so lets pull it apart to better understand it.
We create a new variable centerLyr and tell the browser that it equals a new layerObject(). The sole purpose of this section of the JavaScript statement is to hook back into our layerObject() script so that we can then assign the specific values needed for that particular layer. You can identify the attribute value that belongs to layerObject() properties by looking at the following table.
| Function Name | ID Property | Position Property | Left Property | Top Property | Visibility Property |
| LayerObject | id | position | left | top | visibility |
| LayerSetup | centerLayer | absolute | page_width/2-100 | page_height/2-12 | visible |
The upshot of this little piece of scripting is that we end up with a new JavaScript object called centerLayer which has the CSS attributes of positioning, left, top, and visibility assigned to it. From a scripting perspective this is enormously useful because if we so wished we can then manipulate any of the CSS properties as we shall see later on in this article.
Capturing Browser Dimensions
Let’s get back to positioning our layers by browser dimensions. You will note that instead of assigning a numeric value to the left and top attributes of the new layer object, page_width and page_height are used. These are variables created and set at the onLoad event handler:
onLoad="
if(is.ns6) {
page_width=innerWidth;
page_height=innerHeight;
layerSetup();
} else if(is.ie5 || is.ie55||is.ie6) {
page_width=document.body.clientWidth;
page_height=document.body.clientHeight;
layerSetup();
}"
Once again we need to create a little cross browser and backward compatible DOM switch. Netscape 4 and Netscape 6 use innerWidth and InnerHeight to detect a users screen resolution. Therefore, we create a browser detection condition.
if(is.ns6) {
if this condition holds true then the variables page_width and page_height are assigned the correct DOM method for Netscape 6 and the layerSetup() script is triggered.
page_width=innerWidth; page_height=innerHeight; layerSetup();
If the condition is not true then attention is focused on the Internet explorer part of the script and the DOM for those browsers is utilized.
} else if(is.ie5 || is.ie55 || is.ie6) {
page_width=document.body.clientWidth;
page_height=document.body.clientHeight;
layerSetup();
}"
Understanding Positioning
Having captured a users browsers page dimensions we can then use the newly formed variables to position the layer by those dimensions. Hence, the values of page_width/2-100, page_height/2, in the layerSetup() script. To determine the meaning of these values, lets think about this in a different way. The value page_width/2-100 literally stands for the browser size divided by 2 and minus 100 pixels from the left edge of the browser.
Dividing the browser size by half, centers the layer. However, its positioning is determined by the top left corner of the layer, something that many people often overlook. Therefore, if the content of the layer is sufficiently wide enough, then the layer displays as not being centered. To overcome this we need to take into consideration the layer width. In this instance, the CSS layer centerLayer width is 200 pixels. We halve that, and recognize that for it to appear centered, we need to move it over to the left by 100 pixels. Hence the -100 in the left value. The same logic is applied to top attribute where the browsers height is divided into half and then the layers height is taken into account.
Let’s look at the completed web page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>How to Center A Layer</title>
<script>
function Is() {
agent = navigator.userAgent.toLowerCase();
this.major = parseInt(navigator.appVersion);
this.minor = parseFloat(navigator.appVersion);
this.ns = ((agent.indexOf('mozilla') != -1) &&
((agent.indexOf('spoofer') == -1) && (agent.indexOf('compatible') == -1)));
this.ns4 = (this.ns && (this.major == 4));
this.ns6 = (this.ns && (this.major >= 5));
this.ie = (agent.indexOf("msie") != -1);
this.ie3 = (this.ie && (this.major < 4));
this.ie4 = (this.ie && (this.major == 4) && (agent.indexOf("msie 5.0") == -1));
this.ie5 = (this.ie && (this.major == 4) && (agent.indexOf("msie 5.0") != -1));
this.ie55 = (this.ie && (this.major == 4) && (agent.indexOf("msie 5.5") != -1));
this.ie6 = (this.ie && (agent.indexOf("msie 6.0")!=-1) );
}
var is = new Is();
function layerObject(id,position,left,top,visibility) {
if (is.ie5|| is.ie55||is.ie6|| is.ns6){
this.obj = document.getElementById(id).style;
this.obj.position = position;
this.obj.left = left;
this.obj.top = top;
this.obj.visibility = visibility;
return this.obj;
}
}
function layerSetup() {
centerLyr=new layerObject('centerLayer','absolute',page_width/2-100,page_height/2-12,'visible');
}
</script>
<style type="text/css">
<!--
.main {
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 16px;
color: #FBEED5;
text-decoration: none
}
-->
</style>
</head>
<body bgcolor="#999999" onLoad="
if(is.ns6) {
page_width=innerWidth;
page_height=innerHeight;
layerSetup();
} else if(is.ie5 || is.ie55 ||is.ie6) {
page_width=document.body.clientWidth;
page_height=document.body.clientHeight;
layerSetup();
}"
onResize=" history.go(0); ">
<div id="centerLayer" style="position: absolute; width:200px;
height:24px; left: 0px; top: 0px; z-index: 6; visibility: hidden;">
<span class="main">This is a Layer Centered By Screen Resolution</span>
</div>
</body>
</html>
In a sense, a one CSS layer example doesn’t really do justice to the power of using object constructors, because one of the real advantages of using them is code reduction, especially when there are lots of CSS layers used in a web page. It also does not adequately demonstrate the flexibility of object constructors as they can be used with a wide range of purposes in mind. Despite the shortcomings of the above example, it does introduce the notion of object constructors with regards to coding by a singular standard.
Armed with the concepts presented in this article and what is yet to come in future articles, it is my sincere hope that this will prepare web developers for the next generation of scripting techniques.
For more information about these concepts read the DHTML Library tutorial on this site. It has a different but similar approach.