--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/resources/js/ext/tinymce/dev/classes/dom/DomQuery.js Wed Jun 17 10:00:10 2015 +0200
@@ -0,0 +1,1568 @@
+/**
+ * DomQuery.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class mimics most of the jQuery API:
+ *
+ * This is whats currently implemented:
+ * - Utility functions
+ * - DOM traversial
+ * - DOM manipulation
+ * - Event binding
+ *
+ * This is not currently implemented:
+ * - Dimension
+ * - Ajax
+ * - Animation
+ * - Advanced chaining
+ *
+ * @example
+ * var $ = tinymce.dom.DomQuery;
+ * $('p').attr('attr', 'value').addClass('class');
+ *
+ * @class tinymce.dom.DomQuery
+ */
+define("tinymce/dom/DomQuery", [
+ "tinymce/dom/EventUtils",
+ "tinymce/dom/Sizzle",
+ "tinymce/util/Tools",
+ "tinymce/Env"
+], function(EventUtils, Sizzle, Tools, Env) {
+ var doc = document, push = Array.prototype.push, slice = Array.prototype.slice;
+ var rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
+ var Event = EventUtils.Event, undef;
+
+ function isDefined(obj) {
+ return typeof obj !== 'undefined';
+ }
+
+ function isString(obj) {
+ return typeof obj === 'string';
+ }
+
+ function isWindow(obj) {
+ return obj && obj == obj.window;
+ }
+
+ function createFragment(html, fragDoc) {
+ var frag, node, container;
+
+ fragDoc = fragDoc || doc;
+ container = fragDoc.createElement('div');
+ frag = fragDoc.createDocumentFragment();
+ container.innerHTML = html;
+
+ while ((node = container.firstChild)) {
+ frag.appendChild(node);
+ }
+
+ return frag;
+ }
+
+ function domManipulate(targetNodes, sourceItem, callback, reverse) {
+ var i;
+
+ if (isString(sourceItem)) {
+ sourceItem = createFragment(sourceItem, getElementDocument(targetNodes[0]));
+ } else if (sourceItem.length && !sourceItem.nodeType) {
+ sourceItem = DomQuery.makeArray(sourceItem);
+
+ if (reverse) {
+ for (i = sourceItem.length - 1; i >= 0; i--) {
+ domManipulate(targetNodes, sourceItem[i], callback, reverse);
+ }
+ } else {
+ for (i = 0; i < sourceItem.length; i++) {
+ domManipulate(targetNodes, sourceItem[i], callback, reverse);
+ }
+ }
+
+ return targetNodes;
+ }
+
+ if (sourceItem.nodeType) {
+ i = targetNodes.length;
+ while (i--) {
+ callback.call(targetNodes[i], sourceItem);
+ }
+ }
+
+ return targetNodes;
+ }
+
+ function hasClass(node, className) {
+ return node && className && (' ' + node.className + ' ').indexOf(' ' + className + ' ') !== -1;
+ }
+
+ function wrap(elements, wrapper, all) {
+ var lastParent, newWrapper;
+
+ wrapper = DomQuery(wrapper)[0];
+
+ elements.each(function() {
+ var self = this;
+
+ if (!all || lastParent != self.parentNode) {
+ lastParent = self.parentNode;
+ newWrapper = wrapper.cloneNode(false);
+ self.parentNode.insertBefore(newWrapper, self);
+ newWrapper.appendChild(self);
+ } else {
+ newWrapper.appendChild(self);
+ }
+ });
+
+ return elements;
+ }
+
+ var numericCssMap = Tools.makeMap('fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom', ' ');
+ var booleanMap = Tools.makeMap('checked compact declare defer disabled ismap multiple nohref noshade nowrap readonly selected', ' ');
+ var propFix = {
+ 'for': 'htmlFor',
+ 'class': 'className',
+ 'readonly': 'readOnly'
+ };
+ var cssFix = {
+ 'float': 'cssFloat'
+ };
+
+ var attrHooks = {}, cssHooks = {};
+
+ function DomQuery(selector, context) {
+ /*eslint new-cap:0 */
+ return new DomQuery.fn.init(selector, context);
+ }
+
+ 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;
+ }
+
+ var whiteSpaceRegExp = /^\s*|\s*$/g;
+
+ function trim(str) {
+ return (str === null || str === undef) ? '' : ("" + str).replace(whiteSpaceRegExp, '');
+ }
+
+ 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, key, value) === false) {
+ break;
+ }
+ }
+ }
+ } else {
+ // Loop array items
+ for (i = 0; i < length; i++) {
+ value = obj[i];
+ if (callback.call(value, i, value) === false) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ }
+
+ function grep(array, callback) {
+ var out = [];
+
+ each(array, function(i, item) {
+ if (callback(item, i)) {
+ out.push(item);
+ }
+ });
+
+ return out;
+ }
+
+ function getElementDocument(element) {
+ if (!element) {
+ return doc;
+ }
+
+ if (element.nodeType == 9) {
+ return element;
+ }
+
+ return element.ownerDocument;
+ }
+
+ DomQuery.fn = DomQuery.prototype = {
+ constructor: DomQuery,
+
+ /**
+ * Selector for the current set.
+ *
+ * @property selector
+ * @type String
+ */
+ selector: "",
+
+ /**
+ * Context used to create the set.
+ *
+ * @property context
+ * @type Element
+ */
+ context: null,
+
+ /**
+ * Number of items in the current set.
+ *
+ * @property length
+ * @type Number
+ */
+ length: 0,
+
+ /**
+ * Constructs a new DomQuery instance with the specified selector or context.
+ *
+ * @constructor
+ * @method init
+ * @param {String/Array/DomQuery} selector Optional CSS selector/Array or array like object or HTML string.
+ * @param {Document/Element} context Optional context to search in.
+ */
+ 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 (context && context.nodeType) {
+ self.context = context;
+ } else {
+ if (context) {
+ return DomQuery(selector).attr(context);
+ } else {
+ self.context = context = document;
+ }
+ }
+
+ if (isString(selector)) {
+ self.selector = 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, getElementDocument(context)).firstChild;
+
+ while (node) {
+ push.call(self, node);
+ node = node.nextSibling;
+ }
+ } else {
+ node = getElementDocument(context).getElementById(match[2]);
+
+ if (!node) {
+ return self;
+ }
+
+ if (node.id !== match[2]) {
+ return self.find(selector);
+ }
+
+ self.length = 1;
+ self[0] = node;
+ }
+ } else {
+ return DomQuery(context).find(selector);
+ }
+ } else {
+ this.add(selector, false);
+ }
+
+ return self;
+ },
+
+ /**
+ * Converts the current set to an array.
+ *
+ * @method toArray
+ * @param {Array} Array of all nodes in set.
+ */
+ toArray: function() {
+ return Tools.toArray(this);
+ },
+
+ /**
+ * Adds new nodes to the set.
+ *
+ * @method add
+ * @param {Array/tinymce.dom.DomQuery} items Array of all nodes to add to set.
+ * @return {tinymce.dom.DomQuery} New instance with nodes added.
+ */
+ add: function(items, sort) {
+ var self = this, nodes, i;
+
+ if (isString(items)) {
+ return self.add(DomQuery(items));
+ }
+
+ if (sort !== false) {
+ nodes = DomQuery.unique(self.toArray().concat(DomQuery.makeArray(items)));
+ self.length = nodes.length;
+ for (i = 0; i < nodes.length; i++) {
+ self[i] = nodes[i];
+ }
+ } else {
+ push.apply(self, DomQuery.makeArray(items));
+ }
+
+ return self;
+ },
+
+ /**
+ * Sets/gets attributes on the elements in the current set.
+ *
+ * @method attr
+ * @param {String/Object} name Name of attribute to get or an object with attributes to set.
+ * @param {String} value Optional value to set.
+ * @return {tinymce.dom.DomQuery/String} Current set or the specified attribute when only the name is specified.
+ */
+ attr: function(name, value) {
+ var self = this, hook;
+
+ if (typeof name === "object") {
+ each(name, function(name, value) {
+ self.attr(name, value);
+ });
+ } else if (isDefined(value)) {
+ this.each(function() {
+ var hook;
+
+ if (this.nodeType === 1) {
+ hook = attrHooks[name];
+ if (hook && hook.set) {
+ hook.set(this, value);
+ return;
+ }
+
+ if (value === null) {
+ this.removeAttribute(name, 2);
+ } else {
+ this.setAttribute(name, value, 2);
+ }
+ }
+ });
+ } else {
+ if (self[0] && self[0].nodeType === 1) {
+ hook = attrHooks[name];
+ if (hook && hook.get) {
+ return hook.get(self[0], name);
+ }
+
+ if (booleanMap[name]) {
+ return self.prop(name) ? name : undef;
+ }
+
+ value = self[0].getAttribute(name, 2);
+
+ if (value === null) {
+ value = undef;
+ }
+ }
+
+ return value;
+ }
+
+ return self;
+ },
+
+ /**
+ * Removes attributse on the elements in the current set.
+ *
+ * @method removeAttr
+ * @param {String/Object} name Name of attribute to remove.
+ * @return {tinymce.dom.DomQuery/String} Current set.
+ */
+ removeAttr: function(name) {
+ return this.attr(name, null);
+ },
+
+ /**
+ * Sets/gets properties on the elements in the current set.
+ *
+ * @method attr
+ * @param {String/Object} name Name of property to get or an object with properties to set.
+ * @param {String} value Optional value to set.
+ * @return {tinymce.dom.DomQuery/String} Current set or the specified property when only the name is specified.
+ */
+ prop: function(name, value) {
+ var self = this;
+
+ name = propFix[name] || name;
+
+ if (typeof name === "object") {
+ each(name, function(name, value) {
+ self.prop(name, value);
+ });
+ } else if (isDefined(value)) {
+ this.each(function() {
+ if (this.nodeType == 1) {
+ this[name] = value;
+ }
+ });
+ } else {
+ if (self[0] && self[0].nodeType && name in self[0]) {
+ return self[0][name];
+ }
+
+ return value;
+ }
+
+ return self;
+ },
+
+ /**
+ * Sets/gets styles on the elements in the current set.
+ *
+ * @method css
+ * @param {String/Object} name Name of style to get or an object with styles to set.
+ * @param {String} value Optional value to set.
+ * @return {tinymce.dom.DomQuery/String} Current set or the specified style when only the name is specified.
+ */
+ css: function(name, value) {
+ var self = this, elm, hook;
+
+ function camel(name) {
+ return name.replace(/-(\D)/g, function(a, b) {
+ return b.toUpperCase();
+ });
+ }
+
+ function dashed(name) {
+ return name.replace(/[A-Z]/g, function(a) {
+ return '-' + a;
+ });
+ }
+
+ if (typeof name === "object") {
+ each(name, function(name, value) {
+ self.css(name, value);
+ });
+ } else {
+ if (isDefined(value)) {
+ name = camel(name);
+
+ // Default px suffix on these
+ if (typeof value === 'number' && !numericCssMap[name]) {
+ value += 'px';
+ }
+
+ self.each(function() {
+ var style = this.style;
+
+ hook = cssHooks[name];
+ if (hook && hook.set) {
+ hook.set(this, value);
+ return;
+ }
+
+ try {
+ this.style[cssFix[name] || name] = value;
+ } catch (ex) {
+ // Ignore
+ }
+
+ if (value === null || value === '') {
+ if (style.removeProperty) {
+ style.removeProperty(dashed(name));
+ } else {
+ style.removeAttribute(name);
+ }
+ }
+ });
+ } else {
+ elm = self[0];
+
+ hook = cssHooks[name];
+ if (hook && hook.get) {
+ return hook.get(elm);
+ }
+
+ if (elm.ownerDocument.defaultView) {
+ try {
+ return elm.ownerDocument.defaultView.getComputedStyle(elm, null).getPropertyValue(dashed(name));
+ } catch (ex) {
+ return undef;
+ }
+ } else if (elm.currentStyle) {
+ return elm.currentStyle[camel(name)];
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Removes all nodes in set from the document.
+ *
+ * @method remove
+ * @return {tinymce.dom.DomQuery} Current set with the removed nodes.
+ */
+ 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;
+ },
+
+ /**
+ * Empties all elements in set.
+ *
+ * @method empty
+ * @return {tinymce.dom.DomQuery} Current set with the empty nodes.
+ */
+ empty: function() {
+ var self = this, node, i = this.length;
+
+ while (i--) {
+ node = self[i];
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Sets or gets the HTML of the current set or first set node.
+ *
+ * @method html
+ * @param {String} value Optional innerHTML value to set on each element.
+ * @return {tinymce.dom.DomQuery/String} Current set or the innerHTML of the first element.
+ */
+ html: function(value) {
+ var self = this, i;
+
+ if (isDefined(value)) {
+ i = self.length;
+
+ try {
+ while (i--) {
+ self[i].innerHTML = value;
+ }
+ } catch (ex) {
+ // Workaround for "Unknown runtime error" when DIV is added to P on IE
+ DomQuery(self[i]).empty().append(value);
+ }
+
+ return self;
+ }
+
+ return self[0] ? self[0].innerHTML : '';
+ },
+
+ /**
+ * Sets or gets the text of the current set or first set node.
+ *
+ * @method text
+ * @param {String} value Optional innerText value to set on each element.
+ * @return {tinymce.dom.DomQuery/String} Current set or the innerText of the first element.
+ */
+ text: function(value) {
+ var self = this, i;
+
+ if (isDefined(value)) {
+ i = self.length;
+ while (i--) {
+ if ("innerText" in self[i]) {
+ self[i].innerText = value;
+ } else {
+ self[0].textContent = value;
+ }
+ }
+
+ return self;
+ }
+
+ return self[0] ? (self[0].innerText || self[0].textContent) : '';
+ },
+
+ /**
+ * Appends the specified node/html or node set to the current set nodes.
+ *
+ * @method append
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to append to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ append: function() {
+ return domManipulate(this, arguments, function(node) {
+ if (this.nodeType === 1) {
+ this.appendChild(node);
+ }
+ });
+ },
+
+ /**
+ * Prepends the specified node/html or node set to the current set nodes.
+ *
+ * @method prepend
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to prepend to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ prepend: function() {
+ return domManipulate(this, arguments, function(node) {
+ if (this.nodeType === 1) {
+ this.insertBefore(node, this.firstChild);
+ }
+ }, true);
+ },
+
+ /**
+ * Adds the specified elements before current set nodes.
+ *
+ * @method before
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to add before to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ before: function() {
+ var self = this;
+
+ if (self[0] && self[0].parentNode) {
+ return domManipulate(self, arguments, function(node) {
+ this.parentNode.insertBefore(node, this);
+ });
+ }
+
+ return self;
+ },
+
+ /**
+ * Adds the specified elements after current set nodes.
+ *
+ * @method after
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to add after to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ after: function() {
+ var self = this;
+
+ if (self[0] && self[0].parentNode) {
+ return domManipulate(self, arguments, function(node) {
+ this.parentNode.insertBefore(node, this.nextSibling);
+ }, true);
+ }
+
+ return self;
+ },
+
+ /**
+ * Appends the specified set nodes to the specified selector/instance.
+ *
+ * @method appendTo
+ * @param {String/Element/Array/tinymce.dom.DomQuery} val Item to append the current set to.
+ * @return {tinymce.dom.DomQuery} Current set with the appended nodes.
+ */
+ appendTo: function(val) {
+ DomQuery(val).append(this);
+
+ return this;
+ },
+
+ /**
+ * Prepends the specified set nodes to the specified selector/instance.
+ *
+ * @method prependTo
+ * @param {String/Element/Array/tinymce.dom.DomQuery} val Item to prepend the current set to.
+ * @return {tinymce.dom.DomQuery} Current set with the prepended nodes.
+ */
+ prependTo: function(val) {
+ DomQuery(val).prepend(this);
+
+ return this;
+ },
+
+ /**
+ * Replaces the nodes in set with the specified content.
+ *
+ * @method replaceWith
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to replace nodes with.
+ * @return {tinymce.dom.DomQuery} Set with replaced nodes.
+ */
+ replaceWith: function(content) {
+ return this.before(content).remove();
+ },
+
+ /**
+ * Wraps all elements in set with the specified wrapper.
+ *
+ * @method wrap
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to wrap nodes with.
+ * @return {tinymce.dom.DomQuery} Set with wrapped nodes.
+ */
+ wrap: function(wrapper) {
+ return wrap(this, wrapper);
+ },
+
+ /**
+ * Wraps all nodes in set with the specified wrapper. If the nodes are siblings all of them
+ * will be wrapped in the same wrapper.
+ *
+ * @method wrapAll
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to wrap nodes with.
+ * @return {tinymce.dom.DomQuery} Set with wrapped nodes.
+ */
+ wrapAll: function(wrapper) {
+ return wrap(this, wrapper, true);
+ },
+
+ /**
+ * Wraps all elements inner contents in set with the specified wrapper.
+ *
+ * @method wrapInner
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to wrap nodes with.
+ * @return {tinymce.dom.DomQuery} Set with wrapped nodes.
+ */
+ wrapInner: function(wrapper) {
+ this.each(function() {
+ DomQuery(this).contents().wrapAll(wrapper);
+ });
+
+ return this;
+ },
+
+ /**
+ * Unwraps all elements by removing the parent element of each item in set.
+ *
+ * @method unwrap
+ * @return {tinymce.dom.DomQuery} Set with unwrapped nodes.
+ */
+ unwrap: function() {
+ return this.parent().each(function() {
+ DomQuery(this).replaceWith(this.childNodes);
+ });
+ },
+
+ /**
+ * Clones all nodes in set.
+ *
+ * @method clone
+ * @return {tinymce.dom.DomQuery} Set with cloned nodes.
+ */
+ clone: function() {
+ var result = [];
+
+ this.each(function() {
+ result.push(this.cloneNode(true));
+ });
+
+ return DomQuery(result);
+ },
+
+ /**
+ * Adds the specified class name to the current set elements.
+ *
+ * @method addClass
+ * @param {String} className Class name to add.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ addClass: function(className) {
+ return this.toggleClass(className, true);
+ },
+
+ /**
+ * Removes the specified class name to the current set elements.
+ *
+ * @method removeClass
+ * @param {String} className Class name to remove.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ removeClass: function(className) {
+ return this.toggleClass(className, false);
+ },
+
+ /**
+ * Toggles the specified class name on the current set elements.
+ *
+ * @method toggleClass
+ * @param {String} className Class name to add/remove.
+ * @param {Boolean} state Optional state to toggle on/off.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ toggleClass: function(className, state) {
+ var self = this;
+
+ // Functions are not supported
+ if (typeof className != 'string') {
+ return self;
+ }
+
+ if (className.indexOf(' ') !== -1) {
+ each(className.split(' '), function() {
+ self.toggleClass(this, state);
+ });
+ } else {
+ self.each(function(index, node) {
+ var existingClassName, classState;
+
+ classState = hasClass(node, className);
+ if (classState !== state) {
+ existingClassName = node.className;
+
+ if (classState) {
+ node.className = trim((" " + existingClassName + " ").replace(' ' + className + ' ', ' '));
+ } else {
+ node.className += existingClassName ? ' ' + className : className;
+ }
+ }
+ });
+ }
+
+ return self;
+ },
+
+ /**
+ * Returns true/false if the first item in set has the specified class.
+ *
+ * @method hasClass
+ * @param {String} className Class name to check for.
+ * @return {Boolean} True/false if the set has the specified class.
+ */
+ hasClass: function(className) {
+ return hasClass(this[0], className);
+ },
+
+ /**
+ * Executes the callback function for each item DomQuery collection. If you return false in the
+ * callback it will break the loop.
+ *
+ * @method each
+ * @param {function} callback Callback function to execute for each item.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ each: function(callback) {
+ return each(this, callback);
+ },
+
+ /**
+ * Binds an event with callback function to the elements in set.
+ *
+ * @method on
+ * @param {String} name Name of the event to bind.
+ * @param {function} callback Callback function to execute when the event occurs.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ on: function(name, callback) {
+ return this.each(function() {
+ Event.bind(this, name, callback);
+ });
+ },
+
+ /**
+ * Unbinds an event with callback function to the elements in set.
+ *
+ * @method off
+ * @param {String} name Optional name of the event to bind.
+ * @param {function} callback Optional callback function to execute when the event occurs.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ off: function(name, callback) {
+ return this.each(function() {
+ Event.unbind(this, name, callback);
+ });
+ },
+
+ /**
+ * Triggers the specified event by name or event object.
+ *
+ * @method trigger
+ * @param {String/Object} name Name of the event to trigger or event object.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ trigger: function(name) {
+ return this.each(function() {
+ if (typeof name == 'object') {
+ Event.fire(this, name.type, name);
+ } else {
+ Event.fire(this, name);
+ }
+ });
+ },
+
+ /**
+ * Shows all elements in set.
+ *
+ * @method show
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ show: function() {
+ return this.css('display', '');
+ },
+
+ /**
+ * Hides all elements in set.
+ *
+ * @method hide
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ hide: function() {
+ return this.css('display', 'none');
+ },
+
+ /**
+ * Slices the current set.
+ *
+ * @method slice
+ * @param {Number} start Start index to slice at.
+ * @param {Number} end Optional ened index to end slice at.
+ * @return {tinymce.dom.DomQuery} Sliced set.
+ */
+ slice: function() {
+ return new DomQuery(slice.apply(this, arguments));
+ },
+
+ /**
+ * Makes the set equal to the specified index.
+ *
+ * @method eq
+ * @param {Number} index Index to set it equal to.
+ * @return {tinymce.dom.DomQuery} Single item set.
+ */
+ eq: function(index) {
+ return index === -1 ? this.slice(index) : this.slice(index, +index + 1);
+ },
+
+ /**
+ * Makes the set equal to first element in set.
+ *
+ * @method first
+ * @return {tinymce.dom.DomQuery} Single item set.
+ */
+ first: function() {
+ return this.eq(0);
+ },
+
+ /**
+ * Makes the set equal to last element in set.
+ *
+ * @method last
+ * @return {tinymce.dom.DomQuery} Single item set.
+ */
+ last: function() {
+ return this.eq(-1);
+ },
+
+ /**
+ * Finds elements by the specified selector for each element in set.
+ *
+ * @method find
+ * @param {String} selector Selector to find elements by.
+ * @return {tinymce.dom.DomQuery} Set with matches elements.
+ */
+ 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);
+ },
+
+ /**
+ * Filters the current set with the specified selector.
+ *
+ * @method filter
+ * @param {String/function} selector Selector to filter elements by.
+ * @return {tinymce.dom.DomQuery} Set with filtered elements.
+ */
+ filter: function(selector) {
+ if (typeof selector == 'function') {
+ return DomQuery(grep(this.toArray(), function(item, i) {
+ return selector(i, item);
+ }));
+ }
+
+ return DomQuery(DomQuery.filter(selector, this.toArray()));
+ },
+
+ /**
+ * Gets the current node or any partent matching the specified selector.
+ *
+ * @method closest
+ * @param {String/Element/tinymce.dom.DomQuery} selector Selector or element to find.
+ * @return {tinymce.dom.DomQuery} Set with closest elements.
+ */
+ closest: function(selector) {
+ var result = [];
+
+ if (selector instanceof DomQuery) {
+ selector = selector[0];
+ }
+
+ this.each(function(i, node) {
+ while (node) {
+ if (typeof selector == 'string' && DomQuery(node).is(selector)) {
+ result.push(node);
+ break;
+ } else if (node == selector) {
+ result.push(node);
+ break;
+ }
+
+ node = node.parentNode;
+ }
+ });
+
+ return DomQuery(result);
+ },
+
+ /**
+ * Returns the offset of the first element in set or sets the top/left css properties of all elements in set.
+ *
+ * @method offset
+ * @param {Object} offset Optional offset object to set on each item.
+ * @return {Object/tinymce.dom.DomQuery} Returns the first element offset or the current set if you specified an offset.
+ */
+ offset: function(offset) {
+ var elm, doc, docElm;
+ var x = 0, y = 0, pos;
+
+ if (!offset) {
+ elm = this[0];
+
+ if (elm) {
+ doc = elm.ownerDocument;
+ docElm = doc.documentElement;
+
+ if (elm.getBoundingClientRect) {
+ pos = elm.getBoundingClientRect();
+ x = pos.left + (docElm.scrollLeft || doc.body.scrollLeft) - docElm.clientLeft;
+ y = pos.top + (docElm.scrollTop || doc.body.scrollTop) - docElm.clientTop;
+ }
+ }
+
+ return {
+ left: x,
+ top: y
+ };
+ }
+
+ return this.css(offset);
+ },
+
+ push: push,
+ sort: [].sort,
+ splice: [].splice
+ };
+
+ // Static members
+ Tools.extend(DomQuery, {
+ /**
+ * Extends the specified object with one or more objects.
+ *
+ * @static
+ * @method extend
+ * @param {Object} target Target object to extend with new items.
+ * @param {Object..} object Object to extend the target with.
+ * @return {Object} Extended input object.
+ */
+ extend: Tools.extend,
+
+ /**
+ * Creates an array out of an array like object.
+ *
+ * @static
+ * @method makeArray
+ * @param {Object} object Object to convert to array.
+ * @return {Arrau} Array produced from object.
+ */
+ makeArray: function(array) {
+ if (isWindow(array) || array.nodeType) {
+ return [array];
+ }
+
+ return Tools.toArray(array);
+ },
+
+ /**
+ * Returns the index of the specified item inside the array.
+ *
+ * @static
+ * @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.
+ */
+ inArray: inArray,
+
+ /**
+ * Returns true/false if the specified object is an array or not.
+ *
+ * @static
+ * @method isArray
+ * @param {Object} array Object to check if it's an array or not.
+ * @return {Boolean} True/false if the object is an array.
+ */
+ isArray: Tools.isArray,
+
+ /**
+ * Executes the callback function for each item in array/object. If you return false in the
+ * callback it will break the loop.
+ *
+ * @static
+ * @method each
+ * @param {Object} obj Object to iterate.
+ * @param {function} callback Callback function to execute for each item.
+ */
+ each: each,
+
+ /**
+ * Removes whitespace from the beginning and end of a string.
+ *
+ * @static
+ * @method trim
+ * @param {String} str String to remove whitespace from.
+ * @return {String} New string with removed whitespace.
+ */
+ trim: trim,
+
+ /**
+ * Filters out items from the input array by calling the specified function for each item.
+ * If the function returns false the item will be excluded if it returns true it will be included.
+ *
+ * @static
+ * @method grep
+ * @param {Array} array Array of items to loop though.
+ * @param {function} callback Function to call for each item. Include/exclude depends on it's return value.
+ * @return {Array} New array with values imported and filtered based in input.
+ * @example
+ * // Filter out some items, this will return an array with 4 and 5
+ * var items = DomQuery.grep([1, 2, 3, 4, 5], function(v) {return v > 3;});
+ */
+ grep: grep,
+
+ // Sizzle
+ find: Sizzle,
+ expr: Sizzle.selectors,
+ unique: Sizzle.uniqueSort,
+ text: Sizzle.getText,
+ contains: Sizzle.contains,
+ filter: function(expr, elems, not) {
+ var i = elems.length;
+
+ if (not) {
+ expr = ":not(" + expr + ")";
+ }
+
+ while (i--) {
+ if (elems[i].nodeType != 1) {
+ elems.splice(i, 1);
+ }
+ }
+
+ if (elems.length === 1) {
+ elems = DomQuery.find.matchesSelector(elems[0], expr) ? [elems[0]] : [];
+ } else {
+ elems = DomQuery.find.matches(expr, elems);
+ }
+
+ return elems;
+ }
+ });
+
+ function dir(el, prop, until) {
+ var matched = [], cur = el[prop];
+
+ if (typeof until != 'string' && until instanceof DomQuery) {
+ until = until[0];
+ }
+
+ while (cur && cur.nodeType !== 9) {
+ if (until !== undefined) {
+ if (cur === until) {
+ break;
+ }
+
+ if (typeof until == 'string' && DomQuery(cur).is(until)) {
+ break;
+ }
+ }
+
+ if (cur.nodeType === 1) {
+ matched.push(cur);
+ }
+
+ cur = cur[prop];
+ }
+
+ return matched;
+ }
+
+ function sibling(node, siblingName, nodeType, until) {
+ var result = [];
+
+ if (until instanceof DomQuery) {
+ until = until[0];
+ }
+
+ for (; node; node = node[siblingName]) {
+ if (nodeType && node.nodeType !== nodeType) {
+ continue;
+ }
+
+ if (until !== undefined) {
+ if (node === until) {
+ break;
+ }
+
+ if (typeof until == 'string' && DomQuery(node).is(until)) {
+ break;
+ }
+ }
+
+ result.push(node);
+ }
+
+ return result;
+ }
+
+ function firstSibling(node, siblingName, nodeType) {
+ for (node = node[siblingName]; node; node = node[siblingName]) {
+ if (node.nodeType == nodeType) {
+ return node;
+ }
+ }
+
+ return null;
+ }
+
+ each({
+ /**
+ * Returns a new collection with the parent of each item in current collection matching the optional selector.
+ *
+ * @method parent
+ * @param {String} selector Selector to match parents agains.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching parents.
+ */
+ parent: function(node) {
+ var parent = node.parentNode;
+
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+
+ /**
+ * Returns a new collection with the all the parents of each item in current collection matching the optional selector.
+ *
+ * @method parents
+ * @param {String} selector Selector to match parents agains.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching parents.
+ */
+ parents: function(node) {
+ return dir(node, "parentNode");
+ },
+
+ /**
+ * Returns a new collection with next sibling of each item in current collection matching the optional selector.
+ *
+ * @method next
+ * @param {String} selector Selector to match the next element against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ next: function(node) {
+ return firstSibling(node, 'nextSibling', 1);
+ },
+
+ /**
+ * Returns a new collection with previous sibling of each item in current collection matching the optional selector.
+ *
+ * @method prev
+ * @param {String} selector Selector to match the previous element against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ prev: function(node) {
+ return firstSibling(node, 'previousSibling', 1);
+ },
+
+ /**
+ * Returns all child elements matching the optional selector.
+ *
+ * @method children
+ * @param {String} selector Selector to match the elements against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ children: function(node) {
+ return sibling(node.firstChild, 'nextSibling', 1);
+ },
+
+ /**
+ * Returns all child nodes matching the optional selector.
+ *
+ * @method contents
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ contents: function(node) {
+ return Tools.toArray((node.nodeName === "iframe" ? node.contentDocument || node.contentWindow.document : node).childNodes);
+ }
+ }, function(name, fn) {
+ DomQuery.fn[name] = function(selector) {
+ var self = this, result = [];
+
+ self.each(function() {
+ var nodes = fn.call(result, this, selector, result);
+
+ if (nodes) {
+ if (DomQuery.isArray(nodes)) {
+ result.push.apply(result, nodes);
+ } else {
+ result.push(nodes);
+ }
+ }
+ });
+
+ // If traversing on multiple elements we might get the same elements twice
+ if (this.length > 1) {
+ result = DomQuery.unique(result);
+
+ if (name.indexOf('parents') === 0) {
+ result = result.reverse();
+ }
+ }
+
+ result = DomQuery(result);
+
+ if (selector) {
+ return result.filter(selector);
+ }
+
+ return result;
+ };
+ });
+
+ each({
+ /**
+ * Returns a new collection with the all the parents until the matching selector/element
+ * of each item in current collection matching the optional selector.
+ *
+ * @method parentsUntil
+ * @param {String/Element/tinymce.dom.DomQuery} until Until the matching selector or element.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching parents.
+ */
+ parentsUntil: function(node, until) {
+ return dir(node, "parentNode", until);
+ },
+
+ /**
+ * Returns a new collection with all next siblings of each item in current collection matching the optional selector.
+ *
+ * @method nextUntil
+ * @param {String/Element/tinymce.dom.DomQuery} until Until the matching selector or element.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ nextUntil: function(node, until) {
+ return sibling(node, 'nextSibling', 1, until).slice(1);
+ },
+
+ /**
+ * Returns a new collection with all previous siblings of each item in current collection matching the optional selector.
+ *
+ * @method prevUntil
+ * @param {String/Element/tinymce.dom.DomQuery} until Until the matching selector or element.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ prevUntil: function(node, until) {
+ return sibling(node, 'previousSibling', 1, until).slice(1);
+ }
+ }, function(name, fn) {
+ DomQuery.fn[name] = function(selector, filter) {
+ var self = this, result = [];
+
+ self.each(function() {
+ var nodes = fn.call(result, this, selector, result);
+
+ if (nodes) {
+ if (DomQuery.isArray(nodes)) {
+ result.push.apply(result, nodes);
+ } else {
+ result.push(nodes);
+ }
+ }
+ });
+
+ // If traversing on multiple elements we might get the same elements twice
+ if (this.length > 1) {
+ result = DomQuery.unique(result);
+
+ if (name.indexOf('parents') === 0 || name === 'prevUntil') {
+ result = result.reverse();
+ }
+ }
+
+ result = DomQuery(result);
+
+ if (filter) {
+ return result.filter(filter);
+ }
+
+ return result;
+ };
+ });
+
+ /**
+ * Returns true/false if the current set items matches the selector.
+ *
+ * @method is
+ * @param {String} selector Selector to match the elements against.
+ * @return {Boolean} True/false if the current set matches the selector.
+ */
+ DomQuery.fn.is = function(selector) {
+ return !!selector && this.filter(selector).length > 0;
+ };
+
+ DomQuery.fn.init.prototype = DomQuery.fn;
+
+ DomQuery.overrideDefaults = function(callback) {
+ var defaults;
+
+ function sub(selector, context) {
+ defaults = defaults || callback();
+
+ if (arguments.length === 0) {
+ selector = defaults.element;
+ }
+
+ if (!context) {
+ context = defaults.context;
+ }
+
+ return new sub.fn.init(selector, context);
+ }
+
+ DomQuery.extend(sub, this);
+
+ return sub;
+ };
+
+ function appendHooks(targetHooks, prop, hooks) {
+ each(hooks, function(name, func) {
+ targetHooks[name] = targetHooks[name] || {};
+ targetHooks[name][prop] = func;
+ });
+ }
+
+ if (Env.ie && Env.ie < 8) {
+ appendHooks(attrHooks, 'get', {
+ maxlength: function(elm) {
+ var value = elm.maxLength;
+
+ if (value === 0x7fffffff) {
+ return undef;
+ }
+
+ return value;
+ },
+
+ size: function(elm) {
+ var value = elm.size;
+
+ if (value === 20) {
+ return undef;
+ }
+
+ return value;
+ },
+
+ 'class': function(elm) {
+ return elm.className;
+ },
+
+ style: function(elm) {
+ var value = elm.style.cssText;
+
+ if (value.length === 0) {
+ return undef;
+ }
+
+ return value;
+ }
+ });
+
+ appendHooks(attrHooks, 'set', {
+ 'class': function(elm, value) {
+ elm.className = value;
+ },
+
+ style: function(elm, value) {
+ elm.style.cssText = value;
+ }
+ });
+ }
+
+ if (Env.ie && Env.ie < 9) {
+ /*jshint sub:true */
+ /*eslint dot-notation: 0*/
+ cssFix['float'] = 'styleFloat';
+
+ appendHooks(cssHooks, 'set', {
+ opacity: function(elm, value) {
+ var style = elm.style;
+
+ if (value === null || value === '') {
+ style.removeAttribute('filter');
+ } else {
+ style.zoom = 1;
+ style.filter = 'alpha(opacity=' + (value * 100) + ')';
+ }
+ }
+ });
+ }
+
+ DomQuery.attrHooks = attrHooks;
+ DomQuery.cssHooks = cssHooks;
+
+ return DomQuery;
+});