User:Mike Dillon/Scripts/easydom.js

function buildEasyDomNamespace(namespace, options) { var isType = function (o, t) { return typeof o == t }; var isBool = function (o) { return isType(o, typeof true); }; var isString = function (o) { return isType(o, typeof ''); }; var isNumber = function (o) { return isType(o, typeof 0); }; var isFunction = function (o) { return isType(o, typeof function {}); }; var isObject = function (o) { return isType(o, typeof new Object); }; var isUndefined = function (o) { return isType(o, (function (x) { return typeof x })); }; var isDefined = function (o) { return !isUndefined(o); }; // NOTE: null is "defined" var isPrimitive = function (o) { return isString(o) || isNumber(o) || isBool(o) || isFunction(o); }   var isNode = function (o) { return isDefined(o) && o != null && isNumber(o.nodeType); }

// Default tag names to be installed into the namespace as functions var defaultTagNames = [ "bdo", "script", "style", "object", "param", "iframe", "link", "meta", "p", "pre", "a", "div", "span", "ul", "ol", "li", "img", "hr", "br", "em", "strong", "sup", "sub", "tt", "abbr", "acronym", "del", "ins", "cite", "blockquote", "code", "table", "tbody", "tfoot", "tr", "th", "td", "col", "colgroup", "caption", "form", "input", "select", "option", "optgroup", "button", "textarea", "h1", "h2", "h3", "h4", "h5", "h6", "label", "canvas", "fieldset", "legend" ];

// Default event types var defaultEventTypes = [ // HTML 4.0 "Abort", "Blur", "Change", "Click", "DblClick", "DragDrop", "Error", "Focus", "KeyDown", "KeyPress", "KeyUp", "Load", "MouseDown", "MouseMove", "MouseOut", "MouseOver", "MouseUp", "Move", "Reset", "Resize", "Select", "Submit", "Unload" ];

// Create an anonymous namespace if none was provided if (isUndefined(namespace)) namespace = {};

// Settings var settings = { "namespaceUri": "http://www.w3.org/1999/xhtml", "invokeFunctions": true, "tagNames": defaultTagNames, "eventTypes": defaultEventTypes };

// Override default settings with specified options if (options) { for (var p in options) { settings[p] = options[p]; }   }

// If the browser doesn't understand createElementNS, fake it (God help them...) if (isUndefined(document.createElementNS)) { document.createElementNS = function (ns, name) { return document.createElement(name); };   }

// Creates the DOM element var createDomElement = function(name) { return document.createElementNS(settings.namespaceUri, name); };

var defaultAttributeHandler = function (elem, attrName, attrValue) { // Invoke function callbacks of zero or one argument and use their result as the new attrValue if (settings.invokeFunctions && isFunction(attrValue) && attrValue.length <= 1) { attrValue = attrValue(elem); }

// Skip null values if (attrValue == null) { return; }

// Stringify non-string values if (!isString(attrValue)) { attrValue = attrValue.toString; }

// Set the attribute elem.setAttribute(attrName, attrValue); };

var createAttributeOverrideHandler = function (overrideName) { return function (elem, attrName, attrValue) { defaultAttributeHandler(elem, overrideName, attrValue); };   };

var createEventHandlerAttributeHandler = function (overrideName) { return function (elem, attrName, attrValue) { if (!isFunction(attrValue)) { attrValue = new Function(attrValue); }           elem[overrideName || attrName] = attrValue; };   };

var attributeHandlers = {};

for (var i in settings.eventTypes) { var handlerName = "on" + settings.eventTypes[i]; var internalName = handlerName.toLowerCase; // Force lower case attributeHandlers[internalName] = createEventHandlerAttributeHandler; // Allow mixed case (with lower case internal name) attributeHandlers[handlerName] = createEventHandlerAttributeHandler(internalName); }

// Conditionally add I.E. name overrides /*@cc_on attributeHandlers["for"] = createAttributeOverrideHandler("htmlFor"); attributeHandlers["maxlength"] = createAttributeOverrideHandler("maxLength"); attributeHandlers["class"] = createAttributeOverrideHandler("className"); attributeHandlers["accesskey"] = createAttributeOverrideHandler("accessKey");

attributeHandlers["style"] = function (elem, attrName, attrValue) { elem.style.cssText = attrValue; };   @*/

// Detects if the first element is a hash of attributes and if so, // uses it to set attributes on the DOM node //   // Returns the number of elements processed to let the caller know // how many of the arguments to skip var processDomAttributes = function(elem, args) { if (args.length == 0) { return 0; }

// No attributes to process if null is the first argument if (args[0] == null) { return 0; }

// No attributes to process if a "primitive" is the first argument if (isPrimitive(args[0])) { return 0; }

// No attributes to process if a DOM node is the first argument if (isNode(args[0])) { return 0; }

// Process the first argument as a hash of attributes var attrs = args[0]; for (var attrName in attrs) { if (isUndefined(attributeHandlers[attrName])) { defaultAttributeHandler(elem, attrName, attrs[attrName]); } else { attributeHandlers[attrName](elem, attrName, attrs[attrName]); }       }

// Return the number of arguments processed return 1; };

// Create the function that creates new DOM element builders var createDomElementBuilder = function (name) { return function { var elem = createDomElement(name);

// Process attribute hash, if any and skip the argument count returned var firstChild = processDomAttributes(elem, arguments);

// Process the remaining children, if any for (var i = firstChild; i < arguments.length; i++) { var child = arguments[i]; if (child == null) { continue; }               // Convert any non-DOM nodes to text nodes with toString if (!isNode(child)) { child = document.createTextNode(child.toString); }               elem.appendChild(child); }

return elem; };   };

// Populate the namespace for (var i in settings.tagNames) { var tagName = settings.tagNames[i]; namespace[tagName] = createDomElementBuilder(tagName); }

// Return the namespace for those relying on anonymous creation return namespace; }

// Build the Easy DOM functions in an anonymous namespace easyDom = buildEasyDomNamespace;

// Namespace pollution easydom = easyDOM = easyDom;