tinymce-editor/copy_this/modules/hdi/hdi-tinymce/tinymce/classes/dom/DomQuery.js
2013-07-25 23:50:43 +02:00

724 lines
14 KiB
JavaScript
Executable File

/**
* DomQuery.js
*
* Copyright, Moxiecode Systems AB
* Released under LGPL License.
*
* License: http://www.tinymce.com/license
* Contributing: http://www.tinymce.com/contributing
*
* Some of this logic is based on jQuery code that is released under
* MIT license that grants us to sublicense it under LGPL.
*
* @ignore-file
*/
/**
* @class tinymce.dom.DomQuery
*/
define("tinymce/dom/DomQuery", [
"tinymce/dom/EventUtils",
"tinymce/dom/Sizzle"
], function(EventUtils, Sizzle) {
var doc = document, push = Array.prototype.push, slice = Array.prototype.slice;
var rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
var Event = EventUtils.Event;
function isDefined(obj) {
return typeof obj !== "undefined";
}
function isString(obj) {
return typeof obj === "string";
}
function createFragment(html) {
var frag, node, container;
container = doc.createElement("div");
frag = doc.createDocumentFragment();
container.innerHTML = html;
while ((node = container.firstChild)) {
frag.appendChild(node);
}
return frag;
}
function domManipulate(targetNodes, sourceItem, callback) {
var i;
if (typeof sourceItem === "string") {
sourceItem = createFragment(sourceItem);
} else if (sourceItem.length) {
for (i = 0; i < sourceItem.length; i++) {
domManipulate(targetNodes, sourceItem[i], callback);
}
return targetNodes;
}
i = targetNodes.length;
while (i--) {
callback.call(targetNodes[i], sourceItem.parentNode ? sourceItem : sourceItem);
}
return targetNodes;
}
function hasClass(node, className) {
return node && className && (' ' + node.className + ' ').indexOf(' ' + className + ' ') !== -1;
}
/**
* Makes a map object out of a string that gets separated by a delimiter.
*
* @method makeMap
* @param {String} items Item string to split.
* @param {Object} map Optional object to add items to.
* @return {Object} name/value object with items as keys.
*/
function makeMap(items, map) {
var i;
items = items || [];
if (typeof(items) == "string") {
items = items.split(' ');
}
map = map || {};
i = items.length;
while (i--) {
map[items[i]] = {};
}
return map;
}
var numericCssMap = makeMap('fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom');
function DomQuery(selector, context) {
return new DomQuery.fn.init(selector, context);
}
/**
* Extends the specified object with another object.
*
* @method extend
* @param {Object} target Object to extend.
* @param {Object..} obj Multiple objects to extend with.
* @return {Object} Same as target, the extended object.
*/
function extend(target) {
var args = arguments, arg, i, key;
for (i = 1; i < args.length; i++) {
arg = args[i];
for (key in arg) {
target[key] = arg[key];
}
}
return target;
}
/**
* Converts the specified object into a real JavaScript array.
*
* @method toArray
* @param {Object} obj Object to convert into array.
* @return {Array} Array object based in input.
*/
function toArray(obj) {
var array = [], i, l;
for (i = 0, l = obj.length; i < l; i++) {
array[i] = obj[i];
}
return array;
}
/**
* Returns the index of the specified item inside the array.
*
* @method inArray
* @param {Object} item Item to look for.
* @param {Array} array Array to look for item in.
* @return {Number} Index of the item or -1.
*/
function inArray(item, array) {
var i;
if (array.indexOf) {
return array.indexOf(item);
}
i = array.length;
while (i--) {
if (array[i] === item) {
return i;
}
}
return -1;
}
/**
* Returns true/false if the specified object is an array.
*
* @method isArray
* @param {Object} obj Object to check if it's an array.
* @return {Boolean} true/false if the input object is array or not.
*/
var isArray = Array.isArray || function(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
var whiteSpaceRegExp = /^\s*|\s*$/g;
var trim = function(str) {
return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, '');
};
/**
* Executes the callback function for each item in array/object. If you return false in the
* callback it will break the loop.
*
* @method each
* @param {Object} obj Object to iterate.
* @param {function} callback Callback function to execute for each item.
*/
function each(obj, callback) {
var length, key, i, undef, value;
if (obj) {
length = obj.length;
if (length === undef) {
// Loop object items
for (key in obj) {
if (obj.hasOwnProperty(key)) {
value = obj[key];
if (callback.call(value, value, key) === false) {
break;
}
}
}
} else {
// Loop array items
for (i = 0; i < length; i++) {
value = obj[i];
if (callback.call(value, value, key) === false) {
break;
}
}
}
}
return obj;
}
DomQuery.fn = DomQuery.prototype = {
constructor: DomQuery,
selector: "",
length: 0,
init: function(selector, context) {
var self = this, match, node;
if (!selector) {
return self;
}
if (selector.nodeType) {
self.context = self[0] = selector;
self.length = 1;
return self;
}
if (isString(selector)) {
if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) {
match = [null, selector, null];
} else {
match = rquickExpr.exec(selector);
}
if (match) {
if (match[1]) {
node = createFragment(selector).firstChild;
while (node) {
this.add(node);
node = node.nextSibling;
}
} else {
node = doc.getElementById(match[2]);
if (node.id !== match[2]) {
return self.find(selector);
}
self.length = 1;
self[0] = node;
}
} else {
return DomQuery(context || document).find(selector);
}
} else {
this.add(selector);
}
return self;
},
toArray: function() {
return toArray(this);
},
add: function(items) {
var self = this;
// Force single item into array
if (!isArray(items)) {
if (items instanceof DomQuery) {
self.add(items.toArray());
} else {
push.call(self, items);
}
} else {
push.apply(self, items);
}
return self;
},
attr: function(name, value) {
var self = this;
if (typeof name === "object") {
each(name, function(value, name) {
self.attr(name, value);
});
} else if (isDefined(value)) {
this.each(function() {
if (this.nodeType === 1) {
this.setAttribute(name, value);
}
});
} else {
return self[0] && self[0].nodeType === 1 ? self[0].getAttribute(name) : undefined;
}
return self;
},
css: function(name, value) {
var self = this;
if (typeof name === "object") {
each(name, function(value, name) {
self.css(name, value);
});
} else {
// Camelcase it, if needed
name = name.replace(/-(\D)/g, function(a, b) {
return b.toUpperCase();
});
if (isDefined(value)) {
// Default px suffix on these
if (typeof(value) === 'number' && !numericCssMap[name]) {
value += 'px';
}
self.each(function() {
var style = this.style;
// IE specific opacity
if (name === "opacity" && this.runtimeStyle && typeof(this.runtimeStyle.opacity) === "undefined") {
style.filter = value === '' ? '' : "alpha(opacity=" + (value * 100) + ")";
}
try {
style[name] = value;
} catch (ex) {
// Ignore
}
});
} else {
return self[0] ? self[0].style[name] : undefined;
}
}
return self;
},
remove: function() {
var self = this, node, i = this.length;
while (i--) {
node = self[i];
Event.clean(node);
if (node.parentNode) {
node.parentNode.removeChild(node);
}
}
return this;
},
empty: function() {
var self = this, node, i = this.length;
while (i--) {
node = self[i];
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
return this;
},
html: function(value) {
var self = this, i;
if (isDefined(value)) {
i = self.length;
while (i--) {
self[i].innerHTML = value;
}
return self;
}
return self[0] ? self[0].innerHTML : '';
},
text: function(value) {
var self = this, i;
if (isDefined(value)) {
i = self.length;
while (i--) {
self[i].innerText = self[0].textContent = value;
}
return self;
}
return self[0] ? self[0].innerText || self[0].textContent : '';
},
append: function() {
return domManipulate(this, arguments, function(node) {
if (this.nodeType === 1) {
this.appendChild(node);
}
});
},
prepend: function() {
return domManipulate(this, arguments, function(node) {
if (this.nodeType === 1) {
this.insertBefore(node, this.firstChild);
}
});
},
before: function() {
var self = this;
if (self[0] && self[0].parentNode) {
return domManipulate(self, arguments, function(node) {
this.parentNode.insertBefore(node, this.nextSibling);
});
}
return self;
},
after: function() {
var self = this;
if (self[0] && self[0].parentNode) {
return domManipulate(self, arguments, function(node) {
this.parentNode.insertBefore(node, this);
});
}
return self;
},
appendTo: function(val) {
DomQuery(val).append(this);
return this;
},
addClass: function(className) {
return this.toggleClass(className, true);
},
removeClass: function(className) {
return this.toggleClass(className, false);
},
toggleClass: function(className, state) {
var self = this;
if (className.indexOf(' ') !== -1) {
each(className.split(' '), function() {
self.toggleClass(this, state);
});
} else {
self.each(function() {
var node = this, existingClassName;
if (hasClass(node, className) !== state) {
existingClassName = node.className;
if (state) {
node.className += existingClassName ? ' ' + className : className;
} else {
node.className = trim((" " + existingClassName + " ").replace(' ' + className + ' ', ' '));
}
}
});
}
return self;
},
hasClass: function(className) {
return hasClass(this[0], className);
},
each: function(callback) {
return each(this, callback);
},
on: function(name, callback) {
return this.each(function() {
Event.bind(this, name, callback);
});
},
off: function(name, callback) {
return this.each(function() {
Event.unbind(this, name, callback);
});
},
show: function() {
return this.css('display', '');
},
hide: function() {
return this.css('display', 'none');
},
slice: function() {
return new DomQuery(slice.apply(this, arguments));
},
eq: function(index) {
return index === -1 ? this.slice(index) : this.slice(index, +index + 1);
},
first: function() {
return this.eq(0);
},
last: function() {
return this.eq(-1);
},
replaceWith: function(content) {
var self = this;
if (self[0]) {
self[0].parentNode.replaceChild(DomQuery(content)[0], self[0]);
}
return self;
},
wrap: function(wrapper) {
wrapper = DomQuery(wrapper)[0];
return this.each(function() {
var self = this, newWrapper = wrapper.cloneNode(false);
self.parentNode.insertBefore(newWrapper, self);
newWrapper.appendChild(self);
});
},
unwrap: function() {
return this.each(function() {
var self = this, node = self.firstChild, currentNode;
while (node) {
currentNode = node;
node = node.nextSibling;
self.parentNode.insertBefore(currentNode, self);
}
});
},
clone: function() {
var result = [];
this.each(function() {
result.push(this.cloneNode(true));
});
return DomQuery(result);
},
find: function(selector) {
var i, l, ret = [];
for (i = 0, l = this.length; i < l; i++) {
DomQuery.find(selector, this[i], ret);
}
return DomQuery(ret);
},
push: push,
sort: [].sort,
splice: [].splice
};
// Static members
extend(DomQuery, {
extend: extend,
toArray: toArray,
inArray: inArray,
isArray: isArray,
each: each,
trim: trim,
makeMap: makeMap,
// Sizzle
find: Sizzle,
expr: Sizzle.selectors,
unique: Sizzle.uniqueSort,
text: Sizzle.getText,
isXMLDoc: Sizzle.isXML,
contains: Sizzle.contains,
filter: function(expr, elems, not) {
if (not) {
expr = ":not(" + expr + ")";
}
return elems.length === 1 ?
DomQuery.find.matchesSelector(elems[0], expr) ? [elems[0]] : [] :
DomQuery.find.matches(expr, elems);
}
});
function dir(el, prop, until) {
var matched = [], cur = el[prop];
while (cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !DomQuery(cur).is(until))) {
if (cur.nodeType === 1) {
matched.push(cur);
}
cur = cur[prop];
}
return matched;
}
function sibling(n, el, siblingName, nodeType) {
var r = [];
for(; n; n = n[siblingName]) {
if ((!nodeType || n.nodeType === nodeType) && n !== el) {
r.push(n);
}
}
return r;
}
each({
parent: function(node) {
var parent = node.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
},
parents: function(node) {
return dir(node, "parentNode");
},
parentsUntil: function(node, until) {
return dir(node, "parentNode", until);
},
next: function(node) {
return sibling(node, 'nextSibling', 1);
},
prev: function(node) {
return sibling(node, 'previousSibling', 1);
},
nextNodes: function(node) {
return sibling(node, 'nextSibling');
},
prevNodes: function(node) {
return sibling(node, 'previousSibling');
},
children: function(node) {
return sibling(node.firstChild, 'nextSibling', 1);
},
contents: function(node) {
return toArray((node.nodeName === "iframe" ? node.contentDocument || node.contentWindow.document : node).childNodes);
}
}, function(name, fn){
DomQuery.fn[name] = function(selector) {
var self = this, result;
if (self.length > 1) {
throw new Error("DomQuery only supports traverse functions on a single node.");
}
if (self[0]) {
result = fn(self[0], selector);
}
result = DomQuery(result);
if (selector && name !== "parentsUntil") {
return result.filter(selector);
}
return result;
};
});
DomQuery.fn.filter = function(selector) {
return DomQuery.filter(selector);
};
DomQuery.fn.is = function(selector) {
return !!selector && this.filter(selector).length > 0;
};
DomQuery.fn.init.prototype = DomQuery.fn;
return DomQuery;
});