|
home / bulletins / 3
HierMenus 5.0.1: Release Notes
D.M Ragle, May 29, 2003
Following a few weeks of real-world use, we're pleased to introduce the
first maintenance release for HM5. In this release, we correct a few Netscape 4 specific
problems, a scrolling menu bug in Internet Explorer, and a minor Opera 7 glitch with
the initial display of permanently displayed menus. In addition, we're introducing
two parameters with this version that provide you with new choices in regards to
scrolling menus.
As a reminder, though our release articles can be appreciated by and may
be useful to all DHTML developers and HierMenus fans, the HierMenus script itself is
a licensed product and its use on your site(s) requires a paid license agreement. Contact
Barry Pullen
or call him at (203) 662-2868 for further information (be sure to let him
know how you plan to use HierMenus and tell him a bit about your organization, as well).
Sample Pages
Our sample pages demonstrate both frames and non-frames
HierMenus displays. Each sample page opens in a new window.
IE Scrolling Bug
An HM bug was uncovered such that if you began scrolling a tall
menu and then moved the mouse over another menu (which itself was not
scrollable) while continuing to hold the mouse button down, (i.e., while dragging
the mouse) an error would occur. IE allows the mouseovers of the menus to be fired
even while the user is dragging the mouse. In HM, we've previously not correctly
accounted for this possibility, and assumed
in our main scrolling routines that the menu to be scrolled was the last one the
mouse had rolled over--that's the global variable HM_CurrentMenu within
the actual HM code. HM_CurrentMenu is set automatically whenever the
mouseover handler of a menu is fired, so when the mouse rolled off a
scrolling menu and onto another menu an error was triggered as HM attempted to
scroll the newly rolled over menu, even though that menu may not even
be scroll-capable!
In HM 5.0.1 we've corrected this bug by removing the scrolling
behavior's reliance on HM_CurrentMenu as the menu to be scrolled. Instead,
upon each entry to the main scrolling routines, a new variable, HM_ScrollMenu
is set to be the menu currently being scrolled:
// 5.01
function HM_f_StartScrollUp() {
HM_ScrollMenu=this.menu;
return this.menu.startScroll(true);
}
For later IE browsers, we also adjusted the DoWheelScroll handler
thus:
function HM_f_DoWheelScroll(){
if(!this.scrollbarsCreated) return;
var ScrollUp = (HM_MenusTarget.event.wheelDelta == 120);
// 5.01
HM_ScrollMenu = this;
...
Then, within the crucial DoScroll routine, we rely
not on HM_CurrentMenu but instead on our new HM_ScrollMenu:
// 5.01
// var ScrollEl = HM_CurrentMenu.scrollParent;
var ScrollEl = HM_ScrollMenu.scrollParent;
if(up){
ScrollEl.top += incr;
}
else{
ScrollEl.top -= incr;
}
// 5.01
// HM_CurrentMenu.checkScroll();
HM_ScrollMenu.checkScroll();
Finally, as an added safety measure, we automatically stop any
menu from scrolling when we roll over a menu other than the currently scrolling
menu:
// 5.01
if(HM_ScrollEnabled&&(HM_CurrentMenu!=HM_ScrollMenu))
HM_f_StopScroll();
Separate Scrolling Functions
The eagle-eyed among you may have noticed the new HM_f_StartScrollUp
function displayed above. We've decided to remove most of the function literals of
our code, including the handlers assigned to the scrollbars themselves as demonstrated
by this (line-wrapped) example:
// 5.01
// this.scrollbarTop.onmousedown =
function(){
HM_CurrentMenu=this.menu;
return this.menu.startScroll(true)};
Why we've decided to remove these relates to memory management within
the browser. In a nutshell, when defining a handler via a function literal in
this manner, the JavaScript interpreter must allocate memory to maintain the state of
the local variables put in place by the function in which the literals occur. Or in
other words, as our JavaScript text books remind us, nested JavaScript functions (and
function literals, when they appear within other functions, are treated as nested
functions in this regard) are scoped lexically, the variables that they
access contain the same values as they did when the function was originally
defined. If you need in depth information on this topic, you might want to
read through Timothée Groleau's great article
on the subject (hat tip: WebReference Update). Though written
specifically for ActionScript and Flash MX use, we found it to be informative from a
JavaScript perspective as well.
For a more immediate example, consider this code:
<script language="JavaScript1.2">
<!--
x=10;
y=20;
function someFunction(x,y) {
this.firstFunction=
function() {
var j=prompt("Enter x Variable Name:");
alert("inside x: "+eval(j));};
this.secondFunction=
function() {
var j=prompt("Enter y Variable Name:");
alert("inside y: "+eval(j));};
}
var newObj = new Object;
newObj.f=someFunction;
newObj.f(30,40);
var newObj2 = new Object;
newObj2.f=someFunction;
newObj2.f(50,60);
alert("outside x: "+x); // 10
alert("outside y: "+y); // 20
newObj.firstFunction(); // x=30
newObj.secondFunction(); // y=40
newObj2.firstFunction(); // x=50
newObj2.secondFunction(); // y=60
alert("outside x: "+x); // 10
alert("outside y: "+y); // 20
// -->
</script>
which is duplicated on this test page
for your review (opens in a new window, requires JavaScript1.2 or later capable browsers).
At first you will see the global variables x and y reported as 10
and 20, respectively. You will then be prompted to enter the variable name that
you wish to display from within the newObj.firstFunction function call. Entering a value of
x in the first prompt displays the value 30, and entering y
on the second displays 40, corresponding to the values passed to the function when
the function literals were assigned to firstFunction within the f function.
Again, entering x and y in the next two prompts results in displayed values
of 50 and 60, respectively.
Since the variable name is interpreted via an eval statement, there is no
way the JavaScript compiler could have known in advance that the local variables x and
y would be required of the inner functions; therefore, the interpreter must be saving
the values of all local variables in case they are needed by the function. These local variables
are saved each time the function literal is assigned to a new object.
Nested functions can be an elegant solution in many contexts, especially
if you need to refer to the "frozen" state of local variables at the point the functions are
actually defined. But in the case of HM, we've previously used our function
literals purely from a convenience standpoint and we didn't require them to actually refer
to the local variables. To avoid the additional memory consumption required by such
circumstances, we've moved each of our function literals into regular function
definitions and then assigned them to handlers in the more traditional manner.
In addition to the minor memory gains this tweak provides, we also save a
few bites of code; since the new HM_ScrollOver parameter (described on the next
page) requires that the scrolling handlers themselves be conditionally assigned within a
series of several statements. Using traditionally defined functions for this task prevents
us from having to reinsert the function literals in each of these statements. While we've
not encountered any problems in regards to our use of function literals in HM, it seems
prudent and safe to make this minor tweak.
While we're on the scrolling topic, let's now take a look at
the new menu scrolling parameters available in version
5.0.1.
  
[next]
|