jsbeans

jsbeans  1.0.0

jsbeans > jsbeans > EditInLine.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.
 */

/**
 * EditInLine turns non-editable elements, such as DIVs or SPANs, into input text, textarea or select on the 'onclick' event, so they can be editable.<br/>
 * On the 'onblur' event the element turns to be non-editable, but with the new value.
 * @namespace jsbeans
 * @class EditInLine
 * @static
 */
jsbeans.EditInLine = {
	/**
	 * Turns editable a DOM Object using its id. Operates over multiple Objects if {@param} <code class="param">ids</code> is an Array of Strings.
	 * @method byId
	 * @param ids {String | Array&lt;String>}
	 * @param [options] {Array | Function | JSON} may be an Array of values, a callback (fired on the 'onblur' event), or a JSON with all of them.<br/>
	 * <pre>
	 * onBeforeEnter: &lt;Function>, // optional
	 * onEnter: &lt;Function>, // optional
	 * onExit: &lt;Function>, // optional
	 * onBlur: &lt;Function>, // optional. Overrides default behaviour.
	 * values: &lt;Array> // optional list of values. It automatically turns element to a Select.
	 * mode: &lt;String> // by now only 'textarea' is admitted. It automatically turns element to a Textarea.
	 * cols: &lt;Integer> // number of columns of the textarea used as textarea's cols attribute. Used only if 'mode' option has 'textarea' value.
	 * rows: &lt;Array> // number of rows of the textarea used as textarea's rows attribute. Used only if 'mode' option has 'textarea' value.
	 * </pre>
	 * @static
	 * */
	byId: function(ids /*, options*/) {
		var opts = jsbeans.EditInLine._getOptions(arguments[1], arguments[2]);
		if (jsbeans.EditInLine._isArr(ids)) {
			for (var i = 0, id; id = ids[i]; i++) {
				var o = document.getElementById(id);
				if (typeof o == "undefined" || o == null) {
					continue;
				} 
				else {
					jsbeans.EditInLine._makeEditable(o, opts);
				}
			}
		} 
		else {
			var o = document.getElementById(ids);
			if (typeof o == "undefined" || o == null) {
				return;
			} 
			else {
				jsbeans.EditInLine._makeEditable(o, opts);
			}
		}
	},
	/**
	 * Turns editable DOM Objects selected by their style class.<br/>
	 * Everything else works just like <code class="methd">byId</code>.
	 * @method byClassname
	 * @param class_name {String} the style class for selection
	 * @param [options] {Array | Function | JSON}
	 * @static
	 * */
	byClassname: function(className /*, options*/) {
		var opts = jsbeans.EditInLine._getOptions(arguments[1], arguments[2]);
		var classNameRE = new RegExp('\\b' + className + '\\b');
		var els = document.getElementsByTagName('*');
		for (var i = 0, o; o = els[i]; i++) {
			if (classNameRE.test(o.className)) {
				jsbeans.EditInLine._makeEditable(o, opts);
			}
		}
	},
	/**
	 * As <code class="methd">byClassName</code>, but with a different case.
	 * @method byClassName
	 * @param class_name {String}
	 * @param options {Array | Function | JSON}
	 * @static
	 * */
	byClassName: function(cn /*, options*/) {
		jsbeans.EditInLine.byClassname(cn, arguments[1]);
	},
	/**
	 * @method _makeEditable
	 * @param object {DOM} the DOM Object that will be editable
	 * @param options {JSON} functions <code>onBeforeEnter</code>, <code>onEnter</code> and <code>onExit</code> and <code>values</code> for options.
	 * @private
	 * @static
	 * */
	_makeEditable: function(o, options) {
		o.onclick = function() {
			var input;
			var content = o.innerHTML == "&nbsp;" ? "" : o.innerHTML;
			var values = options.values;
			if (values != null) {
				input = document.createElement("select");
				var index = 0;
				for (var i = 0, val; val = values[i]; i++) {
					var opt = document.createElement("option");
					opt.text = val;
					opt.innerText = val;
					opt.value = val;
					input.appendChild(opt);
					if (content == val) {
						index = i;
					}
				}
				input.selectedIndex = index;
			} 
			else if (options.mode && options.mode == "textarea") {
				input = document.createElement("textarea");
				input.setAttribute("cols", options.cols ? options.cols : "50");
				input.setAttribute("rows", options.rows ? options.rows : "20");
				input.value = content;
			}
			else {
				input = document.createElement("input");
				input.setAttribute("type", "text");
				input.setAttribute("size", content.length + 1);
				input.value = content;
			}
			input.className = "jsbeans_EditInLine_input";
			if (o.id) {
				input.setAttribute("id", o.id + "_input");
			}
			input.onblur = function() {
				// override default behaviour
				if (options.onBlur != null) {
					options.onBlur(o);
				}
				else {
					o.innerHTML = input.value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') == "" ? "&nbsp;" : input.value;
					input.parentNode.replaceChild(o, input);
					input = null;
				}
				// always invoke onExit, if defined
				if (options.onExit != null) {
					options.onExit(o);
				}
			};
			if (options.onBeforeEnter != null) {
				options.onBeforeEnter(o);
			}
			o.parentNode.replaceChild(input, o);
			if (options.onEnter != null) {
				options.onEnter(input);
			}
			input.focus();
			if (input.getAttribute("type") == "text" || input.getAttribute("cols") != null) {
				input.select();
			}
		};
	},
	/**
	 * @method _getOptions
	 * @param arg1 {Array | Function | JSON}
	 * @param arg2 {Array | Function | JSON}
	 * @private
	 * @static
	 * */
	_getOptions: function(arg1, arg2) {
		var values = null;
		var onEnter = null;
		var onBeforeEnter = null;
		var onExit = null;
		var onBlur = null;
		var mode, cols, rows = null;
		if (typeof arg1 != "undefined") {
			if (jsbeans.EditInLine._isArr(arg1)) {
				values = arg1;
			} 
			else if (jsbeans.EditInLine._isFun(arg1)) {
				onExit = arg1;
			} 
			else if (arg1.values || arg1.onBeforeEnter || arg1.onEnter || arg1.onExit || arg1.onBlur) {
				if (arg1.values) {
					values = arg1.values;
				}
				if (arg1.onEnter && jsbeans.EditInLine._isFun(arg1.onEnter)) {
					onEnter = arg1.onEnter;
				}
				if (arg1.onBeforeEnter && jsbeans.EditInLine._isFun(arg1.onBeforeEnter)) {
					onBeforeEnter = arg1.onBeforeEnter;
				}
				if (arg1.onExit && jsbeans.EditInLine._isFun(arg1.onExit)) {
					onExit = arg1.onExit;
				}
				if (arg1.onBlur && jsbeans.EditInLine._isFun(arg1.onBlur)) {
					onBlur = arg1.onBlur;
				}
			}
			if (arg1.mode) {
				mode = arg1.mode;
			}
			if (arg1.cols) {
				cols = arg1.cols;
			}
			if (arg1.rows) {
				rows = arg1.rows;
			}
		}
		var opts = {
			values: values,
			onBeforeEnter: onBeforeEnter,
			onEnter: onEnter,
			onExit: onExit,
			onBlur: onBlur,
			mode: mode,
			cols: cols,
			rows: rows
		};
		if (arg2 && jsbeans.EditInLine._isFun(arg2)) {
			opts.onExit = arguments[2];
		} 
		else if (arg1 && jsbeans.EditInLine._isFun(arg1)) {
			opts.onExit = arg1;
		}
		return opts;
	},
	/**
	 * Cheks if fn is a Function
	 * @method _isFun
	 * @param func {Object}
	 * @return {boolean} true if <code class="param">func</code> is a <code>Function</code>
	 * @private
	 * @static
	 * */
	_isFun: function(fn) {
		return !!fn && typeof fn != "string" && !fn.nodeName && 
		fn.constructor != Array && /function/i.test( fn + "" );
	},
	/**
	 * Checks if a is an Array
	 * @method _isArr
	 * @param arr {Object}
	 * @return {boolean} true if <code class="param">arr</code> is an <code>Array</code>
	 * @private
	 * @static
	 * */
	_isArr: function(a) {
		return (typeof a == "object" && a.constructor == Array);
	}
};

Copyright © 2016 Francesco Mele. All rights reserved.