User:Mike Dillon/Scripts/easydom-dev.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"

];

// 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];

}

}

// 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;

//