/*!
* Copyright (c) 2009 Francesco Mele jsbeans@francescomele.com
*
* This Software is licenced under the LGPL Licence (GNU Lesser General
* Public License).
* In addition to the LGPL Licence the Software is subject to the
* following conditions:
*
* i every modification must be public and comunicated to the Author
* ii every "jsbean" added to this library must be self consistent
* except for the dependence from jsbeans-x.x.x.js
* iii copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* A set of utilities to manage DOM Objects
* @namespace jsbeans
* @class dom
* @static
*/
/**
* @config Defining base object <code class="class">jsbeans.dom</code>.
* @private
*/
jsbeans.define("jsbeans.dom");
/**
* Appends {@param} <code class="param">object_to_append</code> at the same level of {@param} <code class="param">base_object</code>, just after it.<br/>
* Note that no check will be performed on given arguments. Passing DOM Object is up to developer.
* @method insertAfter
* @param base_object {DOM} if <code>null</code> or <code>undefined</code> <code>document.firstChild</code> will be used.
* @param object_to_append {DOM}
* @static
*/
jsbeans.dom.insertAfter = function(obj, newObj) {
if (obj == null || typeof(obj) == "undefined") {
obj = document.firstChild;
}
obj.parentNode.insertBefore(newObj, obj.nextSibling);
};
/**
* Removes {@param} <code class="param">object_to_remove</code>. Useful to direct removing DOM Objects.<br/>
* Note that no check will be performed on given arguments. Passing DOM Object is up to developer.
* @method removeSelf
* @param object_to_remove {DOM}
* @static
*/
jsbeans.dom.removeSelf = function(obj) {
if (obj == null || typeof(obj) == "undefined") {
obj = document.firstChild;
}
obj.parentNode.removeChild(obj);
};
/**
* Switches {@param} <code class="param">object_to_move</code> with next sibling. Effect seems to move down given Object<br/>
* Note that no check will be performed on given arguments. Passing DOM Object is up to developer.<br/>
* <span class="fixme">FIXME</span>: it seems that cloning nodes makes some conflict with event handlers attached via javascript (i.e. jquery.mouseout(...))
* @method moveDown
* @param object_to_move {DOM} if <code>null</code> or <code>undefined</code> the method will exit silently.
* @static
*/
jsbeans.dom.moveDown = function(obj) {
if (obj == null || typeof(obj) == "undefined") {
return;
}
var next, cur = obj;
var num = 0;
for (; cur; cur = cur["nextSibling"]) {
if (cur.nodeType == 1 && ++num == 2) {
next = cur;
break;
}
}
if (typeof(next) != "undefined") {
var clone = obj.cloneNode(true);
jsbeans.dom.insertAfter(next, clone);
jsbeans.dom.removeSelf(obj);
}
};
/**
* Switches {@param} <code class="param">object_to_move</code> with previous sibling. Effect seems to move up given Object<br/>
* Note that no check will be performed on given arguments. Passing DOM Object is up to developer.<br/>
* <span class="fixme">FIXME</span>: it seems that cloning nodes makes some conflict with event handlers attached via javascript (i.e. jquery.mouseout(...))
* @method moveUp
* @param object_to_move {DOM} if <code>null</code> or <code>undefined</code> the method will exit silently.
* @static
*/
jsbeans.dom.moveUp = function(/*DOM*/obj) {
if (obj == null || typeof(obj) == "undefined") {
return;
}
var prev, cur = obj;
var num = 0;
for (; cur; cur = cur["previousSibling"]) {
if (cur.nodeType == 1 && ++num == 2) {
prev = cur;
break;
}
}
if (typeof(prev) != "undefined") {
var clone = obj.cloneNode(true);
obj.parentNode.insertBefore(clone, prev);
jsbeans.dom.removeSelf(obj);
}
};
/**
* Starting from {@param} <code class="param">node</code> this method will call {@param} <code class="param">func</code> on every next sibling recursively.<br/>
* Note that no check will be performed on given arguments. Passing DOM Object is up to developer.
* @method visit
* @param node {DOM}
* @param func {Function}
* @static
*/
jsbeans.dom.visit = function(node, func) {
func(node);
node = node.firstChild;
while(node) {
jsbeans.dom.visit(node, func);
node = node.nextSibling;
}
};
/**
* Returns an Array of DOM objects that match <strong>exactly</strong> the same value for the given attribute name.<br/>
* For "class" attribute it chekcs for a class among the defined ones. Example: <input type="text" class="className1 className2" /> is found even using jsbeans.dom.getElementsByAttribute("class", "className1").<br/>
* Note: this kind of functionality is now widely supported by almost all javascript libraries. It probably won't be deleted, but checking its presence after an update is encouraged.
* @method getElementsByAttribute
* @param attribute {String} the attribute name of a DOM Object
* @param value {String} the attribute value to match
* @return {Array<DOM>}
* @static
*/
jsbeans.dom.getElementsByAttribute = function(attr, value) {
var res = new Array();
jsbeans.dom.visit(document.body, function(node) {
if (attr == "class") {
if (node.className && node.className.match(new RegExp("(^|\\s)" + value + "(\\s|$)"))) {
res.push(node);
}
}
else {
var current = node.nodeType === 1 && node.getAttribute(attr);
if (typeof(current) === "string" && (current === value || typeof(value) !== "string")) {
res.push(node);
}
}
});
return res;
};
/**
* A shortcut to create DOM Elements.<br/>
* Note 1: for "class" attribute use <code>className</code>.<br/>
* Note 2: for "style" use nested rules (e.g. <code>{style: {border: "1px solid red", color: "#de45ff"}}</code>)
* @method create
* @param tagName {String} the name of a DOM Object (e.g 'div')
* @param [options] {JSON} set of attributes
* @return {DOM}
* @static
*/
jsbeans.dom.create = function(tagName, attrs) {
var res = document.createElement(tagName);
var attrs = attrs || {};
for (p in attrs) {
if (("" + p).toLowerCase() != "style") {
res[p] = attrs[p];
}
else {
for (style in attrs["style"]) {
res.style[style] = attrs["style"][style];
}
}
}
return res;
};