jsbeans

jsbeans  1.0.0

jsbeans > jsbeans > Table.js (source view)
Search:
 
Filters
/*!
 * 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.
 */
/**
 * Table utilities
 * @namespace jsbeans
 * @class Table
 * @static
 */
jsbeans.Table = {
	/**
	 * @config _options
	 * @type JSON
	 * @private
	 * @static
	 * */
	_options: {
		select: {
			className: "selected"
		}
	},
	/**
	 * @method _internalSelect
	 * @param node {DOM}
	 * @param options {JSON}
	 * @param mode {String}
	 * @return {DOM}
	 * @private
	 * @static
	 * */
	_internalSelect: function(obj, options, mode) {
		if (obj == null || typeof(obj) == "undefined") {
			return null;
		}
		var isValidObject = obj.tagName.toLowerCase() == "tr" || obj.tagName.toLowerCase() == "td" || obj.tagName.toLowerCase() == "th";
		if (isValidObject) {
			var isSelected = function(o,cn) {
				var sp = (o.className ? o.className : "").split(" ");
				for (var i = 0, c; c = sp[i]; i++) {
					if (c == cn) {
						return true;
					}
				}
				return false || o.className.indexOf(cn) >= 0;
			};
			var add = function(o,cn) {
				var sp = (o.className ? o.className : "").split(" ");
				for (var i = 0, c; c = sp[i]; i++) {
					if (c == cn) {
						return;
					}
				}
				o.className = o.className + " " + cn;
			};
			var del = function(o,cn) {
				var sp = (o.className ? o.className : "").split(" ");
				var res = "";
				for (var i = 0, c; c = sp[i]; i++) {
					if (c != cn) {
						res += c + " ";
					}
				}
				o.className = res;
			};
			var sw = function(o,cn) {
				var sp = (o.className ? o.className : "").split(" ");
				var res = "";
				var found = false;
				for (var i = 0, c; c = sp[i]; i++) {
					if (c == cn) {
						found = true;
					} 
					else {
						res += c + " ";
					}
				}
				if (found || o.className.indexOf(cn) >= 0) {
					o.className = res;
				} 
				else {
					o.className = res + " " + cn;
				}
			};
			switch ("" + options.what) {
				case "tr":
					if (obj.tagName.toLowerCase() == "th" || obj.tagName.toLowerCase() == "td") {
						obj = obj.parentNode;
					}
					if (mode == "a") {
						add(obj, options.className);
					} 
					else if (mode == "r") {
						del(obj, options.className);
					} 
					else {
						sw(obj, options.className);
					}
					break;
				case "td":
					if (mode == "a") {
						add(obj, options.className);
					} 
					else if (mode == "r") {
						del(obj, options.className);
					} 
					else {
						sw(obj, options.className);
					}
					break;
				case "column":
					if (obj.tagName.toLowerCase() != "th" && obj.tagName.toLowerCase() != "td") {
						return null;
					}
					var o = obj;
					if (obj.tagName.toLowerCase() == "th") {
						var table = obj.parentNode.tagName.toLowerCase() == "table" ? obj.parentNode : obj.parentNode.parentNode;
						table = table.tagName.toLowerCase() == "table" ? table : table.parentNode;
						o = table.getElementsByTagName("td")[0];
					}
					var sel = isSelected(o, options.className);
					var trs = o.parentNode.parentNode.getElementsByTagName("tr");
					for (var i = 0, tr; tr = trs[i]; i++) {
						var td = tr.cells[obj.cellIndex];
						if (mode == "a") {
							add(td, options.className);
						} 
						else if (mode == "r") {
							del(td, options.className);
						} 
						else {
							if (sel) {
								del(td, options.className);
							} 
							else {
								add(td, options.className);
							}
						}
					}
					break;
				case "both":
					if (obj.tagName.toLowerCase() != "th" && obj.tagName.toLowerCase() != "td") {
						return null;
					}
					var o = obj;
					if (obj.tagName.toLowerCase() == "th") {
						var table = obj.parentNode.tagName.toLowerCase() == "table" ? obj.parentNode : obj.parentNode.parentNode;
						table = table.tagName.toLowerCase() == "table" ? table : table.parentNode;
						o = table.getElementsByTagName("td")[0];
					}
					var sel = isSelected(o, options.className);
					var trs = o.parentNode.parentNode.getElementsByTagName("tr");
					for (var i = 0, tr; tr = trs[i]; i++) {
						var td = tr.cells[obj.cellIndex];
						if (mode == "a") {
							add(td, options.className);
						} 
						else if (mode == "r") {
							del(td, options.className);
						} 
						else {
							if (sel) {
								del(td, options.className);
							} 
							else {
								add(td, options.className);
							}
						}
					}
					var row = o.parentNode;
					if (mode == "a") {
						add(row, options.className);
					} 
					else if (mode == "r") {
						del(row, options.className);
					} 
					else {
						if (sel) {
							del(row, options.className);
						} 
						else {
							add(row, options.className);
						}
					}
					break;
				default: 
					if (obj.tagName.toLowerCase() == "th" || obj.tagName.toLowerCase() == "td") {
						obj = obj.parentNode;
					}
					if (mode == "a") {
						add(obj, options.className);
					} 
					else if (mode == "r") {
						del(obj, options.className);
					} 
					else {
						sw(obj, options.className);
					}
			}
			return obj;
		}
		return null;
	},
	/**
	 * Selects table element {@param} <code class="param">node</code> (column, row, cell or column+row) based on value of {@param} <code class="param">options</code>.<br/>
	 * It switches selection on every invocation. Use {@method} <code class="methd">selectOn</code> or {@method} <code class="methd">selectOff</code> to force a selection mode.
	 * @method select
	 * @param node {DOM} a table DOM element
	 * @param [options] {JSON} a JSON 
	 * <pre>
	 * what: ['column' | 'tr' | 'td' | 'both'], // optional, default 'td'
	 * className: a_class_name // optional, define style class to use on selection, default 'selected'
	 * </pre>
	 * @return {DOM} selected DOM Object
	 * @static
	 * */
	select: function(obj /*, options*/) {
		var options = arguments[1] || jsbeans.Table._options.select;
		var className = options.className || this._options.select.className;
		var what = options.what || obj.tagName.toLowerCase();
		return this._internalSelect(obj,{className:className,what:what},"s");
	},
	/**
	 * Selects table element {@param} <code class="param">node</code> (column, row, cell or column+row) based on value of {@param} <code class="param">options</code>.
	 * @method selectOn
	 * @param node {DOM} a table DOM element
	 * @param [options] {JSON} a JSON 
	 * <pre>
	 * what: ['column' | 'tr' | 'td' | 'both'], // optional, default 'td'
	 * className: a_class_name // optional, define style class to use on selection, default 'selected'
	 * </pre>
	 * @return {DOM} selected DOM Object
	 * @static
	 * */
	selectOn: function(obj /*, options*/) {
		var options = arguments[1] || jsbeans.Table._options.select;
		var className = options.className || this._options.select.className;
		var what = options.what || obj.tagName.toLowerCase();
		return this._internalSelect(obj,{className:className,what:what},"a");
	},
	/**
	 * Turns off a previous selection by {@method} <code class="methd">select</code> or {@method} <code class="methd">selectOn</code>
	 * @method selectOff
	 * @param node {DOM} a table DOM element
	 * @param [options] {JSON} a JSON 
	 * <pre>
	 * what: ['column' | 'tr' | 'td' | 'both'], // optional, default 'td'
	 * className: a_class_name // optional, define style class to use on selection
	 * </pre>
	 * @return {DOM} selected DOM Object
	 * @static
	 * */
	selectOff: function(obj /*, options*/) {
		var options = arguments[1] || jsbeans.Table._options.select;
		var className = options.className || this._options.select.className;
		var what = options.what || obj.tagName.toLowerCase();
		return this._internalSelect(obj,{className:className,what:what},"r");
	},
	/**
	 * Hides rows of a Table based on {@param} <code class="param">search</code>
	 * @method filter
	 * @param search {String} the search term or phrase
	 * @param head {DOM | String} the TH DOM Element, or its id, containing the filter
	 * @param [min] {Integer} filter fired if <code>value.length &gt;= min</code>. Default <code>0</code>
	 * @static
	 * */
	filter: function(value, head) {
		var h = typeof(head) == "string" ? document.getElementById(head) : head;
		var cn = h.parentNode.childNodes;
		var pos = -1;
		for (var i = 0, c; c = cn[i]; i++) {
			if (c.nodeName && (c.nodeName.toLowerCase() == "td" || c.nodeName.toLowerCase() == "th")) {
				pos++;
				if (c.id == h.id) {
					break;
				}
			}
		}
		// h is a TD or TH, so TABLE isn't that far!
		var tb = h.parentNode.parentNode.nodeName.toLowerCase() == "table" ? h.parentNode.parentNode : h.parentNode.parentNode.parentNode;
		if (tb.getElementsByTagName("tbody")[0] == null) {
			tb.appendChild(document.createElement("tbody"));
		}
		var min = arguments[2] || 0;
		if (value.length >= min || value.length == 0) {
			var trs = tb.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
			for (var i = 0, tr; tr = trs[i]; i++) {
				var cn = tr.childNodes;
				var pos2 = -1;
				for (var j = 0, c; c = cn[j]; j++) {
					if (c.nodeName && (c.nodeName.toLowerCase() == "td" || c.nodeName.toLowerCase() == "th")) {
						pos2++;
						if (pos2 == pos) {
							if (c.firstChild.data.toLowerCase().indexOf(value) > -1) {
								try {
									c.parentNode.style.display = "table-row";
								} 
								catch (e) {
									c.parentNode.style.display = "";
								}
							} 
							else {
								c.parentNode.style.display = "none";
							}
						}
					}
				}
			}
		}
	},
	/**
	 * An easy way to set rows with alternate style and a mouseover effect.
	 * @method zebra
	 * @param table {String | DOM} could be the id of a Table or the DOM Table Object itself
	 * @param options {JSON} a JSON. Note that at least one of these options have to be used to make this method have sense
	 * <pre>
	 * odd: a_class_name, // a style class for odd rows
	 * even: a_class_name, // a style class for even rows
	 * over: a_class_name, // a style class to applied on mouseover event fired. You can even use 'hover'.
	 * </pre>
	 * @static
	 * */
	zebra: function(table, options) {
		if (table == null || typeof table == "undefined") {
			return;
		}
		var tableObj = null;
		if (typeof table == "string") {
			tableObj = document.getElementById(table);
		}
		else {
			tableObj = table;
		}
		if (tableObj != null && typeof tableObj != "undefined" && tableObj.nodeName && tableObj.nodeName.toUpperCase() == "TABLE") {
			var opts = options || {};
			var odd = opts.odd || "";
			var even = opts.even || "";
			// both 'over' and 'hover' are valid
			var over = opts.over || (opts.hover ? opts.hover : "");
			if (odd == "" && even == "" && over == "") {
				return;
			}
			var addHandler = function(element, name, handler) {
				if (element.addEventListener) {
					element.addEventListener(name, handler, false);
			    } 
				else if (element.attachEvent) {
					element["e" + name + handler] = handler;
					element[name + handler] = function() {
						element["e" + name + handler](window.event);
					};
			    	element.attachEvent('on' + name, element[name + handler]);
			    }
			};
			var getTarget = function(e) {
				try {
					e = e || event;
					var object = e.srcElement || e.target;
					if (object != null) {
						return object;
					}
				} 
				catch(e) {
					return null;
				}
			};

			var base = tableObj.getElementsByTagName("tbody").length > 0 ? tableObj.getElementsByTagName("tbody")[0] : tableObj;
			var trs = base.getElementsByTagName("tr");
			var cn;
			for (var i = 0, tr; tr = trs[i]; i++) {
				cn = tr.className;
				if (cn == null || typeof cn == "undefined") {
					cn = "";
				}
				if (i % 2 == 0) {
					tr.className = cn + " " + odd;
				}
				else {
					tr.className = cn + " " + even;
				}
				if (over != "") {
					addHandler(tr, "mouseover", function(e) {
						var el = getTarget(e);
						if (el != null) {
							if (el.nodeName.toUpperCase() == "TD") {
								el = el.parentNode;
							}
							cn = el.className;
							if (cn == null || typeof cn == "undefined") {
								cn = "";
							}
							el.className = cn + " " + over;
						}
						el = null;
					});
					addHandler(tr, "mouseout", function(e) {
						var el = getTarget(e);
						if (el != null) {
							if (el.nodeName.toUpperCase() == "TD") {
								el = el.parentNode;
							}
							cn = el.className;
							if (cn == null || typeof cn == "undefined") {
								// should never happen as this means that mouseover did nothing!
								return;
							}
							var sp = cn.split(" ");
							var s = "";
							for (var j = 0; j < sp.length; j++) {
								c = sp[j];
								if (c != over) {
									s += " " + c;
								}
							}
							el.className = s;
						}
						el = null;
					});
				}
				tr = null;
			}
		}
	}
};

Copyright © 2016 Francesco Mele. All rights reserved.