Custom Web Software Development for the 21st CenturySM

PHP, SQLs, JavaScript, Ajax, HTML5, XHTML, & CSS3: Innovative Enterprise level Scripting for interactive sites, SaaS, & cross-platform desktop apps

UniDOM.js Write one JavaScript codeset for one DOM on all browsers

I’ve heard it said (or something similar by Manual Lemos and one of his guests in a podcast on JSClasses.org) There are JavaScript programmers and there are jQuery programmers, and one person is usually not both.  I say there are three different types of people developing websites: software-engineers, programmers, and code-monkeys.  The code-monkeys really have no personal interest in writing code, other than it’s their job.  They may be graphic artists, or maybe the advertising/social-networking professional for a business, or maybe just a teen building his/her own website for a band he/she plays in; whatever their motivation, they need dynamic and/or interactive HTML pages, and jQuery is a fantastic tool to help them create their vision without having to know (and almost daily keep up with) the many details regarding how to leverage the power of different browsers across different platforms, or worry about creating logic patterns that work without crashing or exposing vulnerabilities.  In other words, programming is not for everyone, but some web-developers still need to utilize scripting power.

Real programmers may go either way, and possibly even both: learning how to write code in pure JavaScript and/or learning how to leverage the power of one or more libraries like jQuery.  They write more complex code, going beyond what the already-available libraries alone can accomplish.  A true software engineer is a well-developed programmer who fully understands how to organize and structure a large set of code, and mold it into an application.  A software engineer (should/hopefully) creates a code-base and supporting file-structure that maximizes efficiency by minimizing file-size and using streamlined code.  Often it is found that common library files like jQuery do not have enough power in their functions, yet at the same time offer far more (and often redundant) functionality than is needed for the application being developed.  For the applications I’ve been developing, this is the case.  While I admire the “Sizzle” sub-component of jQuery (the part that allows you to query the DOM with CSS-like selectors), I generally find the greater jQuery package bloated and underpowered.  So I developed the UniDOM project.

There are two basic parts to the UniDOM code-base.  The first handles DOM “events,” and the second is a collection of methods for querying and working with the DOM.  And as promised in the headlines, UniDOM‘s addEventHandler() method allows a programmer to write one script code-set for all browsers, ¡including low-level event capturing!  Yes, that is correct: you may now create custom drag-and-drop code, for example, and not worry about having to write code for modern browsers as well as separate code for legacy versions of Microsoft’s Internet Exploder.  As a brief reminder, events are “captured” in the standard DOM by passing true as the final (3rd) argument to the standard addEventListener() method, whereas you must use the setCapture() method with Internet Exploder, and the two work very differently; so different that it is virtually, if not literally, impossible to write a “wrapper” method that can manage these two different approaches to “event capturing” on a low level.  Sure you might be able to write a simple drag-and-drop interface that will work cross-browser with HTML elements in a very specific and limited way.  I looked at that possibility and decided I didn’t even want to try.  UniDOM avoids that mess and simply “simulates” the capturing phase, and then if captured, by necessity the “bubbling” phase.  So you write your code as if it were for the standard DOM, and UniDOM does the rest!

UniDOM’s addEventHandler() method also offers high-end programming features such as different coding styles (functional, plus two Object-Oriented styles), and the ability to pass to your event handler functions an unlimited number of user arguments that are true function arguments, not just artificially-added Event object” properties.  UniDOM’s “power methods” take DOM queries to the next level, can do far more, and are more flexible than most other popular JavaScript libraries out there today.  Yet UniDOM’s ultra-lightweight commented code-base is around 1∕4 of jQuery’s, and still even less than the minimized version of jQuery.  Currently (autumn 2014) UniDOM minified and optimized is 30KB versus jQuery minified at 94KB — less than 1∕3 the size!  Taken together, all these features make UniDOM a formidable addition to any JavaScript toolkit library.  It’s true that jQuery has more features and is geared to more devices, operating systems, and browsers than UniDOM, but then not all projects are designed for a smartphone, or require auto-loading HTML subsections via “Ajax,” or animated pages, etc.  UniDOM takes a more modular approach to script libraries, leaving “Ajax” and animation to other code files, giving programmers and software engineers a scripting library that is more flexible yet specialized to need, to create new projects without being stuck inside the box.  UniDOM is not a replacement for jQuery, but it is also true that jQuery is not a replacement for UniDOM!  Although the jQuery slogan is write less, do more, as we will see, UniDOM can simplify scripting in ways that make the equivalent jQuery code seem like a short-story.

The secret behind UniDOM’s “power-methods” for working with the DOM lies not only in their acceptance of regular expressions, whereas for example jQuery only accepts strings:

// jQuery command:   $('.myRedFlowers, .myGreenFlowers, .myPurpleFlowers, .myOrangeFlowers, .myBlueFlowers, .myYellowFlowers, .myCyanFlowers').removeClass('.myRedFlowers, .myGreenFlowers, .myPurpleFlowers, .myOrangeFlowers, .myBlueFlowers, .myYellowFlowers, .myCyanFlowers'); // equivalent UniDOM command:   UniDOM.getElementsByClass(document.body, /\bmy(Red|Green|Purple|Orange|Blue|Yellow|Cyan)Flowers\b/ )._.removeClass( /\bmy.+Flowers\b/ ); // or maybe simply this UniDOM command:   UniDOM.getElementsByClass(document.body, /\bmy.+Flowers\b/ )._.removeClass( /\bmy.+Flowers\b/ );

UniDOM can also accept extremely complex “logic arrays,” whereas jQuery only allows simple “and/or” logic in query strings (the jQuery example above demonstrates logical “or”, and  $('.myPurpleFlowers.onBushes');  is an example of logical “and”).  “Logic arrays” are explained below in the section describing the UniDOM.has() method.  Since UniDOM can also gather document elements using user-defined callbacks, a programmer can write code that gathers callback functions from various different modules and plug-ins, arrange them in complex “logic arrays” and perform a dynamically-created query.  jQuery users are standing there with a blank look on their face… … …  Oh, but wait, can’t a jQuery “selector string” do complex queries very simply that would be more complex for UniDOM? 

$('#myGuitars .sixString:selected'); //jQuery // vs. UniDOM without a CSS-selector engine: UniDOM.getElementsbyClass(document.getElementById('myGuitars'), 'sixString')._.getSelected();

No problem!  Again, as we shall see, UniDOM can use various different selector engines, including the one that jQuery uses.

UniDOM is a lightweight hybrid of different approaches to cross-browser DOM compatibility and “power methods,” intended for use with applications to be inserted into larger projects, with a special focus on programmers’ tools with more flexibility and power, rather than myriads of shortcut methods for the less technically minded, many of which go unused; and with a focus on script readability and method names in the original spirit of JavaScript that allow the uninitiated to follow along at least somewhat (especially if they know JavaScript or another programming language) without having to guess or use a reference as to what each method is essentially trying to do, which allows you to write cross-application code that is more accessible to more people; and also with a focus on tools that allow developers to embrace the balance of:

UniDOM’s coding styles:

UniDOM offers 4 programming/coding styles, all possibly available at the same time.  Note the first two functional styles commonly require “passing in” the DOM Element to work with, while the last two Object-oriented styles are methods of a UniDOM.ElementWrapper, a UniDOM.ElementWrapperArray, or a native DOM Element, so you don’t “pass in” an Element, and therefore the Object-oriented methods take one less argument (sans the first one) than the equivalent functional.

Event handling with UniDOM

addEventHandler(element, eventType, handler[, useCapture [, userArg1 [, userArg2 … … …]]])

element *only when called as a functional
The DOM Element(s) to attach the event-handler to.  You may pass in a single Element, or a UniDOM ElementWrapper instance, or an array of Elements and/or ElementWrappers.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 2 arguments (plus any optional- & user-arguments), as the element is then figured by this method’s Object.
eventType
Event-types may be passed in with or without the prefixed “on” and are case-insensitive.  You may pass in a single event-type (as a String), or an array of event-types.  All event-types passed in will be “bound” to all elements passed in, and all event-handlers you pass in will be called upon by every one of these event-types.  Custom user-defined event types may be used.  With legacy versions of Micorsoft’s® Internet Exploder, since custom events can not be used as “listeners,” UniDOM keeps track of these and “manually fires” them using generateEvent.
handler
You may add a single event handler, or an array of event handlers (using one single call to addEventHandler()) to be called in order by the wrapper function.  That is, all handlers will be called by each eventType you add.  When you add [an] event handler[s], it/they is/are “wrapped” with an internal closure-function, and this wrapper is then the actual attached event handler.  Each handler added using addEventHandler() may be:
  • a function (same as usual for standard DOM or MSIE)
  • an Object with a generic “handleEvent” method (Mozilla® Firefox® style)
  • an Object with a method to match the event type, i.e. myObject.onclick, myObject.onmouseover, myObject.onfocus, etc.  The method name must be the event-type in all lowercase, prefixed with “on”, regardless of how you registered it.
Preference given in reverse order from the above presentation;  therefore note in these example possibilities below that “mousemove” is logged in the console as “unhandled”: ===== myHandler=function(event) {console.log("myHandler unhandled "+event.type+" → "+event.target.name)}; myHandler.onclick=function(event) {… … …}; myHandler.onmouseover=function(event) {… … …}; myHandler.onmouseout=function(event) {… … …}; UniDOM.addEventHandler(element, ['click', 'mouseOver', 'mouseMove', 'mouseOut'], myHandler); ===== myObject={/*… … properties and methods, foos and bazes … …*/} myObject.handleEvent(event) {console.log("myObject unhandled "+event.type+" → "+event.target.name)}; myObject.onclick=function(event) {… … …}; myObject.onmouseover=function(event) {… … …}; myObject.onmouseout=function(event) {… … …}; UniDOM.addEventHandler(element, ['click', 'mouseOver', 'mouseMove', 'mouseOut'], myObject); ===== You may also pass in an Array of handlers and all will be called in order, so given the examples above, we can do: ===== anotherHandler=function(event) {/*… …handle all events… …*/}; UniDOM.addEventHandler(element, ['click', 'mouseOver', 'mouseMove', 'mouseOut'], [myHandler, myObject, anotherHandler]); ===== When using multiple event-handlers (in an Array), any one of them may change the property “doContinue” of the “event” object to “false” ( event.doContinue=false; ) to cancel calling the rest in the Array.  This will not cancel bubbling or capturing, and this will not cancel other event-handlers added using a separate call to “addEventHandler”.
¡¡¡Don’t forget an Array of event-handlers is {{live}}, so you can change it after you add it; therefore, additions to an Array of event-handlers are affected by and can effect “event.doContinue”!!!
In the example below (given the examples above), no “unhandled” events will be logged: ===== anotherHandler=function(event) { if (event.type=='mousemove') event.doContinue=false; //block the rest of the handlers in the handler-array /*… …handle all mouseMove events… …*/ }; UniDOM.addEventHandler(element, ['click', 'mouseOver', 'mouseMove', 'mouseOut'], [anotherHandler, myHandler, myObject]); ===== The value of the JavaScript keyword “this” within the added handler function or Object method will be as follows:
functionthis=the Element to which the event handler was “added”
myObject.handleEventthis=myObject
myObject['on'+event.type]this=myObject
The wrapper sends to your handlers a hybrid EventObject which guarantees at least the following cross-browser properties:
event ={
id:unique id generated for each event
target:MSIE’s event.srcElement  →  the Element, Document, or Window that generated the event, i.e. a possible childNode of the currentTarget element during capture or bubble phases.
currentTarget:element  →  the current element which is handling the event, to which an event handler is attached (value of “this” when an event-handler is attached to or is a property of an Element).
relatedTarget:MSIE’s (event.fromElement || event.toElement) the Element from which the mouse is going/coming.
eventPhase:1   ← when using MSIE, only when you employ the simulated capture phase.
eventPhase:MSIE’s (event.srcElement===element) ? 2 : 3 where element is the one you attach the event to.  (2 is the “on target” phase; 3 is the bubbling phase; same as standards)
charCode:MSIE’s event.keycode
offsetX:↓→mouse offset from the “target” element:
offsetY:↑→calculated for standards-complient browsers when applicable to the event type
currentX:↓→mouse offset from the “currentTarget” element:
currentY:↑→calculated for standards-complient browsers when applicable to the event type
stopPropagation:with MSIE: function() {this.cancelBubble=true;} This will also stop propagation during the simulated capturing phase.
preventDefault:with MSIE: function() {this.returnValue=false;}
MSIE:true when using legacy DOM event-handling with old versions (IE9 & earlier) of Microsoft’s Internet Exploder; undefined otherwise.  Do note that IE9 can use standard DOM event-handling (as well as its legacy DOM package), and when using the standards, this property’s value will be undefined.
}
useCapture
Boolean: default=false  For Microsoft’s Internet Exploder, the “capturing phase” of an event is simulated, provided that both the “capturing” event handlers and any event handlers on descendent elements are registered with UniDOM.  See also the UniDOM.enable_oldMSIE_capture() function to guarantee this provision when also using third-party software that doesn’t use UniDOM.  You should use event.stopPropagation() as with the standard DOM, within any phase of the event.
userArg … … …
You may pass in any number of optional user arguments, and each will be passed as a unique argument to every one of your event handlers in your handler-array.  For example, you might have an HTML photo gallery, with photos displayed in order of popularity.  The page is loaded with the gallery, and on the side-bar you want to use JavaScript to add an alphabetized list of people who took each photo.  So your script would gather the images and their respective data, build the sidebar menu, and attach an onClick or onMouseOver event-handler to each menu item: //given an Object containing the <img/> tags // and an alphabetized array of objects holding the photographer’s name & rank: for (var i=0; i<data.length; i++) {   li=build_li_(data[i].name); // use your function defined elsewhere   UniDOM.addEventHandler(li, ['onMouseOver', 'onClick'], popPic, false,       images[data[i].imageName], data[i].imageName, data[i].photographer, data[i].rank, document.body); } // and now our popPic function is very generic, versatile, and easy to read: function popPic(event, imageTag, imageName, photographer, rank, container) {   var popup, old;   popup=document.createElement('div');   popup.appendChild(imageTag.cloneNode(false));   popup.appendChild(document.createTextNode(imageName + ' by ' + photographer + ': ' + rank + '%'));   popup.id='rank_popup';   if (old=document.getElementById('rank_popup'))     old.parentNode.replaceChild(old, popup);   else container.appendChild(popup);   if (event.type==='click') imageTag.scrollIntoView(); }
Return value:

UniDOM’s addEventHandler returns either:  •an Object holding references to “UniDOM.EventHandler” instance-Objects; or if you “pass in” an array of elements, •a corresponding array of the above-said “holding-Objects.”  Each of the “holding-Object’s” properties correspond to each event type registered.  Each “holding-Object” property name is the exact same as you pass in for the event type.  The UniDOM.EventHandler instance-Objects hold vital info about your attached event handlers, and have live active members.  Here’s a possible example of an Object returned:

rtnval = UniDOM.addEventHandler(element, ['onMouseOver', 'onMouseOut', 'click'], myMouseHandler); /* an example of rtnval = { onMouseOver: // a UniDOM.EventHandler instance onMouseOut: // a UniDOM.EventHandler instance click: // a UniDOM.EventHandler instance } */

Static Properties:

You may globally alter some features of the addEventHandler() function.

static properties of UniDOM.addEventHandler
property initial value description
errorOnDoubleBind: false This Boolean flag controls whether to throw an Error when trying to double-bind the same handler function(s) with the same eventTypes on the same element using the same useCapture flag.  UniDOM will never double-bind, and if this flag is false, attempts to do so will be silently ignored!
retroMSIE9: null This Boolean flag controls whether MSIE9 should use its legacy attachEvent() method (with UniDOM’s simulated capture) or the standard DOM addEventListener() method.  It also controls whether UniDOM.generateEvent() & UniDOM.triggerEvent() use fireEvent() (Boolean true) or the standard dispatchEvent() (Boolean false), or with UniDOM.generateEvent() both if this flag is null.  When I once tried to use two separate JavaScript software packages that used opposing methods from each-other, I started getting stack-overflows when one function called another in succession (functions that were not even event related!), and what seemed like memory corruption causing browser instability.

UniDOM.EventHandler Object instances

A UniDOM.EventHandler Object instance has the following properties and method:
id:unique id ←¡do not change this value!
element:¡do not change this value, it is not live!
eventType:¡do not change this value, it is not live!  This value is all lowercase without the leading “on”
handler:{{LIVE}} an array of the handlers that are executed in order by the wrapper (see below) for each event
handler.suspend:{{LIVE}} Boolean value to temporarily suspend calling the handlers (but the wrapper is still active)
wrapper:¡do not change this value, it is generally not live!  This is the wrapper function that is actually added as an event handler to the element.  This wrapper then calls each of the functions in the handler array (see above).  You may invoke this wrapper directly ( myEH.wrapper(event); ) to simulate an event.  Old MSIE uses this property to simulate event capturing, so in that case, during the simulated capture & bubble phases, this property is {{LIVE}}
userArgs:{{LIVE}} an array of user arguments; each passed as an argument to each handler function by the wrapper.
remove():This method removes (unbinds) the event handler wrapper from the element and sets this Object’s id to false.  (see also UniDOM.removeEventHandler)  It is best practice to keep track of your EventHandler returned by UniDOM’s addEventHandler and then use it to remove (unbind) the handler from the element: // myBinding will be a plain Object that holds EventHandler instances: myBinding=UniDOM.addEventHandler(document.body, "mouseUP", dragDROP, true); function dragDROP(event) {   // the .mouseUP property is a UniDOM.EventHandler instance:   myBinding.mouseUP.remove();   /* now do whatever to drop the dragged thing */ }

You may alter the arrays of the “handler” and “userArgs” properties of a UniDOM.EventHandler Object, but replacing them is ineffective.  For instance you may push, pop, shift, unshift or otherwise alter the handler and userArgs arrays, and the wrapper function will call the functions in the modified handler-array, passing the arguments in the modified userArgs-array, though note that even if you remove all the handlers from the handler-array, the “wrapper” will still be attached to the element and active.

You may use:
(myUnknownVariable instanceof UniDOM.EventHandler) in your scripts, but UniDOM prevents you from creating an instance by scripting myEH=new UniDOM.EventHandler(… … …); or myEH=UniDOM.EventHandler(… … …);  You can only create an instance by using UniDOM’s addEventHandler.  The created instance is returned as a sub-property of the returned Object.  See: addEventHandler’s return value.


removeEventHandler(EventHandler_instance) //preferred removeEventHandler(element, eventType, handler, useCapture)

It is easiest to keep track of the UniDOM.EventHandler instance returned when you add an event handler.  In that case, you can simply use myEH.remove(); (see UniDOM.EventHandler).  If you want or need to, you may instead pass the whole EventHandler instance to this function.

If you don’t have access in the scope of a function to the EventHandler instance returned when the handler was added by UniDOM, you can use the long-form of this function instead (similar to the DOM standard way).

See getEventHandler (below) for info on the arguments passed in to this function when using its long-form.


getEventHandler(element, eventType, handler, useCapture)

If you don’t have access in the scope of a function to the UniDOM.EventHandler instance returned when the handler was added by UniDOM, you can use this function to get it.

element *only when called as a functional
The DOM Element the event-handler is attached to.  You may pass in a single Element, or a UniDOM ElementWrapper instance.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 3 arguments, as the element is then figured by this method’s Object.
eventType
You may pass in only one Event-type.  Event-types may be passed in with or without the prefixed “on” and are case-insensitive.
handler
You must pass in the same handler function that you added, or an array that contains the same handler functions in the same order.  Since a UniDOM.EventHandler array is {{LIVE}} (you can change it at any time) if you do change it after you addEventHandler you must pass in the modified current handler selection.
useCapture
must match the Boolean value you passed in when you added the event handler.
Return value:

The properly corresponding UniDOM.EventHandler instance.


removeAllEventHandlers(element, [goDeep])

element *only when called as a functional
The DOM Element the event-handlers are attached to.  You may pass in a single Element, or a UniDOM ElementWrapper instance.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; the element is then figured by this method’s Object.
goDeep
Optional: default is false.  Whether to remove handlers from DOM childnodes and recursively their children.  See getElements for more details on the use of this parameter.

generateEvent(element, eventType, eSpecs)

For high-level event-creation.  This will create a new Event-Object and then dispatch/fire an event using it, and is cross-browser friendly.  For legacy versions of MSIE that do not recognize custom user-defined (synthetic) event-types, this method will simulate properly “firing” the custom event if it was registered using UniDOM’s addEventHandler.

element *only when called as a functional
The DOM Element to generate the event on.  You may pass in a single Element, or a UniDOM ElementWrapper instance.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 2 arguments, as the element is then figured by this method’s Object.
eventType
You may pass in one Event-type or an Array of Event-types.  Event-types may be passed in with or without the prefixed “on” and are case-insensitive.
eSpecs
An object with property names to define the specifications for the Event you want to generate.  Please refer to a good book on JavaScript for further info.  Note you must supply a value for eSpecs.view if you want to set any other explicit specifications (except eSpecs.canBubble and eSpecs.cancelable).  Some example specs are below for all browsers except old MSIE:
eSpecs.canBubble, eSpecs.cancelableall Events
eSpecs.view, eSpecs.detailUIEvents (includes key events and mouse events)
eSpecs.screenX, eSpecs.screenY, eSpecs.clientX, eSpecs.clientY, eSpecs.ctrlKey, eSpecs.altKey, eSpecs.shiftKey, eSpecs.metaKey, eSpecs.button, eSpecs.relatedTargetMouseEvents
eSpecs.buttons, eSpecs.movementX, eSpecs.movementY, eSpecs.offsetX, eSpecs.offsetY, eSpecs.region, eSpecs.whichMouseEvents in newer browsers
For all browsers including old MSIE: if (eSpecs.userArgs) for (p in eSpecs.userArgs) {event[p]=eSpecs.userArgs[p];}
Related Static Properties:
static properties of UniDOM.addEventHandler
property initial value description
retroMSIE9: null This Boolean flag controls whether MSIE9 should use its legacy attachEvent() method (with UniDOM’s simulated capture) or the standard DOM addEventListener() method.  It also controls whether UniDOM.generateEvent() & UniDOM.triggerEvent() use fireEvent() (Boolean true) or the standard dispatchEvent() (Boolean false), or with UniDOM.generateEvent() both if this flag is null.  When I once tried to use two separate JavaScript software packages that used opposing methods from each-other, I started getting stack-overflows when one function called another in succession (functions that were not even event related!), and what seemed like memory corruption causing browser instability.

triggerEvent(element, event)

For low-level event-creation.  You must create your own new Event-Object (you can not reuse one once the event has occurred).  You must determine the proper method (old MSIE or standard) for creating your new Event-Object, but this function is then cross-browser friendly.  This method is currently not available in the “Element-prototype” programming style.

element *only when called as a functional
The DOM Element to dispatch the event on.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument, as the element is then figured by this method’s Object.
event
An Event-object created with your low-level code using document.createEvent or document.createEventObject.
Related Static Properties:
static properties of UniDOM.addEventHandler
property initial value description
retroMSIE9: null This Boolean flag controls whether MSIE9 should use its legacy attachEvent() method (with UniDOM’s simulated capture) or the standard DOM addEventListener() method.  It also controls whether UniDOM.generateEvent() & UniDOM.triggerEvent() use fireEvent() (Boolean true) or the standard dispatchEvent() (Boolean false), or with UniDOM.generateEvent() both if this flag is null.  When I once tried to use two separate JavaScript software packages that used opposing methods from each-other, I started getting stack-overflows when one function called another in succession (functions that were not even event related!), and what seemed like memory corruption causing browser instability.

enable_oldMSIE_capture()

If you want to use UniDOM’s simulated capture function with old versions Microsoft’s Internet Exploder, and you need to be able to use third-party JavaScript scripts at the same time, call this function before loading any third-party scripts.  This will modify the DOM’s ElementNode prototype “attachEvent” method to run through UniDOM’s script for compatibility; otherwise, third-party event-handlers can not be blocked during the simulated capture, or bubbling may occur twice. 


setMouseEventOffsets(event)

For Firefox® and other older browsers that do not support the non-standard event.offsetX, event.offsetY, event.currentX, and event.currentY properties introduced by MSIE.  This function is called automatically by UniDOM’s event-handler “wrappers” as needed, so there is no need to call this function independently if you use UniDOM.addEventHandler.  Note that this is only available in the functional programming styles, not as a method of an Element or ElementWrapper.

event
A standard event-Object (which holds the mouse position on the window).
Return value:

The event-Object modified to reflect the mouse-offset-distances from the event.target and event.currentTarget.


getMouseOffset(element, event)

element *only when called as a functional
The DOM Element from which to figure the mouse position {x,y} distance.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument, as the element is then figured by this method’s Object.
event
A standard event-Object (which holds the mouse position on the window).
Return value:

An Object:
{x: /*horizontal distance*/ ,
 y: /*vertical distance*/ }


Client Info

getScreenX(_window_) getScreenY(_window_)

These functions are only available in the functional programming styles.

_window_
Optional window-object reference; default is the current window the script is running in.
Return value:

The position of the browser on the screen.  Legacy-browser friendly.


getInnerWidth(_window_) getInnerHeight(_window_)

These functions are only available in the functional programming styles.

_window_
Optional window-object reference; default is the current window the script is running in.
Return value:

Dimensions of the browser window.  Legacy-browser friendly.


getScrollX(_window_) getScrollY(_window_)

These functions are only available in the functional programming styles.

_window_
Optional window-object reference; default is the current window the script is running in.
Return value:

Number of pixels the document is scrolled from the left and top.  Legacy-browser friendly.


getDocumentWidth(_window_) getDocumentHeight(_window_)

These functions are only available in the functional programming styles.

_window_
Optional window-object reference; default is the current window the script is running in.
Return value:

Dimensions of the document.  Legacy-browser friendly.


UniDOM.MS_Exploder

Numerical integer value indicating the base-version of Microsoft’s Internet Exploder, or null if UniDOM detected another browser.


DOM query & manipulation tools

window.getComputedStyle(element)

For old versions of Microsoft’s Internet Exploder that don’t have a native version of this global function, UniDOM gives you a cross-browser shell-wrapper-function as defined below:

function getComputedStyle(element) {return element.currentStyle}

getElementOffset(element, [scroll]) getElementOffset(element, [ancestor])

element *only when called as a functional
The DOM Element from which to figure the offset distance {x,y} from either the •beginning of the document, or the •viewport (see scroll below), or the •ancestor.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style accepts only 1 optional argument, as the element is then figured by this method’s Object.
scroll
Optional Boolean: if true, the offset is figured from the top-left corner of the viewport.  The default value is false.
ancestor
If a DOM Element which is an ancestor to element is passed, the offset is figured from the ancestor instead of the document or viewport.
Return value:

An Object:
{x: /*horizontal distance*/ ,
 y: /*vertical distance*/ }


isElementNode(unknown)

unknown *only when called as a functional
The value to test.  You may pass in a single unknown value.  Do not pass in a value for unknown when using the ElementWrapper—based Object-oriented programming style; the value is then figured by this method’s Object.  Note that UniDOM’s Element-gathering functions can also gather DOM Nodes other than Elements, and these may then be wrapped with a UniDOM.ElementWrapper.  Note also that while this is primarily used as a functional (as UniDOM.isElementNode() or the equivalent as a global function) and also a —method— of an ElementWrapper, logically there is no equivalent method in UniDOM’s Element-prototype—based programming style.
Return value:

Boolean


getAncestor(element, cb [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document backwards to find the matching ancestor element of element, and possibly recursively its ancestors, depending on goDeep.

element *only when called as a functional
The DOM Element from which to begin crawling the document.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus any of the optional arguments), as the element is then figured by this method’s Object.
cb
Callback function: should decide whether each element passed to it is the ancestor of choice and return a Boolean value indicating such choice.
goDeep
Whether to (continue to) recursively check the parentNode(s) of the matching element(s).  May be: •Boolean (default is false for getAncestor methods, true for getElements methods) or a •function that evaluates each individual element passed to it and returns a Boolean value.  When goDeep is a function, a second argument is also passed to it referring back to the “context” element which was passed into this getAncestor function.  UniDOM’s getAncestor() and getElements() each work a little different depending on the value of goDeep.  With getAncestor() methods, goDeep is ignored until the first match is found.  If goDeep==false or alternatively goDeep()==false after a match is found, then the query ends and the matching ancestor(s) will be returned.
ojbFltr
An Object-property-name-filter function to enhance the returned Array value with named properties referring to members of the Array.  See: objectify.
applyDirect
Boolean:  ¿Apply “power methods” directly to returned arrays?  See the UniDOM.ElementWrapperArray constructor.
powerSelect
Boolean:  ¿Apply nonstandard methods (getSelected() & setSelected()) to <select> elements?  See: powerSelect.
Return value:

If no match is found, false is returned.  If goDeep evaluates to false on the first match found, that single element will be returned.  If goDeep evaluates to true on the first match found, an ElementWrapperArray (a simple Array with added “UniDOM power methods”) is returned (the result may only be one member, or multiple members of elements).  ¡Note that the returned array is in reverse order from the document contents!


getElements(element, cb [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document to gather the matching childNodes of element, and possibly recursively their children depending on goDeep.

element *only when called as a functional
The DOM Element from which to begin crawling the document.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus any of the optional arguments), as the element is then figured by this method’s Object.
cb
Callback function: should decide whether each element passed to it is the descendent of choice and return a Boolean value indicating such choice.
goDeep
Whether to recursively check childNodes of the element.  May be: •Boolean (default is true for getElements methods, false for getAncestor methods) or a •function that evaluates each individual element passed to it and returns a Boolean value.  When goDeep is a function, a second argument is also passed to it referring back to the “context” element which was passed into this getElements function.  UniDOM’s getAncestor() and getElements() each work a little different depending on the value of goDeep.  With getElements() methods, if goDeep=false then the children of each element will not be considered.  For getElements, getJuniors, and getElders methods, when goDeep is a function, it may also set the doContinue property of itself to false using the code arguments.callee.doContinue=false (or even the callback cb function may set goDeep.doContinue=false), and the query will terminate immediately.  Note that UniDOM always resets the doContinue property to true when it starts a query, so you don’t need to worry about resetting it.
ojbFltr
An Object-property-name-filter function to enhance the returned Array value with named properties referring to members of the Array.  See: objectify.
applyDirect
Boolean:  ¿Apply “power methods” directly to returned arrays?  See the UniDOM.ElementWrapperArray constructor.
powerSelect
Boolean:  ¿Apply nonstandard methods (getSelected() & setSelected()) to <select> elements?  See: powerSelect.
Return value:

If matching elements are found, returns an ElementWrapperArray (a simple Array with added “UniDOM power methods”) of HTML elements (though there may only be one array member).  Returns an empty array if no matches found.


getJuniors(element, cb [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document of all DOM Elements following element (its childNodes and following siblings), and possibly recursively their children and ancestors’ following siblings depending on goDeep, to gather matching DOM Elements.  See getElements for details on arguments passed to this function, and the return value from this function.

This useful example below uses the getJuniors method; but it also exemplifies for getAncestor, getElements, and getElders how to use the callback cb function and how to pass a function for goDeep.  It also exemplifies using goDeep.doContinue, but that feature is not available for getAncestor since it is illogical: you simply pass false from goDeep() to achieve the same result of immediately terminating the query.

var goDeep=function(e) {return !(e.className.match( /\bdisabled\b/ ));},   cb=function(e) {   if (( (e.nodeName==='INPUT' && e.type==='text')   || e.nodeName==='TEXTAREA' )   && !e.disabled) {   goDeep.doContinue=false;   return true; }   else return false; },   nextTextIn=UniDOM.getJuniors(currentTextIn, cb, goDeep)[0];

getElders(element, cb [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document backwards of all DOM Elements preceding element (its preceding siblings and parentNode), and possibly recursively their children and ancestors’ previous siblings depending on goDeep, to gather matching DOM Elements.  See getElements for details on arguments passed to this function, and the return value from this function, except:  ¡Note that the returned array is in reverse order from the document contents!


hasAncestor(element, unknown)

Crawls (transverses) the document to see if unknown is an ancestor of element.

element *only when called as a functional
The DOM Element from which to begin crawling the document.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument, as the element is then figured by this method’s Object.
unknown
The variable you want to check to see if it is an ancestor of element.
Return value:

Returns a Boolean value reflecting the truth of the logic it was passed to evaluate.


hasElement(element, unknown)

Crawls (transverses) the document to see if unknown is a descendent of element.  Note that this function is the inverse of hasAncestor; internally it uses the code hasAncestor(unknown, element) which is faster than transversing the DOM tree forward through all branches.  But also note that unknown may be any value, whereas element should be a DOM element node; this function therefore gives the user two advantages: a logical syntax that is easy to understand when read, and an extra condition to check that unknown is indeed an element before internally calling hasAncestor which requires its first argument to be an element.

element *only when called as a functional
The DOM Element from which to begin crawling the document.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument, as the element is then figured by this method’s Object.
unknown
The variable you want to check to see if it is a descendent of element.
Return value:

Returns a Boolean value reflecting the truth of the logic it was passed to evaluate.


getElementsByName(element, name [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document to gather the matching childNodes of element, and possibly recursively their children depending on goDeep. See getElements for details on arguments other than name passed to this function, with the following exception:  ¡Note that this function is unique in that it supplies a default objFltr-function which will add object-property names to the returned array that match the name attributes of the selected Elements!

name
Each Element’s name attribute is compared with the name you pass into this function.  You may pass in a String, a Regular-Expression, or a “logic-Array” of Strings, Regular-Expressions, and/or more nested “logic-Arrays”.  See UniDOM’s has function for more info on “logic-Arrays”.  If you don’t pass in a value for name (or pass in null or an empty string) all elements with a name attribute will be collected (typically, <input>s, <textarea>s and <select>s).
Return value:

If matching elements are found, returns an ElementWrapperArray (a simple Array with added “UniDOM power methods”) of HTML elements (though there may only be one array member).  As noted above, the returned array is by default objectified with property names corresponding to the Elements’ names.

Returns false if no matches found.


getAncestorByClass(element, className [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document to gather the matching ancestor(s) of element. See getAncestor for details on arguments other than className passed to this function, and the return value from this function.

className
Each Element’s className attribute is “properly” compared with the className you pass into this function.  See hasClass for detailed information.

getElementsByClass(element, className [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document to gather the matching childNodes of element, and possibly recursively their children depending on goDeep. See getElements for details on arguments other than className passed to this function, and the return value from this function.

className
Each Element’s className attribute is “properly” compared with the className you pass into this function.  See hasClass for detailed information.

getAncestorByComplex(element, conditions [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document to gather the matching ancestor(s) of element. See getAncestor for details on arguments other than “conditions” passed to this function, and the return value from this function.

conditions
Should be an Object with two properties: data and filterdata should be a “logic-Array,” and filter should be a callback function that decides whether each Element passed to it passes each “condition” of the logic array.  See UniDOM’s has function for more info on using filter callback functions with “logic-Arrays”.

getElementsByComplex(element, conditions [, goDeep [, objFltr [, applyDirect [, powerSelect]]]])

Crawls (transverses) the document to gather the matching childNodes of element, and possibly recursively their children depending on goDeep. See getElements for details on arguments other than “conditions” passed to this function, and the return value from this function.

conditions
Should be an Object with two properties: data and filterdata should be a “logic-Array,” and filter should be a callback function that decides whether each Element passed to it passes each “condition” of the logic array.  See UniDOM’s has function for more info on using filter callback functions with “logic-Arrays”.

hasClass(element, className [, logic])

element *only when called as a functional
The DOM Element who’s class name to check.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus 1 optional argument), as the element is then figured by this method’s Object.
className
The Element’s className property (similar to its className attribute) is “properly” compared with the className you pass into this function.  You may pass in a •String, a •Regular-Expression, a •callback Function, or a •“logic-Array” of Strings, Regular-Expressions, callbacks, and/or more nested “logic-Arrays”.  ¡Note how hasClass() works differently when using a String compared with getElementsByClass() and getAncestorByClass()!  If you pass in multiple class names as a string with a space, the className property (attribute value) of a matching element must have these class names in the given order, adjacent to each-other.  For example, given four elements: <div class='foo bar'> <div class='baz foo bar buz'> <div class='foo buz bar'> <div class='bar foo'> only the first two match hasClass( 'foo bar' )
but all four match hasClass( ['foo', 'bar'] )
You can use this fact to style Elements with CSS in a similar fashion, but gather them for use by JavaScript in different groups. ¡Contrast this with getElementsByClass() and getAncestorByClass() which convert a single-string with spaces to an Array before internally calling hasClass()!  So: getElementsByClass( 'foo bar' ) ≡≡≡ hasClass( ['foo', 'bar'] ) getElementsByClass( ['foo bar'] ) ≡≡≡ hasClass( 'foo bar' ) getElementsByClass( ['foo', 'bar'] ) ≡≡≡ hasClass( ['foo', 'bar'] ) getElementsByClass( ['foo bar', 'buz'] ) ≡≡≡ hasClass( ['foo bar', 'buz'] ) ← matches only the second div in the above example Note that the examples above demonstrate the fact that when className is a “logic-Array,” the Boolean logical relationship between Array members is “and;” that is, all array members must match the Element’s className.  You may change this logical relationship between members by setting the “logic” property of this Array, or by passing a value for logic (see below). Given the four <div> elements in the example above, mySub=['baz', 'buz']; mySub.logic='xor'; hasClass(['foo', 'bar', mySub]); Above matches <div class='foo fuq bar buz'> and matches only the third <div> above. See UniDOM’s has function for more info on “logic-Arrays.”
In addition to the relational logic in a “logic-Array,” you may also prefix any string you pass in with the ! character for logical “not.”  Using the example HTML of 4 <div>s given above, the following example matches only the third <div>: hasClass(['buz', '!baz']);  while hasClass(['foo', 'bar', '!foo bar']) only matches the last two <div>s.  Note then how '!foo bar' negates the complete string, not just the first className foo.  And finally, any Regular Expression or callback Function that you pass in as a className may have a property, “not,” that will negate its evaluated return value.  In the example below, an online restaurant menu may have a section that lets users choose certain food-groups or ingredients that they either prefer or don’t want.  You could create one RegExp and toggle its “not” property: // high-calibre example: myViceToAvoid=new RegExp( 'cheese', 'i' ); myViceToAvoid.not= (UniDOM.getElementsByName(dinner_menu_form, 'cheese').getSelected().value==='no'); // ===true myClassnameQuery = [ "dinner", "!Italian", /salad/, myViceToAvoid ]; //pasta and cheese line the gut with paper-maché // above matches: "dinner Peruvian Andes_salad blackBeans" // above matches: "Mexican pintoBeans dinner Acapolco_salad" // but not: "dinner Italian Caesar_salad parmaseanCheese" // but not: "lunch Greek_salad feta_cheese" // continuing example: myClassnameQuery.logic='or' // above matches: "dinner Peruvian Andes_salad blackBeans" // above matches: "Mexican pintoBeans dinner Acapolco_salad" // above matches: "dinner Italian Caesar_salad parmaseanCheese" // above matches: "lunch Greek_salad feta_cheese" // continuing example: myClassnameQuery.logic='xor' // no match: "dinner Peruvian Andes_salad blackBeans" // no match: "Mexican pintoBeans dinner Acapolco_salad" // no match: "dinner Italian Caesar_salad parmaseanCheese" // no match: "lunch Greek_salad feta_cheese" // above matches: "lunch Italian Greek_salad feta_cheese"
logic
If you pass in a “logic-Array” for the className, you may set its “logic” property by passing it as an optional last argument.  This facilitates easy function calling with one step instead of 3: hasClass(['cats', 'dogs'], 'xor');   vs. var query=['cats', 'dogs']; query.logic='xor'; hasClass(query);
Return value:

Returns a Boolean value reflecting the truth of the logic it was passed to evaluate.


addClass(element, className)

element *only when called as a functional
The DOM Element who’s class name to add to.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus 1 optional argument), as the element is then figured by this method’s Object.
className
Must be a String of the class-name to add, or an array of these.  Each className String is added to element’s className, if it does not exist already.  Note this function is indiscriminate when a className String has two or more space-separated class-names, in that it will not allow you to add "foo bar" to the existing className "baz foo bar buz", but you can add it to the existing className "bar baz foo buz".  You should instead pass an array: ['foo', 'bar'].  It also does not check the validity of the className you pass in.  This function also automatically cleans extra white-space from the element’s existing/final className.

removeClass(element, className)

element *only when called as a functional
The DOM Element who’s class name to remove from.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus 1 optional argument), as the element is then figured by this method’s Object.
className
Must be a String of the class-name to remove, a Regular-Expression to match the class-name to remove, or an array of these.  All copies of the className String are removed from the element’s className.  Note this function is indiscriminate when a className String has two or more space-separated class-names, in that it will allow you to remove "foo bar" from the existing className "baz foo bar buz", but you can not remove it from the existing className "bar baz foo buz".  You should instead pass an array: ['foo', 'bar'].  This function also automatically cleans extra white-space from the element’s existing/final className.

useClass(element, className, flag)

element *only when called as a functional
The DOM Element who’s class name is to be modified.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus 1 optional argument), as the element is then figured by this method’s Object.
className
Must be a String or an array of Strings, of the class-name to add or remove (depending on flag).  See addClass and removeClass for more info, except that note that since the addClass function does not use Regular-Expressions, neither can this one.
flag
Boolean: whether to add (flag=true) or remove (flag=false) the className.

swapOutClass(element, removals, additions)

At least one browser I’ve seen will update the DOM immediately upon changing a className as opposed to changing a style-attribute of an Element, which may be postponed until the current (event) function is complete.  So if you remove a class in one statement and add another in the next, you still get a “farc-flash” effect displayed to the user.  Use this for less farc. 

element *only when called as a functional
The DOM Element who’s class name is to be modified.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus 1 optional argument), as the element is then figured by this method’s Object.
removals
See removeClassclassName description.
additions
See addClassclassName description.

disable(element, flag [, className])

When you disable/enable a document section, the containing element has the className (or its default) added/removed, and its “disabled” property is set to equal flag.  All descendents of element that can accept user input or keyboard “focus” also have their “disabled” property set to equal flag, excepting that if you disable a section «A», as well as a sub-section «B» of «A», when you then enable (flag=false) section «A», its sub-section «B» will remain disabled if you pass in the same className (or use the default) for both section «A» and its sub-section «B».

For standards-complient browsers that have the capability (not legacy versions of Micorsoft’s Internet Exploder), an onDisabledStateChange event is also fired/triggered on the element as well as on all of its above-noted user-input descendents.  The Event-object passed into your onDisabledStateChange handler will have a property (event.disable) with a Boolean value corresponding to flag.

element *only when called as a functional
The DOM Element containing the document section to be disabled.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus 1 optional argument), as the element is then figured by this method’s Object.
flag
Boolean: whether to disable (flag=true) or enable (flag=false) this document section.
className
Must be a String or an array of Strings, of the class-name(s) to add or remove (depending on flag).  The default value for className is “disabled”.  See addClass and removeClass for more info, except that note that since the addClass function does not use Regular-Expressions, neither can this one.

has(element, data, filter) Object.has(data, filter) SoftMoon.WebWare.objHas(obj, data, filter)

UniDOM’s has method is a simple but flexible “logic engine” that allows a programmer to write code that can easily create complex, powerful, and highly specialized dynamic queries in real-time.  This tool is the heart of all of UniDOM’s query functions/methods.  But it is flexible enough to work with any JavaScript Object.  So not only is it available as a function/method to work with the DOM, it is also available in “raw” form as a static property of the JavaScript constructor Object.  (Note that this is not a property of Object.prototype — don’t confuse this fact.)  You can use it like this:

MyObject={foo: "bar", fi: "buz", fo: "baz", fum: "boz"}; // this way allows you to do many queries simply: MyObject.has=Object.has; MyObject.has(data,filter); //now perform a query on myObject // this way allows you to do one query fast: Object.has.call(MyObject, data, filter); myElement=document.getElementById('myElement'); query_result=UniDOM.has(myElement, data, filter); //functional style query_result=UniDOM(myElement).has(data, filter); //Object-oriented wrapper style // or prototypify the DOM at page load UniDOM.prototypify(); query_result=document.getElementById('myElement').has(data, filter); //prototypical style: makes it simple

There are many practical examples shown for hasClass that demonstrate basic “logic-Arrays.”  The UniDOM functions that utilize this “has” method accept a “logic-Array” and then use a filter function similar to this one used by hasClass shown below:

function(e, c) { //is passed one className in the “logic-Array“ at a time var not=false; if (typeof c === 'function') return c(e)^c.not; if (typeof c !== 'object' || !(c instanceof RegExp)) { if (typeof c == 'string' && c.charAt(0)==='!') {c=c.substr(1); not=true;} c=new RegExp('\\b'+c+'\\b'); } return (not || c.not) ? (e.className.match(c)===null) : e.className.match(c); }
element *only when called as a functional
The DOM Element to query.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus 1 optional argument), as the element is then figured by this method’s Object.
data
A random-length “logic-Array” of a user-defined set of “conditions” to be met.  Data members that have a “logic” property should be Arrays that are considered a sub-set of conditions; and this is recursive, so you may have deeply nested sub-set “logic-Arrays.”  The “logic” property may be any of the following (strings) ('and' is default if no “logic” property is defined): 'and' 'or' 'nor' 'not' 'nand' 'xor' 'xnor' 'xnot' (“nor” and “not” have the same logical meaning)  Note that these logical operators take on a slightly new, expanded meaning, as they can operate on multiple values, not only two.  For example: ([false, true, true]).logic='or' // logic-Array evaluates to true ([false, true, true]).logic='xor' // logic-Array evaluates to false ([false, true, true]).logic='and' // logic-Array evaluates to false ([false, true, true]).logic='xnor' // logic-Array evaluates to false ([false, true, true]).logic='nand' // logic-Array evaluates to true ([false, true, true]).logic='not' // logic-Array evaluates to false ([false, true, true]).logic='xnot' // logic-Array evaluates to true
filter
Your filtering function should accept the arguments: filter(obj, query_condition) and should return true if “query_condition” is met, false if not.  The filter function receives the Object that UniDOM’s has is applied as a method of (either the DOM Element or a user-Object) as the first argument, and individually each of the members of the data “logic-Array,” excepting if any of these members is itself (recursively) a sub-set “logic-Array,” its individual members will each be passed to the filter function.
Return value:

Returns a Boolean value reflecting the truth of the logic it was passed to evaluate.


Utilizing your results

objFltr objectify(filter [, applyDirect [, powerSelect]]) Array.objectify(filter) SoftMoon.WebWare.objectifyArray(arr, filter)

For functions/methods that return UniDOM.ElementWrapperArrays (really just a simple Array with some standard methods & properties tacked on), additional “named” properties may be added to the Array, holding members of the Array for quick access in the future without having to know which Array-member (integer) contains the needed element(s). If the filter (a.k.a. objFltr) callback Function returns the same property name for two or more elements in the Array, the property will then hold another UniDOM.ElementWrapperArray containing the multiple elements.

==== example: // first we pass in an “objFltr” directly through the “getElementsByClass” method → ↓ myElementsArray = UniDOM.getElementsByClass(myPageSectionElement, /^my...Blocks/ , true, function(e) {return e.className.match( /_(.+)$/ )[1];} ); // then we further “objectify” the “UniDOM.ElementWrapperArray” with a second “filter” myElementsArray._.objectify( function(e) {return e.className.match( /my(...)Blocks/ )[1];} ); // myElementArray results might return something like this Array-Object (note it IS a real JavaScript Array): { [0] → <div id='b0' class='mySqrBlocks _red'> [1] → <div id='b1' class='mySqrBlocks _green'> [2] → <div id='b2' class='mySqrBlocks _blue'> [3] → <div id='b3' class='mySqrBlocks _yellow'> [4] → <div id='b4' class='myTriBlocks _blue'> [5] → <div id='b5' class='myTriBlocks _green'> [6] → <div id='b6' class='myLogBlocks _green'> [7] → <div id='b7' class='myLogBlocks _blue'> [length] → 8 [_] → the “UniDOM power methods” object for this Array [red] → <div id='b0' class='mySqrBlocks _red'> [green] → [ <div id='b1' class='mySqrBlocks _green'> , <div id='b5' class='myTriBlocks _green'> , <div id='b6' class='myLogBlocks _green'> ] ← the “power methods” for this Array are also available through its Array._ [blue] → [ <div id='b2' class='mySqrBlocks _blue'> , <div id='b4' class='myTriBlocks _blue'> , <div id='b7' class='myLogBlocks _blue'> ] ← the “power methods” for this Array are also available through its Array._ [yellow] → <div id='b3' class='mySqrBlocks _yellow'> [Sqr] → [ <div id='b0' class='mySqrBlocks _red'> , <div id='b1' class='mySqrBlocks _green'> , <div id='b2' class='mySqrBlocks _blue'> , <div id='b3' class='mySqrBlocks _yellow'> ] [Tri] → [ <div id='b4' class='myTriBlocks _blue'> , <div id='b5' class='myTriBlocks _green'> ] [Log] → [ <div id='b6' class='myLogBlocks _green'> , <div id='b7' class='myLogBlocks _blue'> ] }

But it is flexible enough to work with any JavaScript Array.  So not only is it available as a function/method to work with DOM query results, it is also available in “raw” form as a static property of the JavaScript constructor Array.  (Note that this is not a property of Array.prototype — don’t confuse this fact.)  You can use it like this:

myArray=["bar", "buz", "baz", "boz"]; Array.objectify.call(myArray, filter); //or if it better suits your coding style and/or needs: myArray.objectify=Array.objectify; //do this once… myArray.objectify(filter); // do this as many times as you need with different filters.
arr
The array to objectify.
objFltr
filter
Pass in a callback-function as the filter (a.k.a. objFltr) which should return a property-name (¡numerical values may override existing array members!) for the element passed into the callback, to be added as an Object-property to the finally-returned Array.  ¡¡¡ the returned Array may have nonstandard properties added to <select> elements if you pass “true” for powerSelect !!!  Each added property usually reflects a single member of the returned Array.  If the filter callback returns the same name for multiple elements in the returned Array, the added property will be a sub- Array of elements, each reflecting a member of the overall returned Array.
applyDirect
Boolean:  ¿Apply “power methods” directly to sub-arrays when multiple elements share the same property name?  See the UniDOM.ElementWrapperArray constructor.
powerSelect
Boolean:  ¿Apply nonstandard methods (getSelected() & setSelected()) to <select> elements?  See: powerSelect.

powerSelect getSelected(forceReturnArray) setSelected(value) UniDOM.addPowerSelect(select) UniDOM.getSelectedOptions(select [, forceReturnArray]) UniDOM.setSelectedOptions(select, value) UniDOM.powerSelect=true

When using UniDOM’s “element-gathering” functions/methods that return UniDOM.ElementWrapperArrays (really just a simple Array with some standard methods & properties tacked on), or when using the objectify method, you may pass in a final optional Boolean argument “powerSelect” which will add nonstandard methods (getSelected() & setSelected()) directly to <select> elements.  These methods mirror the same methods that are found on the returned ElementWrapperArrays.  You can then write code that can get/set either a <select> or a group of <input>s in a UniDOM.ElementWrapperArray without worrying about if the form-format may change a little in the future, giving more flexibility to the HTML developer. Consider an online menu where users can choose one large side item and one small side item:

==== example: name of the element(s) that match ↓ ↓deep ↓ returns “objectify” property names applyDirect↓ ↓powerSelect   sideOrders = UniDOM.getElementsByName(myMenu, /sideOrders/, true, function(e) {return e.name.match( /\[(.+)\]/ )[1]}, true, true)   largeSide = sideOrders.large.getSelected().value;   smallSide = sideOrders.small.getSelected().value;

May return something like:

  sideOrders =  { //Array-Object: a UniDOM.ElementWrapperArray ← also has standard “power methods” “applied directly” (too many to list)   [0] → <input type='radio' name='sideOrders[large]' value='baked potato with cheese' />   [1] → <input type='radio' name='sideOrders[large]' value='cheesy broccoli' />   [2] → <input type='radio' name='sideOrders[large]' value='vegi-baked beans with cheese' />   [3] → <input type='radio' name='sideOrders[large]' value='Greek salad' checked='checked'/>   [4] → <select name='sideOrders[small]'> ← has options (these options are NOT “in” this array):   <option value='snow peas' selected='selected'>   <option value='string beans'>   <option value='creamed corn'>   [length] → 5   [_] → the “power methods” object for this Array - they are also “applied directly,” but they are not shown here for space limitations   [large] → { //Array-Object: a UniDOM.ElementWrapperArray ← also has standard “power methods” “applied directly” (too many to list)   [0] → <input type='radio' name='sideOrders[large]' value='baked potato with cheese' />   [1] → <input type='radio' name='sideOrders[large]' value='cheesy broccoli' />   [2] → <input type='radio' name='sideOrders[large]' value='vegi-baked beans with cheese' />   [3] → <input type='radio' name='sideOrders[large]' value='Greek salad' checked='checked'/>   [length] → 4   [_] → the “power methods” object for this Array   }   [small] → <select name='sideOrders[small]'> ← has options (these options are NOT “in” this array):   <option value='snow peas' selected='selected'>   <option value='string beans'>   <option value='creamed corn'>  }   largeSide='Greek salad'   smallSide='snow peas'

Now we can develop an online-menu manager software-package that allows restaurant managers to manage their menu which may change daily based on locally available ingredients or the chef’s specials, etc.  The restaurant manager can choose a <select> or list of <input>s for the ingredients or menu items, and the high-end JavaScript logic that puts together a customer’s order need not worry about the form’s format.  How's that go?……write less, do more… …

Also provided, the UniDOM.addPowerSelect() function will add nonstandard methods getSelected() & setSelected() directly to <select> elements;  and the static functions UniDOM.getSelectedOptions() & UniDOM.setSelectedOptions() are available if you don’t want to tarnish the DOM.

powerSelect
(The final optional argument passed into UniDOM’s “element-gathering” (and other) methods.)  Boolean: ¿Add nonstandard methods (getSelected() & setSelected()) to <select> elements?
forceReturnArray
Boolean.  The getSelected methods by default will return a single <input type='radio'> element from a UniDOM.ElementWrapperArray, or a single <option> element from a <select>-one field.  In opposition, by default it will return an Array of one or more <input type='checkbox'> elements, or an Array of one or more <option> elements from a <select>-multiple field.  By default it will return null if there are none checked or selected.  By passing a Boolean value for forceReturnArray you may override these defaults:  passing true will always return an array, with zero, one, or more elements as members; and passing false will return only one element (no Array) if only one is checked or selected
value
String or an Array of Strings.  Any <input> or <option> (of a UniDOM.ElementWrapperArray or <select> element) with a value attribute, or the text of an <option>, that matches the value (or if value is an Array, one of its members) you pass into the setSelected() method will be checked or selected.
select
The <select> element you want to empower with getSelected() & setSelected() methods.
Return value:

See forceReturnArray above for details on the return value for getSelected methods.  There is no return value for the other methods.



UniDOM’s Element Wrappers for OO style code

UniDOM.ElementWrapper(element [, applyDirect]) Object instances

A UniDOM.ElementWrapper is simply a shell-wrapper for a DOM element.  This wrapper has all the relevent UniDOM methods to work on the given element.  In this way, you can write Object-oriented code without modifying the DOM’s prototypes, and you can “chain” a UniDOM method on to the results of the previous method.

Note you can create a new wrapper using: myWrapper=new UniDOM.ElementWrapper(myElement) but it may be easier to simply use the basic functional interface: myWrapper=UniDOM(myElement) which will return the same new ElementWrapper.  You can always check an unknown value using (unknown instanceof UniDOM.ElementWrapper).

element
The DOM element you want to wrap with UniDOM’s power methods.
applyDirect
Boolean: this flag does not affect the ElementWrapper, rather it is passed on automatically to any of UniDOM’s power methods that are called on this wrapper, and when they return a UniDOM.ElementWrapperArray this applyDirect flag will affect whether UniDOM’s power methods will be added directly to the said returned ElementWrapperArray.  See UniDOM.ElementWrapperArray for more details.
Instance Properties:
element

Boolean: this property mirrors the same-named argument passed into the ElementWrapper constructor.

applyDirect

Boolean: this property mirrors the same-named argument passed into the ElementWrapper constructor.


Instance Methods

An ElementWrapper has all the standard relevent UniDOM “power-methods.”

  • $
  • addEventHandler
  • removeEventHandler
  • removeAllEventHandlers
  • generateEvent
  • triggerEvent
  • getMouseOffset
  • getOffset
  • getAncestor
  • getElements
  • getElders
  • getJuniors
  • getElementsByName
  • getElementsByClass
  • getAncestorByClass
  • getElementsByComplex
  • getAncestorByComplex
  • hasAncestor
  • hasElement
  • has
  • hasClass
  • addClass
  • removeClass
  • useClass
  • swapOutClass
  • disable
  • getSelected
  • setSelected

UniDOM.ElementWrapperArray([wrapElements [, applyDirect]]) ↑ a new Array will be created with the relevant “power methods” UniDOM.ElementWrapperArray(userArray [, wrapElements [, applyDirect]]) ↑ the userArray will have the relevant “power methods” added to it Object instances

UniDOM’s ElementWrapperArrays are simply a basic JavaScript Array with UniDOM power methods and relevent properties tacked on.  These methods and properties are not prototyped to the Array (there is no way to do that without affecting all JavaScript arrays, and creating custom Object instances can not duplicate the inherent functionality of the Array.length property).  UniDOM always uses real JavaScript Arrays instead of Object instances that “hide away” the actual element members.  (UniDOM is oriented toward flexibility for programmers, rather than merely simplicity for less-technical developers.) We want to manipulate the Array as an array, rather than being required to use add() and remove() and getArray() methods.  We can keep track of what we add, where, when, why, and how, and may want to hack the contents.

Since these are real JavaScript Arrays (to keep the inherent length-property-functionality which can not be fully simulated), and we can not prototype the “power-methods” into a new UniDOM.ElementWrapperArray, they are available through the “_” property of the ElementWrapperArray. If you want to access these methods directly through the Array, the “power methods” must be individually copied to the new Array, a burden on the processor.  This is not a big problem with fast modern computers, but may be on older ones in code-loops.  See the applyDirect argument flag and the static ElementWrapperArray.applyDirect flag.

Do note that the above-mentioned “_” property of the ElementWrapperArray is itself an Object instance, and has a property referring back to the ElementWrapperArray, and is therefore custom-made and not simply transferable.

Also note that the UniDOM “power-methods” that generally return more than one DOM element return them in an ElementWrapperArray.  These “power-methods” automatically determine the value of wrapElements (depending on the coding style you are using), but you may pass through them a value for applyDirect.

wrapElements
Boolean:  Whether the Array members are “wrapped” in UniDOM.ElementWrappers, or if they are simply “raw” DOM elements.  Each member in the userArray and those added to the returned Array should be a DOM Element or a UniDOM.ElementWrapper according to wrapElements.  Power-methods of this ElementWrapperArray that return or add DOM Elements will then respect the wrappedElements flag property, and treat the ElementWrapperArray members accordingly.
applyDirect
Boolean:  Whether to apply the “power methods” directly to this UniDOM.ElementWrapperArray (really just a simple Array with some standard properties tacked on).  They are always available through its “_” property. ==== example:   myInputs=UniDOM.getElementsByClass(myForm, 'sideOrders')   myInputs._.setSelected(['potato', 'peas']); ← note the use of the ._. object to hold the methods ==== example: ↓ applyDirect   myInputs=UniDOM.getElementsByClass(myForm, 'sideOrders', true, null, true)   myInputs.setSelected(['potato', 'peas']); ← note now we don’t need the ._. object
Static Properties & Constructor

The default action of not applying “power-methods” directly to the ElementWrapperArray can be overridden by changing the static value of: UniDOM.ElementWrapperArray.applyDirect

==== example:   UniDOM.ElementWrapperArray.applyDirect=true;   myInputs=UniDOM.getElementsByClass(myForm, 'sideOrders')   myInputs.setSelected(['potato', 'peas']);

It would usually be OK to always apply direct, but if your program repeatedly and extensively loops through UniDOM methods that return ElementWrapperArrays, it may noticeably slow the process.

Likewise, the default type of Array member is a DOM element.  This may be overridden by setting the static value of: UniDOM.ElementWrapperArray.wrappedElements=true to signify the use of UniDOM.ElementWrappers (containing the DOM elements) instead of the “raw” DOM elements by themselves.  Note ElementWrappers allow you to use UniDOM’s power methods on each individual ElementWrapperArray member, not only on the Array (which would affect all members).

The UniDOM.ElementWrapperArray.dfltMethods constructor is used to create instances of the “power-method” objects attached to instances of ElementWrapperArrays as the _ property.  You may add to or otherwise modify it for additional methods, etc., to work on the ElementWrapperArray, but be sure you understand how to access the array within your newly added methods.


Instance Properties
_

This property holds all the relevent “power-methods” for the ElementWrapperArray.  It is always available, even when the methods are also “applied directly.”  See applyDirect above.

wrappedElements

Boolean: this property mirrors the wrapElements argument passed into the ElementWrapperArray constructor, or the corresponding default value.

EWAMAppliedDirect

Boolean: this property mirrors the applyDirect argument passed into the ElementWrapperArray constructor, or the corresponding default value.  (EWAMAppliedDirect stands for “Element Wrapper Array Methods Applied Directly”).


Instance Methods

An ElementWrapperArray has all the standard relevent UniDOM “power-methods” for working with the DOM (available either through its “_” property or directly — see applyDirect above), plus a few additional methods specifically for working with Arrays of elements.  See UniDOM.ElementWrapper for details on the standard “power-methods.”

Additional methods specific to ElementWrapperArrays:
objectify(filter [, applyDirect [, powerSelect]])

Adds properties to the array defined by the filter callback function.  See the section specific to objectify.

wrap([flag])

Sets the wrappedElements property.  Useful when chaining without wasting processor time wrapping intermediate results: given an ElementWrapperArray of “raw” (unwrapped) Elements:

====Example: we can now chain on an individual ↓  myEWA.getElements(…).map(…).wrap().filter(…)[1].disable(…)

¡Note wrap() and raw() do not modify the existing Array members, only the results of the next method in the chain!

raw([flag])

Sets the wrappedElements property.  Useful when chaining on elements, while delivering a clean array:  given an individual ElementWrapper (myEW in the example below), chaining creates an Array of ElementWrappers … until raw() is called.

element=myEW.getAncestor(…)[1].getElements(…).raw().filter(…)

¡Note wrap() and raw() do not modify the existing Array members, only the results of the next method in the chain!

add()

This method takes any number of arguments, each either a DOM element or a UniDOM.ElementWrapper, and adds them to the existing ElementWrapperArray.  It wraps or unwraps the arguments you pass in depending on the ElementWrapperArray’s wrappedElements property flag.

map(cb [, o [, wrap [, applyDirect]]])

This method works just like the standard Array.map() method, (with the cb() function’s return values becoming the members of the new Array returned by map()) except with the optional extra arguments specific to UniDOM’s functioning.  If wrap is Boolean true then the resulting mapped-Array will be a UniDOM.ElementWrapperArray, and the applyDirect flag will then affect this new ElementWrapperArray.

filter(cb [, o])

This method works just like a standard Array.filter() method, (passing each array member to the cb() function who’s Boolean return values determine the members of the original Array included in the new Array returned by filter()) except that the returned Array is a UniDOM.ElementWrapperArray.  If you pass an Object for o, cb will be invoked on that Object.


UniDOM(element [, applyDirect]) UniDOM(ElementWrapper [, applyDirect]) UniDOM(CSSQueryString [, applyDirect]) ↑ the third argument, passData, must be ==false (or undefined) UniDOM(element‖ElementWrapper, CSSQueryString [, applyDirect]) UniDOM(eArray [, applyDirect [, passData]]) UniDOM(element‖ElementWrapper‖eArray‖userData, applyDirect, passData=true)

The basic UniDOM() function is a catch-all for creating ElementWrappers with UniDOM’s “power-methods” to work on your chosen DOM element(s).  It is the basis for using the “wrapper-based Object-oriented programming style.”  In this respect, it is similar in function to jQuery’s “$”.  However in contrast, note UniDOM’s “$” function only acts as a CSS-selector-query Engine without “wrapping” the gathered elements.

element
The DOM element you want to wrap with UniDOM’s ElementWrapper power methods.
ElementWrapper
The UniDOM.ElementWrapper containing the DOM element you want to “re-wrap” with UniDOM’s power methods.  (note technically “wrappers” are just Objects that “point” to the element, and only give the illusion of “wrapping-around,” so you may have as many ElementWrappers pointing to a single element as you want, and none will be “wrapped-around” interfering with another)
CSSQueryString
A Cascading-Style-Sheet category of a query-string to gather DOM elements that will each be individually wrapped with UniDOM.ElementWrappers, and collected in a UniDOM.ElementWrapperArray.  See UniDOM’s “$” function for more info.  ¡Note that you may not pass true for the passData argument (see below) if you want to use this query-string as the first argument!
eArray
An Array that may contain any number of legal arguments for the first value passed to this UniDOM function including nested Arrays.  Each member (recursively) will be “wrapped” in UniDOM.ElementWrappers, and the group of them will be returned in one (or more when nested) UniDOM.ElementWrapperArray(s).
userData
Any type of data may be passed through the UniDOM() function when its passData argument is true.  See passData below.
applyDirect
Boolean: this flag does not affect the ElementWrapper created with UniDOM(), rather it is passed on automatically to any of UniDOM’s power methods that are called on the wrapper, and when they return a UniDOM.ElementWrapperArray this applyDirect flag will affect whether UniDOM’s power methods will be added directly to the said returned ElementWrapperArray.  See UniDOM.ElementWrapperArray for more details.
passData
This argument is used internally by UniDOM’s ElementWrapperArray “power-methods” to pass raw data returned by the methods through the UniDOM() function without error or confusion of data-type.  There is generally no reason for you to need to use it; however if you want to play “hackey-sack” with it, go ahead…  Passing true for this argument will still “wrap” elements, “rewrap” existing ElementWrappers, and array members of these two former; and this passData value will be simply ignored in those cases.  In contrast, when passData=true, passing a String for the first argument will simply return the string as user-data instead of treating the string as a CSS selector to gather elements;  and as well, passing through any other variable-type for the first argument is simply passed back instead of throwing an Error.

DOM queries with CSS selectors

$(CSSQueryString , element [, objFltr [, applyDirect [, powerSelect]]])

UniDOM’s “dollar–sign” function/method $ integrates UniDOM’s total functionality with the “CSS-Engine” of your choice.  UniDOM does not have an Engine of its own (but given enough free time I plan on writing one that utilizes UniDOM’s powerful has method) but it will automatically use the standard JavaScriptDOM interface method querySelectorAll if it is available, or else look for “Sizzle” (jQuery’s Engine) or “Slick” (MooTools’ Engine) (see: http://sizzlejs.com/  &  http://mootools.net/docs/core/Slick/Slick).  Of course you may specify exactly which CSS-Engine to use including any other similarly compatible.  See the UniDOM.CSSEngine property specs below.

¡Note that if you call UniDOM.globalize() to use the global-functional programming style, this method’s name $ will over-write any same-named variable in the window, commonly used by jQuery and many other toolkits!

CSSQueryString
String: A standard Cascading-Style-Sheet type of description to identify the Elements to be “gathered.”  The exact specifications of this query String may very slightly depending on the “CSS-Engine” you use.  Please refer to a good tutorial on using the native JavaScript querySelectorAll method, or if using “Sizzle” or “Slick” (or another CSS Engine), their documentation.
element *only when called as a functional
The DOM Element from which to begin crawling the document.  You may pass in a single Element, or a UniDOM ElementWrapper.  Do not pass in a value for element when using ElementWrapper— or prototype— based Object-oriented programming styles; using an Object-oriented style requires only 1 argument (plus any of the optional arguments), as the element is then figured by this method’s Object.
ojbFltr
An Object-property-name-filter function to enhance the returned Array value with named properties referring to members of the Array.  See: objectify.
applyDirect
Boolean:  ¿Apply “power methods” directly to returned arrays?  See the UniDOM.ElementWrapperArray constructor.
powerSelect
Boolean:  ¿Apply nonstandard methods (getSelected() & setSelected()) to <select> elements?  See: powerSelect.
Return value:

If matching elements are found, returns an ElementWrapperArray (a simple Array with added “UniDOM power methods”) of HTML elements (though there may only be one array member).  Returns an empty array (or an empty “array-like Object: NodeList” when using the standard DOM querySelectorAll Engine) if no matches found.  Note the elements returned are not individually wrapped with UniDOM.ElementWrappers; only the returned array has UniDOM’s “power-methods.”  You can instead use the code: UniDOM(CSSQueryString)  and the resulting array members will be individually “wrapped” with “power-methods,” as well as the returned array.