HierMenus CENTRAL: HierMenus In Progress. HierMenus 5.0 Release Notes (6/7) | WebReference

HierMenus CENTRAL: HierMenus In Progress. HierMenus 5.0 Release Notes (6/7)

To page 1To page 2To page 3To page 4To page 5current pageTo page 7
[previous] [next]

HierMenus 5.0: Developmental Considerations

For developers following along with the ongoing HM Development, a number of issues were raised in the creation of HM5 that may be of interest. Primary among these are the cross-frames specific issues of building the menus in the content frame (and especially the timing of this process), and the trapping and handling of access errors resulting from the Same-Origin policy. Some additional cross-browser implementation issues will round out our release notes for this version.

Loading the Menus

As noted earlier in this article, a key design goal of HM5 was to allow the script to be downloaded once and only once per frameset. Specifically, the script should be downloaded and implemented as part of the navigation page of the frameset, and not repeatedly downloaded with each new content page, in order to preserve this key advantage to using a frames-based design in the first place. For the initial load of the menus, we simply trap the onload handler of the frameset itself, which is supported in all HM-capable browsers. But what about when the content page changes? In order to display menus within the content frame, the menus themselves must be created and attached (using appendChild or some similar method) to the actual document in the content frame, so once the content page is changed the menus we've so carefully created are gone. So how do we know when to reload them?

It turns out there are three different methods utilized by HM to determine when to rebuild the menus in the content frame; four when you consider the differing methods used for different browsers.

1.) Monitor the load event of the content frame.

This ends up being the simplest and most efficient of all of our methods, as it allows us to know conclusively when a new page has been loaded into the content frame each time a new page is loaded. We can then use the firing of that event to tell us when it's time to rebuild the menus themselves in the content frame (assuming, of course, security checks on the content frame's document pass).

Netscape 4.x supports this event via its event registration methods:

HM_LoadElement.captureEvents(Event.LOAD);
HM_LoadElement.onload = HM_f_CheckFrameLoad;

And then:

function HM_f_CheckFrameLoad(e){
	if (e.target.name == HM_FramesMainFrameName){
		HM_f_FrameLoad();
		routeEvent(e);
	}
}

And later versions of Mozilla (1.1+), Netscape (7+) and Konqueror (3.0+) support the assignment of the frame onload via the standardized method:

var FrameEl=parent.document.getElementsByName(HM_FramesMainFrameName)[0];
FrameEl.addEventListener('load',HM_f_FrameLoad,false);
HM_FrameHasLoadHandler = true;

Internet Explorer, however, provides a very interesting case. Though we can retrieve the frame element itself via the same getElementsByName call above, setting its onload handler, either directly via FrameEl.onload= or via the Microsoft specific FrameEl.attachEvent() results not in the assignment of the frame load handler, but rather in the assignment of the frameset load handler. Yet, attaching a simple handler to the onload attribute of a frame tag verifies that both IE5.5 and IE6 will fire the load event with each swap of the content page!

For IE, therefore, we've resorted to the admittedly kludgey method of looking for something specifically triggered from a user supplied onload handler to tell us if such a handler is actually in use. If we see this "something," (in our case, the setting of a specific variable in the parent) then we know the handler actually exists and can latch on to it for further page swaps. The code we ask users to insert into their frame onload handlers is as follows:

onLoad="HM_UseFrameLoad=1;if(window.HM_f_LoadMenus)HM_f_LoadMenus();"

And the (condensed) version of the HM code used to "look" for this onload is:

if(!HM_LoadCheckDone) {
	if(parent.HM_UseFrameLoad) {
		HM_FrameHasLoadHandler = true;
		parent.HM_f_LoadMenus = HM_f_FrameLoad;
	}
	HM_LoadCheckDone = true;
}

Clearly not the prettiest thing in the world; but it works, and has the added advantage of working for any browser that supports frame loads regardless of their event handling methods.

2.) Check document.readyState.

For browsers that do not support frame loads but do support the document.readyState property (that's Internet Explorer 4.0/5.0, IE5.5+ without the onload kludge described above, and Opera 7+) this property is interrogated for the value complete before attempting to build menus in the content page.

3.) Hook timers to the page unload.

All other browsers use the clumsy method of setting timers that begin firing when the content page is unloaded and check for the presence (and accessibility) of the content page's document. As soon as the content document can be recovered (without any accessibility errors) and it appears to be a legitimate object, we begin the process of rebuilding the menus on the page. We also search the content page document for the existence of the last menu created on the previous page. If this menu exists, then the content page document we are looking at is not the newly loaded page; but instead is the existing page, which has not fully unloaded yet. In this case, we reset the timer and keep waiting.

Clearly this is the least-desirable option and is therefore saved for last, after the other two options have failed.

Handling Access Errors

When attempting to access or manipulate properties in another frame, there is always the possibility of triggering access errors as the result of the browser's Same-Origin policy (described more fully on an earlier page). Thus, error handlers must be put in place to examine these errors and return from them gracefully in the event they are encountered. Again, two methods were employed, depending on the browser version being used.

For later version browsers (all for which basic DOM processing is supported) the elegant try..catch structure is the way to go, as it allows us to localize the "security checking" of the target document via simple statements such as (line wrapped here for clarity):

function HM_f_DocumentCheck() {
 var ErrorFound = false;
 var theDocument = null;
 try{
  var TypeOfDocument = typeof(HM_MenusTarget.document);
  if((HM_IE||HM_Opera)&&(typeof(HM_MenusTarget.document) == "unknown")) 
    return false;
  if((HM_IE||HM_Opera)&&(HM_MenusTarget.document.readyState != "complete")) 
    return false;
  theDocument = ((HM_MenusTarget)&&(HM_MenusTarget.document)) ? 
                HM_MenusTarget.document : null;
  var DummyMenu = HM_MenusTarget.document.getElementById('HM_dummy_menu');
  if(theDocument) ErrorFound = false;
 }
 catch(e){
  ErrorFound = HM_f_PermissionDenied(e);
 }
 return (!ErrorFound);
}

The above contains a couple browser-specific workarounds to make sure that, if an error is indeed triggered, that it will be the access error (and not some other type of error report). For example, in Opera 7 it is enough to test for the typeof the target document to trigger an access error, hence that statement comes first. Additional checks are then made specifically for the document.readyState variable (for those browsers that support it) and the existence of the target document itself (for other browsers). Finally, since some Mozilla versions won't trigger an access error with any of the previous statements, a getElementById call is processed for a dummy menu item. We don't need the actual dummy menu itself (indeed, it doesn't exist), we only need to know that we can use the method. Once an error is found, it's passed to a specific function that will interrogate the error message and return true if it appears to be one related to permissions.

For earlier browsers, we're limited to hooking the onerror handler directly, interrogating the message provided to it, and returning true if a permission error is found and passing on the error handler to the original error handler (if there was one) if not. We are careful to return the value that is returned to us from the original error handler, so as to preserve its intentions.

On our final page of this release article, we take a quick look at some of the other specific cross-browser issues that surfaced during our HM5 development.

To page 1To page 2To page 3To page 4To page 5current pageTo page 7
[previous] [next]

Created: April 22, 2003
Revised: April 24, 2003

URL: http://www.webreference.com/dhtml/hiermenus/inprogress/2/6.html

Justtechjobs.comFind a programming school near you






Online Campus Both