User:Mike Dillon/Scripts/easydom-dev.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Mike Dillon/Scripts/easydom-dev. |
// <pre><nowiki>
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;
// </nowiki></pre>