Programming Languages
What is DHTML?
Dynamic HTML refers to new HTML extensions that will enable a Web page to react to user input without sending requests to the Web server. Microsoft and Netscape have submitted competing Dynamic HTML proposals to W3C (Short for World Wide Web Consortium, an international consortium of companies involved with the Internet and the Web. The W3C was founded in 1994 by Tim Berners-Lee, the original architect of the World Wide Web. The organization's purpose is to develop open standard so that the Web evolves in a single direction rather than being splintered among competing factions.
Tips
Check for Objects
You should try to put your DHTML inside some kind of a JavaScript browser check that runs the DHTML script only if the browser can understand it. One way to do this is to detect if a browser supports a given method or property, a trick detailed in Builder.com's SuperScripter column. Basically, before trying to use a method or property, you simply put in some sort of if statement that first checks to see whether the element exists, like so:
if (window.focus) {
popupWin.focus();
}
The advantage to this approach is that you don't have to worry about version changes. Either a particular browser supports the element or it doesn't.
However, sometimes you may want to check the browser and version using traditional JavaScript methods. This technique is useful when you're interested in checking for broad support, such as whether the script is running on a 3.x, 4.x, or 5.x browser. It's also useful for dealing with specific situations where Navigator and Internet Explorer require different code to perform the same action.
Detecting the specific browser also lets you code the same function slightly differently for Internet Explorer or Navigator. For example, IE uses myElement.style.visibility = "hidden" to make an element invisible, while Navigator uses myElement.visibility = "hide".
Replacing Custom Controls with DHTML
DHTML provides everything you need to generate animated effects without resorting to custom controls. For example, consider the following script, which is a replacement for the Path control.
var tickDuration;
tickDuration = 50;
var activeObjectCount;
var activeObjects;
var itemDeactivated;
var tickGeneration;
activeObjects = new Array();
activeObjectCount = 0;
timerRefcount = 0;
itemDeactivated = false;
tickGeneration = 0;
function initializePath(e) {
e.waypointX = new Array();
e.waypointY = new Array();
e.duration = new Array();
}
function addWaypoint(e, number, x, y, duration) {
e.waypointX[number] = x;
e.waypointY[number] = y;
e.duration[number] = duration;
}
function compact() {
var i, n, c;
n = new Array();
c = 0;
itemDeactivated = false;
for (i=0; i<activeObjectCount; i++) {
if (activeObjects[i].active == true) {
n[c] = activeObjects[i];
c++;
}
}
activeObjects = n;
activeObjectCount = c;
}
function tick(generation) {
if (generation < tickGeneration) {
// alert("Error "+generation);
return;
}
//alert("tick: "+generation);
if (itemDeactivated)
compact();
if (activeObjectCount == 0) {
return;
}
else {
for (i=0; i<activeObjectCount; i++) {
moveElement(activeObjects[i]);
}
window.setTimeout("tick("+generation+");", tickDuration);
}
}
function start(e) {
if (itemDeactivated)
compact();
activeObjects[activeObjectCount] = e;
activeObjectCount++;
if (activeObjectCount == 1) {
tickGeneration++;
tick(tickGeneration);
}
}
function runWaypoint(e, startPoint, endPoint) {
var startX, startY, endX, endY, duration;
if (e.waypointX == null)
return;
startX = e.waypointX[startPoint];
startY = e.waypointY[startPoint];
endX = e.waypointX[endPoint];
endY = e.waypointY[endPoint];
duration = e.duration[endPoint];
e.ticks = duration / tickDuration;
e.endPoint = endPoint;
e.active = true;
e.currTick = 0;
e.dx = (endX - startX) / e.ticks;
e.dy = (endY - startY) / e.ticks;
e.style.posLeft = startX;
e.style.posTop = startY;
start(e);
}
function moveElement(e) {
e.style.posLeft += e.dx;
e.style.posTop += e.dy;
e.currTick++;
if (e.currTick > e.ticks) {
e.active = false;
itemDeactivated = true;
if (e.onpathcomplete != null) {
window.pathElement = e;
e.onpathcomplete()
}
}
}
To use this script in your document, do the following:
- Load the script using the src attribute of the script element.
- Initialize the paths using the initializePath function.
- Set the way points using the addWaypoint function.
- Set the path-complete handlers using the runWaypoint function.
The following sample document shows how this works.
<html>
<body>
<div id=Item1 style="position: absolute; left: 0; top: 0;">Item1</div>
<div id=Item2 style="position: absolute; left: 0; top: 0;">Item2</div>
<div id=Item3 style="position: absolute; left: 0; top: 0;">Item3</div>
<div id=Item4 style="position: absolute; left: 0; top: 0;">Item4</div>
<div id=Item5 style="position: absolute; left: 0; top: 0;">Item5</div>
<div id=Item6 style="position: absolute; left: 0; top: 0;">Item6</div>
<input type=button value="Start" onclick="runWaypoint(Item1, 0, 1); runWaypoint(Item2, 0, 1);">
<div id=Debug>Generation</div>
<script src="htmlpath.js">
</script>
<script>
// need to call initializePath on all objects that will be moved with this mechanism
initializePath(Item1);
initializePath(Item2);
initializePath(Item3);
initializePath(Item4);
initializePath(Item5);
initializePath(Item6);
// the 0th waypoint is the initial position for waypoint #1
// syntax is item, waypoint, endx, endy, duration in msecs
addWaypoint(Item1, 0, 0, 0, 0);
addWaypoint(Item1, 1, 200, 200, 2000);
addWaypoint(Item2, 0, 100, 100, 0);
addWaypoint(Item2, 1, 400, 100, 4000);
addWaypoint(Item3, 0, 400, 400, 0);
addWaypoint(Item3, 1, 200, 100, 1000);
addWaypoint(Item4, 0, 0, 0, 0);
addWaypoint(Item4, 1, 200, 200, 2000);
addWaypoint(Item5, 0, 100, 100, 0);
addWaypoint(Item5, 1, 400, 100, 4000);
addWaypoint(Item6, 0, 400, 400, 0);
addWaypoint(Item6, 1, 200, 100, 1000);
function endfunction() {
// syntax for runWaypoint is Item, start point, end point
runWaypoint(Item3, 0, 1);
runWaypoint(Item4, 0, 1);
runWaypoint(Item5, 0, 1);
runWaypoint(Item6, 0, 1);
}
function endfunction2() {
runWaypoint(Item1, 0, 1);
}
Item1.onpathcomplete = endfunction;
Item6.onpathcomplete = endfunction2;
</script>
</body>
</html>
Understanding the Version 4.0 DOMs
Both Internet Explorer and Navigator have a Document Object Model, which provides access to Web page elements through a scripting language such as JavaScript. The problem is that Navigator and IE have different object models. Significant compatibility issues have not yet beendocumented for 5.0 and later browsers, in part because of their relatively low market share. Until version 5.0 and 6.0 browsers gain more market share, it's important to understand how to work around the differences between majority leaders IE and Navigator version 4.0 DOMs and to create scripts that work for both.
IE 4.0 and later gives you scripting access to all HTML page elements, including style sheet properties. IE also reflects page elements as objects contained in a document.all collection, and it lets you access elements by index, name, or ID.
For example, you'd use the following code to write out the names of all tags on a page:
for (i=0; i < document.all.length; i++)
{
document.write(document.all[i].tagName + " ");
}
Try this code to access a tag by ID:
document.write("myLayer visibility is:" +
document.all['myLayer'].style.visibility);
Any changes to object properties appear on the page instantaneously. Netscape's model provides scripting access to specific collections of HTML page elements, such as layers on the page. The layer collection in Navigator includes areas bounded by a <LAYER> tag and areas positioned using Cascading Style Sheet (CSS) attributes. You can access elements accessed by index, name, or ID within those collections.
For example, you'd use the code below to write out the names of all layers:
for (i=0; i < document.layers.length; i++)
{
document.write(document.layers[i].name + " ");
}
This bit of code accesses a layer by ID:
document.write("myLayer visibility is:" +
document.layers['myLayer'].visibility);
As with IE 4.0 and later, Navigator instantaneously displays changes to layer position, visibility, and clipping on the page.
To access objects in either browser, you can create a reference variable that encapsulates the syntax for whichever browser the reader is using when the page is loaded.
if (navigator.appName == "Netscape") {
layerRef="document.layers";
styleRef="";
} else {
layerRef="document.all";
styleRef=".style";
}
By building references to objects this way, you can use one script in both browsers. For example, the code below tests the current visibility of an element named myLayer:
isVisible = eval(layerRef + '["myLayer"]' + styleRef + '.visibility');
Referencing Form Objects
In our previous tip, we mentioned the importance of enclosing form objects with the Form tag. In addition to ensuring that your form objects display properly in Internet Explorer and Netscape Navigator, we suggest that you name your form.
Naming your form makes it easy to use JavaScript to refer to the form and its objects. For example, if you place a text field named First_Name into a form with the name MyForm, you can refer to the value of the text field through the following line of JavaScript:window.document.MyForm.First_Name.value]
Canceling An Event
Irrevocably, when you script any user interaction into a DHTML document, you will direct the page to do something if a certain state is fulfilled and do nothing if that state is not fulfilled. For example, form validation requires your HTML document to check certain text fields for content. If the text fields contain content, submit the form. If the text fields are empty, display an error message and do not submit the form.
To accomplish this form submit cancellation, you must be certain to include the RETURN element in your event handler. To cancel an event properly, you must return the result of the confirmation question to the event. You do so by directing JavaScript to return True or False from the called event.
To illustrate how, let's walk through an example. Say we have a simple link. When the user clicks the link, we want to confirm that the user wants to go to the link source, which we can do by presenting a yes or no confirmation dialog box. To do this, place a function in the HEAD of the HTML document, like so:
<HEAD>
<SCRIPT LANGUAGE="JScript">
function AreYouSure()
{ return window.confirm ("Are you sure you wish to follow the
hyperlink? Click OK
to Continue or Cancel")
}
</SCRIPT>
</HEAD>
In our example, we've created an HTML page with a hyperlink. When the user clicks the link, we display a dialog box that request confirmation that the user wants to navigate to the link. If the user clicks OK, he or she continues to the link. If the user clicks Cancel, the mouse click action is canceled and nothing happens. In our previous tip, we explained how to add the AreYouSure confirmation JavaScript function to the HEAD of your HTML document. Today we'll cover how to trap when the user clicks the hyperlink and how to cancel the hyperlink.
After you create the HTML document and place the confirmation JavaScript function into the HEAD of the document, enter the following code as the HTML BODY. As you can see, the hyperlink's OnClick event is trapped and sent to the AreYouSure function. From that point on, the page waits for the user to make a yes or no decision. The decision is sent back to the OnClick event, which continues only if the user decision was true.
Use All-in-One Pages That Support Older Browsers
While 3.0 browsers combined capture barely 7 percent of the market, if you need to code for them you can. With some crafty coding you can build all-in-one pages that contain DHTML animation but also include HTML that older browsers can display correctly. This is especially useful for animation, since you don't lose any functionality when the older browsers ignore the DHTML code.
The secret is an intimate familiarity with HTML table layout. First you lay out the elements of your page with tables, just the way you normally would for a 3.0 browser. Then you surround each element (text or graphic) you want to animate with a <DIV> or <SPAN> tag that includes CSS-P positioning coordinates and z-index (layer) information.
Since the 3.0 browsers understand <DIV> and <SPAN>, there are two important points to take into consideration. First, it's probably better to use a <SPAN> tag because the <DIV> contains a paragraph return, which can push table elements apart. Second, if you need to align the object, the <DIV> or <SPAN> tag will override the alignment set in the <TD> tag. However, the alignment doesn't seem to visibly affect the actual DHTML animation.
Finally, write the JavaScript needed to animate these elements. The one restriction is that at the end of the animation, all the elements need to be in the same places on the page where they're located in the tables.The code would look something like this:
<TABLE border="1" width="200">
<TR>
<TD width="200" height="50" align="right" valign="top">
<DIV align="right" id="Layer1" style="position:absolute; width:200px; height:115px; z-index:1; left:25px; top:11px">
Animated flying text
</DIV>
</TD>
</TR>
</TABLE>
For 4.0 browsers, the DHTML code takes precedence over the HTML code, so the browser runs the animation and ignores the tables. Older browsers don't recognize the DHTML code, so they ignore it and instead read the HTML table code. This approach works with Netscape 3.0, Internet Explorer 3.0, and AOL 3.0, as well as old browsers that don't understand JavaScript.
The one problem comes with Netscape 2.0, which can generate error messages when it runs across newer JavaScript functions it doesn't understand. Remember to specify the JavaScript version and you should be able to avoid these problems.
Relative Positioning
You've seen how to position a <DIV> entity in relation to the top-left corner of the document-display portion of the browser window. It's also possible to use the position: relative style to move a <SPAN> element relative to a <DIV> element that contains it. Here's an example:
<HEAD>
<TITLE>Relative Positioning</TITLE>
</HEAD>
<DIV ID="absPos" STYLE="position:absolute; left:100; top:200">
This was positioned absolutely.
<SPAN ID="relPos" STYLE="position:relative; left:20; top:20">
This was positioned relatively.
</SPAN>
</DIV>
You see? The contents of the <DIV> element are moved 100 pixels from the left edge and 200 pixels from the top edge. But there's a <SPAN> element nested inside the <DIV>. Its boundaries start 20 pixels to the right of the left edge of the <DIV> element, and 20 pixels down from its top edge. The location of the <SPAN> element exists in relation to the <DIV> element only.
Setting a Background
As you probably know, you can specify an image to appear as a tillable background in a Web page. However, you may not know that DHTML and Cascading Style Sheets (CSS) allow you to set the position and repeat the pattern. To set an image, redefine the BODY tag like so:
BODY {
Background-image: url(bg.gif);
Backgournd-color:#FFFFFF;
Background-repeat: no-repeat
}
We discussed how to use DHTML to set the position and repeat the pattern of a background image. Unfortunately, setting these specifics for a background image is another inconsistency between browsers and browser versions.
Netscape Navigator 4 and varying iterations of Internet Explorer 4 do not allow you to customize background image position or repeat patterns. However, the latest version of Internet Explorer and the upcoming release of Netscape Navigator 6 do fully support this DHTML feature.
|
|||