skylark-utils
Version:
An Elegant HTML5 JavaScript Library.
412 lines (341 loc) • 10.5 kB
JavaScript
define([
"./skylark",
"./langx",
"./styler"
], function(skylark, langx, styler) {
var isIE = !!navigator.userAgent.match(/Trident/g) || !!navigator.userAgent.match(/MSIE/g),
fragmentRE = /^\s*<(\w+|!)[^>]*>/,
singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
div = document.createElement("div"),
table = document.createElement('table'),
tableBody = document.createElement('tbody'),
tableRow = document.createElement('tr'),
containers = {
'tr': tableBody,
'tbody': table,
'thead': table,
'tfoot': table,
'td': tableRow,
'th': tableRow,
'*': div
},
rootNodeRE = /^(?:body|html)$/i,
map = Array.prototype.map,
slice = Array.prototype.slice;
function ensureNodes(nodes, copyByClone) {
if (!langx.isArrayLike(nodes)) {
nodes = [nodes];
}
if (copyByClone) {
nodes = map.call(nodes, function(node) {
return node.cloneNode(true);
});
}
return langx.flatten(nodes);
}
function nodeName(elm, chkName) {
var name = elm.nodeName && elm.nodeName.toLowerCase();
if (chkName !== undefined) {
return name === chkName.toLowerCase();
}
return name;
};
function contents(elm) {
if (nodeName(elm, "iframe")) {
return elm.contentDocument;
}
return elm.childNodes;
}
function html(node, html) {
if (html === undefined) {
return node.innerHTML;
} else {
this.empty(node);
html = html || "";
if (langx.isString(html) || langx.isNumber(html)) {
node.innerHTML = html;
} else if (langx.isArrayLike(html)) {
for (var i = 0; i < html.length; i++) {
node.appendChild(html[i]);
}
} else {
node.appendChild(html);
}
}
}
function clone(node, deep) {
var self = this,
clone;
// TODO: Add feature detection here in the future
if (!isIE || node.nodeType !== 1 || deep) {
return node.cloneNode(deep);
}
// Make a HTML5 safe shallow copy
if (!deep) {
clone = document.createElement(node.nodeName);
// Copy attribs
each(self.getAttribs(node), function(attr) {
self.setAttrib(clone, attr.nodeName, self.getAttrib(node, attr.nodeName));
});
return clone;
}
}
function createElement(tag, props) {
var node = document.createElement(tag);
if (props) {
langx.mixin(node, props);
}
return node;
}
function createFragment(html) {
// A special case optimization for a single tag
if (singleTagRE.test(html)) {
return [createElement(RegExp.$1)];
}
var name = fragmentRE.test(html) && RegExp.$1
if (!(name in containers)) {
name = "*"
}
var container = containers[name];
container.innerHTML = "" + html;
dom = slice.call(container.childNodes);
dom.forEach(function(node) {
container.removeChild(node);
})
return dom;
}
function contains(node, child) {
return isChildOf(child, node);
}
function createTextNode(text) {
return document.createTextNode(text);
}
function doc() {
return document;
}
function empty(node) {
while (node.hasChildNodes()) {
var child = node.firstChild;
node.removeChild(child);
}
return this;
}
function isChildOf(node, parent) {
if (document.documentElement.contains) {
return parent.contains(node);
}
while (node) {
if (parent === node) {
return true;
}
node = node.parentNode;
}
return false;
}
function isDoc(node) {
return node != null && node.nodeType == node.DOCUMENT_NODE
}
function ownerDoc(elm) {
if (!elm) {
return document;
}
if (elm.nodeType == 9) {
return elm;
}
return elm.ownerDocument;
}
function ownerWindow(elm) {
var doc = ownerDoc(elm);
return doc.defaultView || doc.parentWindow;
}
function after(node, placing, copyByClone) {
var refNode = node,
parent = refNode.parentNode;
if (parent) {
var nodes = ensureNodes(placing, copyByClone),
refNode = refNode.nextSibling;
for (var i = 0; i < nodes.length; i++) {
if (refNode) {
parent.insertBefore(nodes[i], refNode);
} else {
parent.appendChild(nodes[i]);
}
}
}
return this;
}
function before(node, placing, copyByClone) {
var refNode = node,
parent = refNode.parentNode;
if (parent) {
var nodes = ensureNodes(placing, copyByClone);
for (var i = 0; i < nodes.length; i++) {
parent.insertBefore(nodes[i], refNode);
}
}
return this;
}
function prepend(node, placing, copyByClone) {
var parentNode = node,
refNode = parentNode.firstChild,
nodes = ensureNodes(placing, copyByClone);
for (var i = 0; i < nodes.length; i++) {
if (refNode) {
parentNode.insertBefore(nodes[i], refNode);
} else {
parentNode.appendChild(nodes[i]);
}
}
return this;
}
function append(node, placing, copyByClone) {
var parentNode = node,
nodes = ensureNodes(placing, copyByClone);
for (var i = 0; i < nodes.length; i++) {
parentNode.appendChild(nodes[i]);
}
return this;
}
function overlay(elm, params) {
var overlayDiv = createElement("div", params);
styler.css(overlayDiv, {
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
zIndex: 0x7FFFFFFF,
opacity: 0.7
});
elm.appendChild(overlayDiv);
return overlayDiv;
}
function remove(node) {
if (node && node.parentNode) {
node.parentNode.removeChild(node);
}
return this;
}
function replace(node, oldNode) {
oldNode.parentNode.replaceChild(node, oldNode);
return this;
}
function throb(elm, params) {
params = params || {};
var self = this,
text = params.text,
style = params.style,
time = params.time,
callback = params.callback,
timer,
throbber = this.createElement("div", {
className: params.className || "throbber",
style: style
}),
_overlay = overlay(throbber, {
className: 'overlay fade'
}),
throb = this.createElement("div", {
className: "throb"
}),
textNode = this.createTextNode(text || ""),
remove = function() {
if (timer) {
clearTimeout(timer);
timer = null;
}
if (throbber) {
self.remove(throbber);
throbber = null;
}
},
update = function(params) {
if (params && params.text && throbber) {
textNode.nodeValue = params.text;
}
};
throb.appendChild(textNode);
throbber.appendChild(throb);
elm.appendChild(throbber);
var end = function() {
remove();
if (callback) callback();
};
if (time) {
timer = setTimeout(end, time);
}
return {
remove: remove,
update: update
};
}
function traverse(node, fn) {
fn(node)
for (var i = 0, len = node.childNodes.length; i < len; i++) {
traverse(node.childNodes[i], fn);
}
return this;
}
function reverse(node) {
var firstChild = node.firstChild;
for (var i = node.children.length - 1; i > 0; i--) {
if (i > 0) {
var child = node.children[i];
node.insertBefore(child, firstChild);
}
}
}
function wrapper(node, wrapperNode) {
if (langx.isString(wrapperNode)) {
wrapperNode = this.createFragment(wrapperNode).firstChild;
}
node.parentNode.insertBefore(wrapperNode, node);
wrapperNode.appendChild(node);
}
function wrapperInner(node, wrapperNode) {
var childNodes = slice.call(node.childNodes);
node.appendChild(wrapperNode);
for (var i = 0; i < childNodes.length; i++) {
wrapperNode.appendChild(childNodes[i]);
}
return this;
}
function unwrap(node) {
var child, parent = node.parentNode;
if (parent) {
if (this.isDoc(parent.parentNode)) return;
parent.parentNode.insertBefore(node, parent);
}
}
function noder() {
return noder;
}
langx.mixin(noder, {
clone: clone,
contents: contents,
createElement: createElement,
createFragment: createFragment,
contains: contains,
createTextNode: createTextNode,
doc: doc,
empty: empty,
html: html,
isChildOf: isChildOf,
isDoc: isDoc,
ownerDoc: ownerDoc,
ownerWindow : ownerWindow,
after: after,
before: before,
prepend: prepend,
append: append,
remove: remove,
replace: replace,
throb: throb,
traverse: traverse,
reverse: reverse,
wrapper: wrapper,
wrapperInner: wrapperInner,
unwrap: unwrap
});
return skylark.noder = noder;
});