As remarked earlier, even simple style changes in an HTML document can cause the current layout of a document to be disturbed. Thus most style changes aren't possible in Navigator 4.0, and in Internet Explorer 4.0 they cause the browser to automatically reflow as a result. For small changes, like expanding text by increasing its font size, this latter possibility is a useful but trivial feature. However, it can be exploited more thoroughly for good effect.
The most obvious example of this effect is collapsing menus, such as you might find in the Apple Macintosh's Finder, or in the Windows Explorer utility of Microsoft Windows. Using the innerHTML
and outerHTML
properties discussed earlier, this is fairly straightforward to achieve. This example is Internet Explorer 4.0 only:
<HTML><HEAD><SCRIPT>
var hairy_exposed = false;
var scaly_exposed = false;
var bugs_exposed = false;
function show_details(obj)
{
if ( eval(obj.id+"_exposed" ) == false ) // show the exploded list
{
obj.innerHTML = document.all[obj.id+"_list"].innerHTML;
eval(obj.id+"_exposed=true");
}
else // collapse the list
{
obj.children[0].outerHTML='';
eval(obj.id+"_exposed=false");
}
}
</SCRIPT></HEAD><BODY>
<DIV ID="hairy_list" STYLE="display: none">
<UL> <LI> Mammals <LI> Marsupials <LI> Monotremes </UL>
</DIV>
<DIV ID="scaly_list" STYLE="display: none">
<UL> <LI> Fish <LI> Reptiles <LI> Birds .. sort of </UL>
</DIV>
<DIV ID="bugs_list" STYLE="display: none">
<UL> <LI> Creepy crawlies <LI> Stinging things
<LI> Slugs and stuff <LI> Ugh - Germs </UL>
</DIV>
<H2> Amateur's guide to the animal kingdom</H2>
<UL>
<LI ID="hairy" ONCLICK="show_details(this)">Hairy things</LI>
<LI ID="scaly" ONCLICK="show_details(this)">Scaly things</LI>
<LI ID="bugs" ONCLICK="show_details(this)">Bugs</LI>
</UL></BODY></HTML>
In this example, the three <DIV>
elements are just invisible storage areas for HTML used as replacement text later, hence the 'display: none" style information. You could just as easily store the HTML in plain JavaScript strings, but that's very cumbersome to type in. Since the <DIV>
tags appear as objects in the DOM hierarchy, access to their original HTML is as easy (or easier in this case) as literal strings. When the user clicks on the line items, they get an expanded, two level view for that item. Note the careful use of innerHTML
and outerHTML
to make this happen.
However, this example has a problem. When you replace one tag's contents with another, you lose the original contents. In this example, the main headings disappear forever, even though their bullet-points remain. The script could save the old values somewhere and replace them later, but there is a better way.
Each tag object supports an insertAdjacentHTML()
method. This method allows new content to be slipped into the document before or after the tag of the current tag object. It takes two arguments: a special keyword indicating exactly where to insert ("BeforeBegin
", "AfterBegin
", "BeforeEnd
", "AfterEnd
"), and the HTML content to insert. As for the innerHTML
/innerText
pair of properties, there is also an insertAdjacentText()
method. To fix the behavior of the above example, replace the first branch of the 'if'
statement with these statements:
obj.insertAdjacentHTML("BeforeEnd", document.all[obj.id+"_list"].innerHTML);
eval(obj.id+"_exposed=true");
These features provide a flexible way to manipulate the document's source. They rely on some knowledge of the document's current structure in order to identify the bits that are of interest. Browser users, on the other hand, aren't encumbered with structured views of HTML. When a browser user selects part of a document in a browser window by dragging and highlighting with the mouse, any amount of content might be selected. The user doesn't care where tag boundaries might lie. To handle that behavior, Internet Explorer 4.0 supports a special TextRange
object. TextRange
objects require a bit of study before you can exploit them usefully, so their features are left to books more closely focussed on dynamic HTML.