mrhoo.js is a library file built for document object scripting. It works
with html in the browsers that support, more or less, the document object
model. If a browser doesn't do the DOM, or has scripting turned off, the code
acts like Tar Baby: it just sits, and don't say nuffin. In fact, as we will see,
the source code can be downloaded only to the clients who support and request it.
I don't use scripts on every page, but when I do, mrhoo.js is usually the first included source file.This suggests a practical consideration. One of the tenets of a good webpage is that it loads quickly, and most people have a slow connection to the web. You have to make up your own mind for every page- is it worth loading this script? Is the return greater than the wait?
I work hard to keep the code tight. This is why I don't include comments in "live" code, which annoys some programmers, and gratifies others.
I'll begin these comments in the conventional way, with global variable declarations
I start with three global variables- a boolean, an integer, and an object. They appear before anything else:
var wait= false;
var nxt= 0;
var Memry= new Object();
You can examine wait and use it to control visual feedback- the cursor can be set to the system "wait" cursor, or a "hot" element can stay cool, or a message can be displayed.
nxt is an index for generating unique ids. It is a counter, a number value that is incremented and combined with some string of text, like a tagName, to provide a string value when you can't use an object reference- when you need a name for an object property, for instance. nxt is a player in the functions Run.dr(wot) and Run.hoozit(hoo), among others.
var temid=element.tagName.toLowerCase()+'_'+ (++nxt);
element.setAttribute('id',temid);
This generates ids like 'h1_1' and 'p_3'.
The only global variable I declare in my library code, besides nxt and wait, is Memry.
Global variables have a tendency to bite the hand that scripts them, but they are so darned handy to have around! The troubles arise when you add scripts to pages that already have scripts- are you changing the context or type of a global that is in play, or have you reset a value with a new declaration?
You need a strategy for global variables, both to avoid collisions and to have them at hand when needed. I like to combine scripts, and I write a lot of code. My practice is to put globals in a box, all of them in one box.
I call the box Memry, so in my code you will find lines like:
if(Memry.groupW) Run.mrs(groupW,'color:#ff0000')
This line checks to see if there is a groupW object in the Memry box. If there is such an object, it most likely will consist of an array of elements- headings or paragraphs or whatever I put in it. The array is passed to the function , who changes the color of each of the elements in groupW to red, in this example.
I use Memry for everything from property values to text content and tabular data. It is also used for timers and event handlers and error logs. If it can be declared, it will fit in Memry. Memry is a lot like the carpet bag that Felix the cat carries.
When you are using multiple windows or frames, it is becomes almost trivial to examine the separate Memry objects.
Another reason I use this system for variable management is the added scope it gives to the delete operator. If you declare your globals with the var keyword you cannot use delete to remove them. But you can always call
delete Memry.groupW
There are times when this is useful, as we shall see.
Now it's time to meet the functions.
mr(hoo) examines its argument and returns a reference to an html element.
| index | required | description | type |
|---|---|---|---|
| (hoo) [0] | yes | reference to or id of an html element | string or object |
if(!hoo) return false;
if(typeof(hoo)== 'string'){
return (document.getElementById(hoo))?
document.getElementById(hoo): false;
}
else if (typeof(hoo)== 'object'){
return (hoo.tagName)? hoo: false;
}
else return false;
}
mr(hoo) returns a reference to an html element in the current document.
Since you can dynamically add and remove elements at any time, it is easy to refer to an element that has not yet been created, or has already been used and discarded. mr(hoo) expects one argument, a string id or an object reference. It returns a reference to the element, or false if it doesn't exist.
if(!hoo) return false;
If you pass an argument that evaluates null or false the first line will return false.
Since javascript is a loosely typed language, the argument may be of any type.
if(typeof(hoo)== 'string'){
return (document.getElementById(hoo))?
document.getElementById(hoo): false;
}
If hoo is a string, the method document.getElementById(hoo) returns the
element that has the id- or false, if there is no element with the specified
id.
else if (typeof(hoo)=='object'){
return (hoo.tagName)? hoo: false;
}
The argument can be an object- document.body, or document.links[0], or
document.getElementsByTagName('p')[0]. To ensure that the object is an html
element, the function checks for a tagName attribute before returning.
else return false;
If the argument is neither fish nor fowl, neither a string or an object, mr(hoo) returns false. The last line is belt and suspender code. I don't expect to need it, but it provides symmetry, and makes the function a bit more self-documenting.
if(mr('pic1')) mr('pic1').src='newUrl.jpg';
The previous call changes the source of an image, if an image with the id ('pic1') exists in the document.
if(!mr('toolBar') buildToolBar();
This bit checks to see if there is an element with the id 'toolBar' in the document. If there is none, the buildToolBar function is called. Presumably buildToolBar will create the element, with the required id. The if statement will prevent it from being created more than once if the code is called again for some reason.
For instance, in an event handler, the first click of a button can create an element, and subsequent clicks can toggle its display on the page:
if(!mr('toolBar') buildToolBar();
(mr('toolBar').style.display!='block' )? mr('toolBar').style.display=
'block':
mr('toolBar').style.display= 'none';
This locution makes sure that mr('toolBar') initially has its display property set to 'block' .
Note that this code relies on a document object method to operate correctly. If I want to be able to get an element by its id in Navigator or IE4 I have to direct the specified browser to a vendor specific function that shuffles through layers or the document.all array.
I don't often use these anymore, having put my eggs in the document object basket. If a browser doesn't support the DOM I don't write much script for it.
If you want a more general script you can use something like this:
if(document.getElementById) return mr(hoo);
else if (document.all) return document.all[hoo];
else if (document.layers) return mrNav(hoo);
else return false;
}
Navigator will need its own branch (mrNav) to find who is hoo.
mr(hoo) is the most frequently called function in the code I write for html pages. Another valuable player is Run.dr(wot), who creates new elements in the current open document.