jsbeans

jsbeans  1.0.0

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

/**
 * IntSpinner is an UI (User Interface) element representing an input that 
 * allows only Integers and let the user go up and down by a defined step.
 * @namespace jsbeans
 * @class IntSpinner
 * @constructor
 * @param object {DOM | String}
 * @param [options] {JSON}
 * <pre>
 * arrowColor: &lt;String>, // the color of arrows
 * min: &lt;Integer>, // the minimum value allowed, default jsbeans.IntSpinner.MIN_VALUE
 * max: &lt;Integer>, // the maximum value allowed, default jsbeans.IntSpinner.MAX_VALUE
 * step: &lt;Integer>, // amount of increment/decrement, default 1
 * roll: &lt;boolean>, // if one of bound is reached, it starts again, default true
 * inputClassName: &lt;String>, // the input style class
 * arrowUpClassName: &lt;String>, // the up arrow style class
 * arrowDownClassName: &lt;String>, // the down arrow style class
 * readonly: &lt;boolean>, // if the input can be edit by user, default true (not editable)
 * label: &lt;String>, // a string inside a label tag. Optional
 * startsWith: &lt;Integer>, // the starting number, default 1
 * onBeforeClick: &lt;Function>, // function fired on both arrows just before value's update, it may be used to store previous value. It takes the input and the event fired as arguments.
 * onClick: &lt;Function>, // function fired onclick on both arrows. It takes the input and the event fired as arguments.
 * onMouseOver: &lt;Function>, // function fired on mouseover the input, may be used to store previous value. It takes the input and the event fired as arguments.
 * onMouseOut: &lt;Function> // function fired onmouseout the input, may be used for AJAX calls or for validation. It takes the input and the event fired as arguments.
 * </pre>
 * @author Francesco Mele
 * @credits Andrea Previati for 'onClick', 'onMouseOver' and 'onMouseOut' suggestion
 * */
jsbeans.IntSpinner = function(o) {
	this._obj = null;
	if (typeof o === "string") {
		this._obj = document.getElementById(o);
	}
	if (typeof this._obj == "undefined" || this._obj == null) {
		return;
	}
	this.options = arguments[1] || {};
	this.options.arrowColor = this.options.arrowColor || null;
	this.options.min = this.options.min || jsbeans.IntSpinner.MIN_VALUE;
	this.options.max = this.options.max || jsbeans.IntSpinner.MAX_VALUE;
	this.options.step = this.options.step || 1;
	this.options.roll = (typeof(this.options.roll) == "undefined") ? true : this.options.roll;
	this.options.inputClassName = this.options.inputClassName || null;
	this.options.arrowUpClassName = this.options.arrowUpClassName || null;
	this.options.arrowDownClassName = this.options.arrowDownClassName || null;
	this.options.readonly = (typeof(this.options.readonly) == "undefined") ? true : this.options.readonly;
	this.options.label = this.options.label || null;
	this.options.startsWith = this.options.startsWith || 1;
	this.options.onBeforeClick = this.options.onBeforeClick || null;
	this.options.onClick = this.options.onClick || null;
	this.options.onMouseOver = this.options.onMouseOver || null;
	this.options.onMouseOut = this.options.onMouseOut || null;
};

/**
 * Renders the UI element.
 * @method dispose
 * */
jsbeans.IntSpinner.prototype.dispose = function() {
	if (this._obj == null) {
		return;
	}
	var table = document.createElement("table");
	var tr = document.createElement("tr");
	var td = document.createElement("td");

	var input = document.createElement("input");
	input.setAttribute("type", "text");
	var inputId = this._obj.getAttribute("id") + "_input";
	input.setAttribute("id", inputId);
	input.setAttribute("name", inputId);
	input.value = this.options.startsWith;
	if (this.options.readonly === true) {
		input.setAttribute("readonly", "readonly");
	}
	if (this.options.inputClassName != null) {
		input.className = this.options.inputClassName;
	}
	if (this.options.label != null) {
		var label = document.createElement("label");
		label.setAttribute("for", inputId);
		label.innerHTML = this.options.label;
		td.appendChild(label);
	}

	td.appendChild(input);
	var td2 = document.createElement("td");
	tr.appendChild(td);
	tr.appendChild(td2);
	table.appendChild(tr);

	var table2 = document.createElement("table");
	var tr21 = document.createElement("tr");
	var tdUp = document.createElement("td");
	var divUp = document.createElement("div");
	if (this.options.arrowUpClassName != null) {
		tdUp.className = this.options.arrowUpClassName;
	}
	tdUp.appendChild(divUp);
	var styleUp = "border-color: transparent transparent " + ((this.options.arrowColor != null) ? this.options.arrowColor : "#333") + ";"
		+ "border-style: solid;"
		+ "border-width: 0 6px 6px;"
		+ "height: 0;"
		+ "margin: 0 3px;"
		+ "width: 0;"
		+ "cursor:hand;cursor:pointer";
	divUp.setAttribute("style", styleUp);
	var ops = this.options;
	tdUp.onclick = function(e) {
		if (ops.onBeforeClick != null) {
			try {
				e = e || event;
				ops.onBeforeClick(input, e);
			}
			catch(eup) {}
		}
		jsbeans.IntSpinner._roll(input, ops.step, ops);
		if (ops.onClick != null) {
			try {
				e = e || event;
				ops.onClick(input, e);
			}
			catch(eup) {}
		}
	};
	tr21.appendChild(tdUp);
	table2.appendChild(tr21);
	
	var tr22 = document.createElement("tr");
	var tdDown = document.createElement("td");
	var divDown = document.createElement("div");
	if (this.options.arrowDownClassName != null) {
		tdDown.className = this.options.arrowDownClassName;
	}
	tdDown.appendChild(divDown);
	var styleDown = "border-color: " + ((this.options.arrowColor != null) ? this.options.arrowColor : "#333") + " transparent transparent;"
		+ "border-style: solid;"
		+ "border-width: 6px 6px 0;"
		+ "height: 0;"
		+ "margin: 0 3px;"
		+ "width: 0;"
		+ "cursor:hand;cursor:pointer";
	divDown.setAttribute("style", styleDown);
	tdDown.onclick = function(e) {
		if (ops.onBeforeClick != null) {
			try {
				e = e || event;
				ops.onBeforeClick(input, e);
			}
			catch(edown) {}
		}
		jsbeans.IntSpinner._roll(input, -ops.step, ops);
		if (ops.onClick != null) {
			try {
				e = e || event;
				ops.onClick(input, e);
			}
			catch(edown) {}
		}
	};
	tr22.appendChild(tdDown);
	table2.appendChild(tr22);

	td2.appendChild(table2);
	
	input.onmouseover = function(e) {
		jsbeans.IntSpinner._addHandler(document, 'mousewheel', jsbeans.IntSpinner._wheel);
		jsbeans.IntSpinner._addHandler(document, 'DOMMouseScroll', jsbeans.IntSpinner._wheel);
		if (ops.onMouseOver != null) {
			try {
				e = e || event;
				ops.onMouseOver(input, e);
			}
			catch(emover) {}
		}
	};
	input.onmouseout = function(e) {
		jsbeans.IntSpinner._removeHandler(document, 'mousewheel', jsbeans.IntSpinner._wheel);
		jsbeans.IntSpinner._removeHandler(document, 'DOMMouseScroll', jsbeans.IntSpinner._wheel);
		if (ops.onMouseOut != null) {
			try {
				e = e || event;
				ops.onMouseOut(input, e);
			}
			catch(emover) {}
		}
	};

	input.options = ops;
	
	this._input = input;
	this._obj.appendChild(table);
	
};

/**
 * @config jsbeans.IntSpinner.MIN_VALUE
 * @type Integer
 * @static
 * @final
 * @default -999999999999999
 * */
jsbeans.IntSpinner.MIN_VALUE = -999999999999999;

/**
 * @config jsbeans.IntSpinner.MAX_VALUE
 * @type Integer
 * @static
 * @final
 * @default 999999999999999
 * */
jsbeans.IntSpinner.MAX_VALUE = 999999999999999;

/**
 * @method _roll
 * @param object {DOM}
 * @param step {Integer}
 * @param options {JSON}
 * @private
 * @static
 * */
jsbeans.IntSpinner._roll = function(o, step, options) {
	var ops = options || {};
	var v = parseInt(o.value);
	if (isNaN(v)) {
		return;
	}
	var min = ops.min || jsbeans.IntSpinner.MIN_VALUE;
	var max = ops.max || jsbeans.IntSpinner.MAX_VALUE;
	var roll = (typeof(ops.roll) == "undefined") ? true : ops.roll;
	var nv;
	if (step > 0) {
		if (v >=max) {
			if (roll) {
				nv = min;	
			} 
			else {
				nv = max;
			}
		} 
		else if ((v + step) > max) {
			nv = max;
		} 
		else if (v < min) {
			nv = step;
		} 
		else {
			nv = v + step;
		}
	} 
	else {
		if (v <= min) {
			if (roll) {
				nv = max;
			} 
			else {
				nv = min;
			}
		} 
		else if ((v + step) < min) {
			nv = min;
		} 
		else if (v > max) {
			nv = min;
		} 
		else {
			nv = v + step;
		}
	}
	o.value = nv;
};

/**
 * @method _wheel
 * @param event {event}
 * @private
 * @static
 * */
jsbeans.IntSpinner._wheel = function(event) {
	event = event ? event : window.event;

	var delta = null;
    if (event.wheelDelta){
        delta = event.wheelDelta;
    } else {
        delta = -event.detail * 40;
    }
	var target = event.target || event.srcElement;
	if (delta > 0) {
		jsbeans.IntSpinner._roll(target, target.options.step, target.options);
	} 
	else { 
		jsbeans.IntSpinner._roll(target, -target.options.step, target.options);
	}
	
    if (event.preventDefault){
        event.preventDefault();
    } 
    else {
        event.returnValue = false;
    }
};

/**
 * @method _addHandler
 * @param element {DOM}
 * @param type {String}
 * @param handler {Function}
 * @private
 * @static 
 * */
jsbeans.IntSpinner._addHandler = function(element, type, handler){
    if (element.addEventListener){
        element.addEventListener(type, handler, false);
    } 
    else if (element.attachEvent){
        element.attachEvent("on" + type, handler);
    } 
    else {
        element["on" + type] = handler;
    }
};

/**
 * @method _removeHandler
 * @param element {DOM}
 * @param type {String}
 * @param handler {Function}
 * @private
 * @static 
 * */
jsbeans.IntSpinner._removeHandler = function(element, type, handler){
    if (element.removeEventListener){
        element.removeEventListener(type, handler, false);
    } 
    else if (element.detachEvent){
        element.detachEvent("on" + type, handler);
    } 
    else {
        element["on" + type] = null;
    }
};

Copyright © 2016 Francesco Mele. All rights reserved.