/* * aciTree jQuery Plugin v4.5.0-rc.7 * http://acoderinsights.ro * * Copyright (c) 2014 Dragos Ursu * Dual licensed under the MIT or GPL Version 2 licenses. * * Require jQuery Library >= v1.9.0 http://jquery.com * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin */ /* * The aciTree low-level DOM functions. * * A collection of functions optimised for aciTree DOM structure. * * Need to be included before the aciTree core and after aciPlugin. */ aciPluginClass.plugins.aciTree_dom = { // get the UL container from a LI // `node` must be valid LI DOM node // can return NULL container: function(node) { var container = node.lastChild; if (container && (container.nodeName == 'UL')) { return container; } return null; }, // get the first children from a LI (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node // can return NULL firstChild: function(node, callback) { var container = this.container(node); if (container) { var firstChild = container.firstChild; if (callback) { while (firstChild && !callback.call(this, firstChild)) { firstChild = firstChild.nextSibling; } } return firstChild; } return null; }, // get the last children from a LI (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node // can return NULL lastChild: function(node, callback) { var container = this.container(node); if (container) { var lastChild = container.lastChild; if (callback) { while (lastChild && !callback.call(this, lastChild)) { lastChild = lastChild.previousSibling; } } return lastChild; } return null; }, // get the previous LI sibling (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node // can return NULL prev: function(node, callback) { var previous = node.previousSibling; if (callback) { while (previous && !callback.call(this, previous)) { previous = previous.previousSibling; } } return previous; }, // get the next LI sibling (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node // can return NULL next: function(node, callback) { var next = node.nextSibling; if (callback) { while (next && !callback.call(this, next)) { next = next.nextSibling; } } return next; }, // get the previous LI in tree order (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node // can return NULL prevAll: function(node, callback) { var previous, lastChild, drillDown, match, prev, parent; while (true) { previous = this.prev(node); if (previous) { if (callback) { match = callback.call(this, previous); if (match === null) { node = previous; continue; } } lastChild = this.lastChild(previous); if (lastChild) { if (callback && (callback.call(this, lastChild) === null)) { node = lastChild; continue; } prev = false; while (drillDown = this.lastChild(lastChild)) { lastChild = drillDown; if (callback) { match = callback.call(this, lastChild); if (match === null) { node = lastChild; prev = true; break; } } } if (prev) { continue; } if (callback) { match = callback.call(this, lastChild); if (match) { return lastChild; } else if (match !== null) { node = lastChild; continue; } } else { return lastChild; } } else { if (!callback || match) { return previous; } else { node = previous; continue; } } } parent = this.parent(node); if (parent) { if (callback) { match = callback.call(this, parent); if (match) { return parent; } else { node = parent; } } else { return parent; } } else { return null; } } return null; }, // get the next LI in tree order (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node // can return NULL nextAll: function(node, callback) { var firstChild, match, next, parent, child; while (true) { firstChild = this.firstChild(node); if (firstChild) { if (callback) { match = callback.call(this, firstChild); if (match) { return firstChild; } else { node = firstChild; if (match !== null) { continue; } } } else { return firstChild; } } while (true) { next = this.next(node); if (next) { if (callback) { match = callback.call(this, next); if (match) { return next; } else { node = next; if (match !== null) { break; } else { continue; } } } else { return next; } } else { parent = node; child = null; while (parent = this.parent(parent)) { next = this.next(parent); if (next) { if (callback) { match = callback.call(this, next); if (match) { return next; } else { node = next; if (match !== null) { child = true; } else { child = false; } break; } } else { return next; } } } if (child !== null) { if (child) { break; } else { continue; } } return null; } } } return null; }, // get the first LI in tree order (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node // can return NULL first: function(node, callback) { var container = this.container(node); if (container) { var firstChild = container.firstChild; if (firstChild) { if (callback && !callback.call(this, firstChild)) { return this.nextAll(firstChild, callback); } return firstChild; } } return null; }, // get the last LI in tree order (with filtering) // `node` must be valid LI DOM node // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node // can return NULL last: function(node, callback) { var container = this.container(node); if (container) { var lastChild = container.lastChild; if (lastChild) { if (callback && (callback.call(this, lastChild) === null)) { return this.prevAll(lastChild, callback); } else { var drillDown; while (drillDown = this.lastChild(lastChild)) { lastChild = drillDown; } if (callback && !callback.call(this, lastChild)) { return this.prevAll(lastChild, callback); } return lastChild; } } } return null; }, // get the children LI from the node // `node` must be valid LI DOM node // `drillDown` if TRUE all children are returned // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node children: function(node, drillDown, callback) { var children = [], levels = [], match, next, skip; var firstChild = this.firstChild(node); if (firstChild) { while (true) { skip = false; do { if (callback) { match = callback.call(this, firstChild); if (match) { children.push(firstChild); } if (drillDown && (match !== null)) { next = this.firstChild(firstChild); if (next) { levels.push(firstChild); firstChild = next; skip = true; break; } } } else { children.push(firstChild); if (drillDown) { next = this.firstChild(firstChild); if (next) { levels.push(firstChild); firstChild = next; skip = true; break; } } } } while (firstChild = firstChild.nextSibling); if (!skip) { while (firstChild = levels.pop()) { firstChild = firstChild.nextSibling; if (firstChild) { break; } } if (!firstChild) { break; } } } } return children; }, // get a children from the node // `node` must be valid DOM node // `callback` can return FALSE to skip a node or NULL to stop the search // can return NULL childrenTill: function(node, callback) { var levels = [], match, next, skip; var firstChild = node.firstChild; if (firstChild) { while (true) { skip = false; do { match = callback.call(this, firstChild); if (match) { return firstChild; } else if (match === null) { return null; } next = firstChild.firstChild; if (next) { levels.push(firstChild); firstChild = next; skip = true; break; } } while (firstChild = firstChild.nextSibling); if (!skip) { while (firstChild = levels.pop()) { firstChild = firstChild.nextSibling; if (firstChild) { break; } } if (!firstChild) { break; } } } } return null; }, // get a children from the node having a class // `node` must be valid DOM node // `className` String or Array to check for // can return NULL childrenByClass: function(node, className) { if (node.getElementsByClassName) { var list = node.getElementsByClassName(className instanceof Array ? className.join(' ') : className); return list ? list[0] : null; } else { return this.childrenTill(node, function(node) { return this.hasClass(node, className); }); } }, // get the parent LI from the children LI // `node` must be valid LI DOM node // can return NULL parent: function(node) { var parent = node.parentNode.parentNode; if (parent && (parent.nodeName == 'LI')) { return parent; } return null; }, // get the parent LI from any children // `node` must be valid children of a LI DOM node // can return NULL parentFrom: function(node) { while (node.nodeName != 'LI') { node = node.parentNode; if (!node) { return null; } } return node; }, // get a parent from the node // `node` must be valid DOM node // `callback` can return FALSE to skip a node or NULL to stop the search // can return NULL parentTill: function(node, callback) { var match; while (node = node.parentNode) { match = callback.call(this, node); if (match) { return node; } else if (match === null) { return null; } } return null; }, // get a parent from the node having a class // `node` must be valid DOM node // `className` String or Array to check for // can return NULL parentByClass: function(node, className) { return this.parentTill(node, function(node) { return this.hasClass(node, className); }); }, // test if node has class(es) // `className` String or Array to check for // `withOut` String or Array to exclude with hasClass: function(node, className, withOut) { var oldClass = ' ' + node.className + ' '; if (withOut instanceof Array) { for (var i = 0; i < withOut.length; i++) { if (oldClass.indexOf(' ' + withOut[i] + ' ') != -1) { return false; } } } else { if (withOut && oldClass.indexOf(' ' + withOut + ' ') != -1) { return false; } } if (className instanceof Array) { for (var i = 0; i < className.length; i++) { if (oldClass.indexOf(' ' + className[i] + ' ') == -1) { return false; } } } else { if (className && oldClass.indexOf(' ' + className + ' ') == -1) { return false; } } return true; }, // filter nodes with class(es) // `nodes` Array of DOM nodes // @see `hasClass` withClass: function(nodes, className, withOut) { var filter = []; for (var i = 0; i < nodes.length; i++) { if (this.hasClass(nodes[i], className, withOut)) { filter.push(nodes[i]); } } return filter; }, // test if node has any class(es) // `className` String or Array to check for (any class) // `withOut` String or Array to exclude with hasAnyClass: function(node, className, withOut) { var oldClass = ' ' + node.className + ' '; if (withOut instanceof Array) { for (var i = 0; i < withOut.length; i++) { if (oldClass.indexOf(' ' + withOut[i] + ' ') != -1) { return false; } } } else { if (withOut && oldClass.indexOf(' ' + withOut + ' ') != -1) { return false; } } if (className instanceof Array) { for (var i = 0; i < className.length; i++) { if (oldClass.indexOf(' ' + className[i] + ' ') != -1) { return true; } } } else { if (className && oldClass.indexOf(' ' + className + ' ') != -1) { return true; } } return false; }, // filter nodes with any class(es) // `nodes` Array of DOM nodes // @see `hasAnyClass` withAnyClass: function(nodes, className, withOut) { var filter = []; for (var i = 0; i < nodes.length; i++) { if (this.hasAnyClass(nodes[i], className, withOut)) { filter.push(nodes[i]); } } return filter; }, // add class(es) to node // `node` must be valid DOM node // `className` String or Array to add // return TRUE if className changed addClass: function(node, className) { var oldClass = ' ' + node.className + ' ', append = ''; if (className instanceof Array) { for (var i = 0; i < className.length; i++) { if (oldClass.indexOf(' ' + className[i] + ' ') == -1) { append += ' ' + className[i]; } } } else { if (oldClass.indexOf(' ' + className + ' ') == -1) { append += ' ' + className; } } if (append) { node.className = node.className + append; return true; } return false; }, // add class(es) to nodes // `nodes` Array of DOM nodes // @see `addClass` addListClass: function(nodes, className, callback) { for (var i = 0; i < nodes.length; i++) { this.addClass(nodes[i], className); if (callback) { callback.call(this, nodes[i]); } } }, // remove class(es) from node // `node` must be valid DOM node // `className` String or Array to remove // return TRUE if className changed removeClass: function(node, className) { var oldClass = ' ' + node.className + ' '; if (className instanceof Array) { for (var i = 0; i < className.length; i++) { oldClass = oldClass.replace(' ' + className[i] + ' ', ' '); } } else { oldClass = oldClass.replace(' ' + className + ' ', ' '); } oldClass = oldClass.substr(1, oldClass.length - 2); if (node.className != oldClass) { node.className = oldClass; return true; } return false; }, // remove class(es) from nodes // `nodes` Array of DOM nodes // @see `removeClass` removeListClass: function(nodes, className, callback) { for (var i = 0; i < nodes.length; i++) { this.removeClass(nodes[i], className); if (callback) { callback.call(this, nodes[i]); } } }, // toggle node class(es) // `node` must be valid DOM node // `className` String or Array to toggle // `add` TRUE to add them // return TRUE if className changed toggleClass: function(node, className, add) { if (add) { return this.addClass(node, className); } else { return this.removeClass(node, className); } }, // toggle nodes class(es) // `nodes` Array of DOM nodes // @see `toggleClass` toggleListClass: function(nodes, className, add, callback) { for (var i = 0; i < nodes.length; i++) { this.toggleClass(nodes[i], className, add); if (callback) { callback.call(this, nodes[i]); } } }, // add/remove and keep old class(es) // `node` must be valid DOM node // `addClass` String or Array to add // `removeClass` String or Array to remove // return TRUE if className changed addRemoveClass: function(node, addClass, removeClass) { var oldClass = ' ' + node.className + ' '; if (removeClass) { if (removeClass instanceof Array) { for (var i = 0; i < removeClass.length; i++) { oldClass = oldClass.replace(' ' + removeClass[i] + ' ', ' '); } } else { oldClass = oldClass.replace(' ' + removeClass + ' ', ' '); } } if (addClass) { var append = ''; if (addClass instanceof Array) { for (var i = 0; i < addClass.length; i++) { if (oldClass.indexOf(' ' + addClass[i] + ' ') == -1) { append += addClass[i] + ' '; } } } else { if (oldClass.indexOf(' ' + addClass + ' ') == -1) { append += addClass + ' '; } } oldClass += append; } oldClass = oldClass.substr(1, oldClass.length - 2); if (node.className != oldClass) { node.className = oldClass; return true; } return false; }, // add/remove and keep old class(es) // `nodes` Array of DOM nodes // @see `addRemoveClass` addRemoveListClass: function(nodes, addClass, removeClass, callback) { for (var i = 0; i < nodes.length; i++) { this.addRemoveClass(nodes[i], addClass, removeClass); if (callback) { callback.call(this, nodes[i]); } } } };