Yankee Web Code- Run.dr(wot)

by Kenneth Tibbetts

Content and Control Call on Run.dr(wot) to create and insert new elements into the open document. While it is at it, the function allows you to set various style properties and html attributes, including event handlers. Run.dr(wot) requires only one argument, the tagName for the new element. The optional arguments are what make this guy a most valuable player.

Calling Run.dr(wot)

Arguments: 1 required. Any number of optional arguments

Returns: A reference to a newly created html element

Arguments:
Run.dr(tagname, reference element, id, text data, style, attributes, event handlers)

index required description type
(wot) [0] yes any html tagName, optional modifier string
[1] no reference element object or string
[2] no id string, '', or 'nxt'
[3] no textnode content string
[4] no className or styles string
[5] no styles or attributes string
[6] no event handler string or function
[7],[8]... no event handlers eval strings or functions

Run.dr(wot) uses the method document.createElement(wot) to create and return an html element with the tagName passed in wot.

There is only one required argument, the tag name of the new element. But there are several optional arguments that can be used to set attributes and properties of the new element.

You can use a series of calls to Run.dr(wot) to produce a webpage entirely from code, or you can build a button bar or a table or anything at all, and insert it in the open document wherever you wish. It is especially useful to add scriptable elements to an ordinary html page- the browsers that don't do the dom methods get a simpler, easy to digest page, and the new kids get the shiny new toys.

Run.dr(wot) can take a lot of arguments- in fact, you can tack on any number of eval statements as arguments. This doesn't make the function complicated or difficult to use. It does give you the ability to create exactly the elements you want, with the content, properties and attributes you want them to have.

You do need to put the arguments in the correct order, and insert empty strings as placeholders to skip  arguments. 



Run.dr(wot) source

Here is the source for Run.dr(wot), without comments. (Comments will follow).

function Run.dr(wot){

var a= arguments;

wot= wot.toLowerCase();

var Run.tagN= wot;



var ref= mr(a[1]) ;

var pa=ref;

if(ref && /_/.test(wot)){

pa= ref.parentNode;

Run.tagN= wot.slice(0,-3);

}

var El= document.createElement(Run.tagN);



if(pa){

if(pa== ref) pa.appendChild(El);

else {

(/_b4/.test(wot))? pa.insertBefore(El, ref) :

pa.replaceChild(El, ref);

}

}

if(a[2]){

El.id= (a[2] != 'nxt')? a[2] : Run.tagN+ '_' + (++nxt);

}

if(a[3]) {

El.appendChild(document.createTextNode(a[3]));

}

if(a[4]){

(/\:|\=/.test(a[4]) )? mrs(El,a[4]) :

El.setAttribute('className',a[4]);

}

if(a[5]) mrs(El, a[5]);



if(a.length>6 && typeof(doDr)=='function') doDr(El,a);



return El;

}

Calling Run.dr(wot)

The following snip appends a heading with a child text node to an existing div element ('div1'). The new heading is not assigned an id- a[2] is the empty string (''):

Run.dr('h3','div1','','Note This Heading:')

html equivilent: <h3>Note This Heading: </h3>

Note This Heading

If you want to assign style or html attributes to the new element you can pass more arguments.

This new h3 is created with an id, a text node, color and font style, and a title attribute:

Run.dr('h3','div1','h3Note','Note This Heading:',
'color:red;fontStyle:italic','title=DOM aware code');

html:<h3 id="h3Note" style="color:red; font-style:italic" title="DOM aware code">

Note this Heading </h3>

Note This Heading



It doesn't have to be a text element:

Run.dr('img','div1','','',
'src=img.gif; width=36px; height=36px; alt=my picture')

Run.dr('div','div1','div_new')

Run.dr('hr','div_new')



And if your element needs event handlers, they are passed at the end:

Run.dr('h3','page1', '','Heading','','title:click to display',Run.hot.setHot, Run.showNext);

In this case, Run.dr(wot) uses the functions Run.hot.setHot and Run.showNext to assign event handlers to the new h3 element. More on these functions, by and by.

Modified Wot

The first line of code in the function is just a device to reduce typing- I declare a local variable to be equal to the argument array.

var a= arguments;

If a[0] (a.k.a. wot) is an html tag name, and a[1] is an html element, the new element will be appended to the existing (reference) element:

Run.dr('p','div1')  

A new paragraph element becomes the new lastChild of the element having the id 'div1'.

Sometimes that's not what you want. Maybe you want to insert a new paragraph at the beginning of a div, or just before the third h1 element. I use a modifier in the first argument to signal this.

Add the string '_b4' to the tagName: 'p_b4' or 'h1_b4'. This uses the method insertBefore:

parent_element.insertBefore(new_element, existing_ element).

Make sure that a[1] names the element marking the place in the document you are aiming at, and Run.dr(wot) will insert the p or h1 in the correct place:

Run.dr('h1_b4','div1').

Similarly, if you append '_rp' to the tagName in wot, 'p_rp' or 'h1_rp', Run.dr(wot) will replace the named element in the document with the new element. If you use either modifier, you must pass an element reference in a[1]:

Run.dr('p_rp','div1').

This uses:

parent_element.replaceChild(new_element, existing_ element).

 

I sometimes create elements that are not instantiated right away.

Passing the empty string in the second argument (a[1]) returns an element to the calling function without changing the open document:

var newElement=Run.dr('h3','','h3Note','Note:','color:red');

When it is needed, a direct use of appendChild, insertBefore or replaceChild will put the element in play.

What? Where?

Let's run through the code. The first half of the function determines what kind of element to create, and where to put it in the document. The rest of the function sets various attributes and property values for the new element.

The optional second argument, a[1], is a string id or an object reference to an element. It is identified by our friend mr(hoo). If a[1] is the empty string, an element will be created with whatever content and attributes the rest of the arguments supply, but it will not be added to the document. The return value of the function hands the new element to the calling function to be dealt with.

If there is a reference element in a[1] and no modifier to wot, the new element will be appended to the reference element, as its last child. And if there is a modifier to wot, the new element will be inserted in the document at the point determined by the modifier and the reference element.

The local variable declarations determine the tagName and the reference element and parentNode for the new element's insertion into the document:

var Run.tagN= wot;

var ref= mr(a[1]);

var pa=ref;

if(ref && /_/.test(wot)){

pa= ref.parentNode;

Run.tagN= wot.slice(0,-3);

}

If there was a modifier in wot, found by testing for the underline ('_') character, pa is set to the parentNode of ref, and Run.tagN becomes the valid tagName portion of the wot argument (by slicing off the modifier string).

var El= document.createElement(Run.tagN);

whatever else happens, an element is created.

if(pa){

if(pa== ref) pa.appendChild(El);

else {

(/_b4/.test(wot)) pa.insertBefore(El, ref) :

pa.replaceChild(El, ref);

}

}

If a[1] exists and wot is not modified, the new element is appended to the ref element.

If there is a modifier, it is examined, and El is inserted accordingly.

Id and Text

The third possible argument to Run.dr(wot), a[2], is an id string. Sometimes you want it, sometimes not. Some of the code expects a string value, and if all you got is an object, you got problems.

Remember the global variable nxt? Here it is again... 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.

If you want to assign an id automatically, send the string 'nxt' for a[2]- a unique id of the form tagName+'_'+ (++nxt) will be assigned to the element: 'p_11' or 'span_15'.

if(a[2]){

El.id= (a[2] != 'nxt') a[2] : Run.tagN+ '_' + (++nxt);

}

The fourth possible argument, a[3], is a string, or something that evaluates to a string, that will become the text content of the element. Note that if you are adding a text node the element you are creating must support it. You cannot add a text node to a <br> or <img> element, for example.

The text can be a literal string for a button or a short heading, or it can be a long involved paragraph, defined elsewhere. It is the data value for a single textNode.

if(a[3]) {

El.appendChild(document.createTextNode(a[3]));

}

Style and Attributes

The next two arguments, if they exist, are used to set special styles and html attributes for the element.

I'll show how this all actually works when we get to the discussion of the function Run.mrs(). Briefly stated, the job of Run.mrs() is to set particular style properties and html attributes of an element to specified values.

If a[4] or a[5] is a string of style properties and values, each style property will be set to its value. Use the same syntax you would in a stylesheet or inline style declaration, but remember to convert hyphenated names to mixed case:font-size must be fontSize, border-width-left is borderWidthLeft.

For example: 'fontSize:large; fontWeight:bold; textAlign:right'.

When you are setting html attribute values, remember that you are working in a string, and don't need additional quotes for the values: 'src=../img.gif; width=36px; height=36px'.

Style property names and values are separated by colons, attribute names and values by equals signs. Both cases split the pairs on semicolons. You can use spaces between the pairs for readability, but don't include a trailing space at the end of the string. And if a[4] consists of a string that is not a name-value pair ( no colon or equals sign) treat it as a className.

if(a[4]){

(/\:|\=/.test(a[4]) )? mrs(El,a[4]) :

El.setAttribute('className',a[4]);

}

Pass the argument to mrs if the string has name/value pairs, or set a className.

The next line allows for more assignments. Sometimes it can be awkward for one argument to handle a lot of these, especially if they are being generated based on some changing conditions. You don't always need either of these two arguments, but they can be very helpful.

if(a[5]) mrs(El, a[5]);

Run.dr('a','page1','','Home', 'biglinkClass', 'href=../index.html, 'title=home page');

The Main Event

At this point you have created an element, inserted it at an appropriate place in the document, and assigned it any content, style properties and html attributes that you desire. Not bad... Often, that is all you need. Assigning event handlers to your new element can be done after Run.dr(wot) returns:

var el= Run.dr('h3','page1','','Note:','color:red;fontSize:large;fontStyle:italic');

el.onmouseover=do_elHot;

el.onmouseout= do_elOff;

el.onclick= Run.showNext;

Nothing wrong with that. But we've come this far...If there are more than four arguments, Run.dr(wot) passes the new element and the arguments array to another helper, Run.do_Run.dr(). Run.do_Run.dr() is in charge of assigning event handlers wholesale.

Just as a website needs to have a consistent style in terms of appearance and layout, its usability is vastly improved if it has a consistent style of event handling. The visitor should not have to begin a new learning curve with every page loading in his browser. 

Having a central event handling control is as useful as using a stylesheet to maintain page layouts. This is as individual as a web's stylesheet, and I include one not to suggest it be used on anyone else's site, but to illustrate the idea. Note that Run.do_Run.dr() is a short bit of code that can be easily replaced from page to page by a more appropriate handler. Whatever Run.do_Run.dr() is gets the element and the argument list passed as parameters:

if(a[6]) Run.do_Run.dr(El, a);

Run.do_Run.dr()

I use doDr as a shortcut for assigning a couple of my most common handlers:

function Run.do_Run.dr(El,a){

var hoo=Run.hoozit(El);

Run.hoozit() finds the id of El, or assign a unique id if it has none. I'll have more on Run.hoozit(), by and by, but basically it tests for the presence of an id, and if there is none, works like passing 'nxt' to Run.dr(wot)'s third argument.

for (var i= 6; i< a.length; i++){

if(a[i]=='dh') Run.showHood(hoo);

else if(a [i]== 'sh') Run.hot.setHot(hoo, a[++i]);

else eval(a[i]);

}

}

Run.showHood, called when the string 'dh' is passed as an argument, adds the element to an array of "switchable" elements. These have the ability to be shown or hidden in various sequences and combinations. 

Run.hot.setHot, triggered by 'sh' , manages mouse events for the element- red on mouseover, for example. If Run.hot.setHot is called it means that the element is "clickable", and the next argument will supply the function that is called when the element is clicked.

I use these two guys extensively on the sites I design, often using Run.hot.setHot() to make a heading a clickable switch to display/hide a paragraph or div element, which is created with Run.showHood(). Run.showHood() puts the hidable element in an array, which enables 'expand' or 'print view' commands to switch on all the hidden elements at once. We'll get into the guts of these two functions later.

If neither string ('dh' or 'sh') is passed, doDr expects a string that will eval to something like the html event handlers listed at the beginning of this section.

And that brings us to the end of Run.dr(wot):

return El;

Run.dr(wot) returns El to the calling function and waits for the next order.

Finis

I could suppress all possible errors with try- catch routines, and I am sometimes tempted to do so, but it makes it so hard to debug...Here are the most common bug makers:

  1. wot must be either a real html tagName or a tagName with a modifier suffix. If there is a modifier, there must be an element as the reference in a[1].
  2. Watch your reference elements! You cannot insert a block level element between inline elements. If you try to append a block level element to an inline element, or a text node to an element that does not allow text, you will cause a type match error.( A heading to an image, or text to a <br />).
  3. If the reference element does not exist, the element will be created and returned, but not added to the document.
  4. If you use an existing id for a new element, neither of the elements with the id will throw events properly.
  5. In the string arguments for styles and attributes, a trailing space at the end of the string can prevent the value from being read correctly. Spaces between the names and values are OK, as are spaces after the delimiting semicolons. It's that last, extra space that bites you.

Them's the ones that get me. If you find other errors, drop me an e-mail and I'll pulverize 'em. I'll demolish 'em. I'll grind them up and feed them to the cat...

Next time: Run.mrs(hoo)- setting styles and attributes, wholesale

What Else?

    Code from the Yankee Webshop
  1. Practical Code
  2. A DOM Function Library
  3. mr(hoo)
  4. Run.dr(wot)
  5. Run.mrs(hoo)
  6. Run.doRight()
  7. Run.sayWhat()
  8. Run.zap()

Internet Resources:

e-mail: editor@yankeeweb.net

WebShop Privacy Policy