diff options
Diffstat (limited to 'library/jslider/js/jquery.slider.js')
-rw-r--r-- | library/jslider/js/jquery.slider.js | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/library/jslider/js/jquery.slider.js b/library/jslider/js/jquery.slider.js new file mode 100644 index 000000000..6d903775f --- /dev/null +++ b/library/jslider/js/jquery.slider.js @@ -0,0 +1,700 @@ +/** + * jquery.slider - Slider ui control in jQuery + * + * Written by + * Egor Khmelev (hmelyoff@gmail.com) + * + * Licensed under the MIT (MIT-LICENSE.txt). + * + * @author Egor Khmelev + * @version 1.1.0-RELEASE ($Id$) + * + * Dependencies + * + * jQuery (http://jquery.com) + * jquery.numberformatter (http://code.google.com/p/jquery-numberformatter/) + * tmpl (http://ejohn.org/blog/javascript-micro-templating/) + * jquery.dependClass + * draggable + * + **/ + +(function( $ ) { + + function isArray( value ){ + if( typeof value == "undefined" ) return false; + + if (value instanceof Array || (!(value instanceof Object) && + (Object.prototype.toString.call((value)) == '[object Array]') || + typeof value.length == 'number' && + typeof value.splice != 'undefined' && + typeof value.propertyIsEnumerable != 'undefined' && + !value.propertyIsEnumerable('splice') + )) { + return true; + } + + return false; + } + + $.slider = function( node, settings ){ + var jNode = $(node); + if( !jNode.data( "jslider" ) ) + jNode.data( "jslider", new jSlider( node, settings ) ); + + return jNode.data( "jslider" ); + }; + + $.fn.slider = function( action, opt_value ){ + var returnValue, args = arguments; + + function isDef( val ){ + return val !== undefined; + }; + + function isDefAndNotNull( val ){ + return val != null; + }; + + this.each(function(){ + var self = $.slider( this, action ); + + // do actions + if( typeof action == "string" ){ + switch( action ){ + case "value": + if( isDef( args[ 1 ] ) && isDef( args[ 2 ] ) ){ + var pointers = self.getPointers(); + if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){ + pointers[0].set( args[ 1 ] ); + pointers[0].setIndexOver(); + } + + if( isDefAndNotNull( pointers[1] ) && isDefAndNotNull( args[2] ) ){ + pointers[1].set( args[ 2 ] ); + pointers[1].setIndexOver(); + } + } + + else if( isDef( args[ 1 ] ) ){ + var pointers = self.getPointers(); + if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){ + pointers[0].set( args[ 1 ] ); + pointers[0].setIndexOver(); + } + } + + else + returnValue = self.getValue(); + + break; + + case "prc": + if( isDef( args[ 1 ] ) && isDef( args[ 2 ] ) ){ + var pointers = self.getPointers(); + if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){ + pointers[0]._set( args[ 1 ] ); + pointers[0].setIndexOver(); + } + + if( isDefAndNotNull( pointers[1] ) && isDefAndNotNull( args[2] ) ){ + pointers[1]._set( args[ 2 ] ); + pointers[1].setIndexOver(); + } + } + + else if( isDef( args[ 1 ] ) ){ + var pointers = self.getPointers(); + if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){ + pointers[0]._set( args[ 1 ] ); + pointers[0].setIndexOver(); + } + } + + else + returnValue = self.getPrcValue(); + + break; + + case "calculatedValue": + var value = self.getValue().split(";"); + returnValue = ""; + for (var i=0; i < value.length; i++) { + returnValue += (i > 0 ? ";" : "") + self.nice( value[i] ); + }; + + break; + + case "skin": + self.setSkin( args[1] ); + + break; + }; + + } + + // return actual object + else if( !action && !opt_value ){ + if( !isArray( returnValue ) ) + returnValue = []; + + returnValue.push( self ); + } + }); + + // flatten array just with one slider + if( isArray( returnValue ) && returnValue.length == 1 ) + returnValue = returnValue[ 0 ]; + + return returnValue || this; + }; + + var OPTIONS = { + + settings: { + from: 1, + to: 10, + step: 1, + smooth: true, + limits: true, + round: 0, + format: { format: "#,##0.##" }, + value: "5;7", + dimension: "" + }, + + className: "jslider", + selector: ".jslider-", + + template: tmpl( + '<span class="<%=className%>">' + + '<table><tr><td>' + + '<div class="<%=className%>-bg">' + + '<i class="l"></i><i class="r"></i>' + + '<i class="v"></i>' + + '</div>' + + + '<div class="<%=className%>-pointer"></div>' + + '<div class="<%=className%>-pointer <%=className%>-pointer-to"></div>' + + + '<div class="<%=className%>-label"><span><%=settings.from%></span></div>' + + '<div class="<%=className%>-label <%=className%>-label-to"><span><%=settings.to%></span><%=settings.dimension%></div>' + + + '<div class="<%=className%>-value"><span></span><%=settings.dimension%></div>' + + '<div class="<%=className%>-value <%=className%>-value-to"><span></span><%=settings.dimension%></div>' + + + '<div class="<%=className%>-scale"><%=scale%></div>'+ + + '</td></tr></table>' + + '</span>' + ) + + }; + + function jSlider(){ + return this.init.apply( this, arguments ); + }; + + jSlider.prototype.init = function( node, settings ){ + this.settings = $.extend(true, {}, OPTIONS.settings, settings ? settings : {}); + + // obj.sliderHandler = this; + this.inputNode = $( node ).hide(); + + this.settings.interval = this.settings.to-this.settings.from; + this.settings.value = this.inputNode.attr("value"); + + if( this.settings.calculate && $.isFunction( this.settings.calculate ) ) + this.nice = this.settings.calculate; + + if( this.settings.onstatechange && $.isFunction( this.settings.onstatechange ) ) + this.onstatechange = this.settings.onstatechange; + + this.is = { + init: false + }; + this.o = {}; + + this.create(); + }; + + jSlider.prototype.onstatechange = function(){ + + }; + + jSlider.prototype.create = function(){ + var $this = this; + + this.domNode = $( OPTIONS.template({ + className: OPTIONS.className, + settings: { + from: this.nice( this.settings.from ), + to: this.nice( this.settings.to ), + dimension: this.settings.dimension + }, + scale: this.generateScale() + }) ); + + this.inputNode.after( this.domNode ); + this.drawScale(); + + // set skin class + if( this.settings.skin && this.settings.skin.length > 0 ) + this.setSkin( this.settings.skin ); + + this.sizes = { + domWidth: this.domNode.width(), + domOffset: this.domNode.offset() + }; + + // find some objects + $.extend(this.o, { + pointers: {}, + labels: { + 0: { + o: this.domNode.find(OPTIONS.selector + "value").not(OPTIONS.selector + "value-to") + }, + 1: { + o: this.domNode.find(OPTIONS.selector + "value").filter(OPTIONS.selector + "value-to") + } + }, + limits: { + 0: this.domNode.find(OPTIONS.selector + "label").not(OPTIONS.selector + "label-to"), + 1: this.domNode.find(OPTIONS.selector + "label").filter(OPTIONS.selector + "label-to") + } + }); + + $.extend(this.o.labels[0], { + value: this.o.labels[0].o.find("span") + }); + + $.extend(this.o.labels[1], { + value: this.o.labels[1].o.find("span") + }); + + + if( !$this.settings.value.split(";")[1] ){ + this.settings.single = true; + this.domNode.addDependClass("single"); + } + + if( !$this.settings.limits ) + this.domNode.addDependClass("limitless"); + + this.domNode.find(OPTIONS.selector + "pointer").each(function( i ){ + var value = $this.settings.value.split(";")[i]; + if( value ){ + $this.o.pointers[i] = new jSliderPointer( this, i, $this ); + + var prev = $this.settings.value.split(";")[i-1]; + if( prev && new Number(value) < new Number(prev) ) value = prev; + + value = value < $this.settings.from ? $this.settings.from : value; + value = value > $this.settings.to ? $this.settings.to : value; + + $this.o.pointers[i].set( value, true ); + } + }); + + this.o.value = this.domNode.find(".v"); + this.is.init = true; + + $.each(this.o.pointers, function(i){ + $this.redraw(this); + }); + + (function(self){ + $(window).resize(function(){ + self.onresize(); + }); + })(this); + + }; + + jSlider.prototype.setSkin = function( skin ){ + if( this.skin_ ) + this.domNode.removeDependClass( this.skin_, "_" ); + + this.domNode.addDependClass( this.skin_ = skin, "_" ); + }; + + jSlider.prototype.setPointersIndex = function( i ){ + $.each(this.getPointers(), function(i){ + this.index( i ); + }); + }; + + jSlider.prototype.getPointers = function(){ + return this.o.pointers; + }; + + jSlider.prototype.generateScale = function(){ + if( this.settings.scale && this.settings.scale.length > 0 ){ + var str = ""; + var s = this.settings.scale; + var prc = Math.round((100/(s.length-1))*10)/10; + for( var i=0; i < s.length; i++ ){ + str += '<span style="left: ' + i*prc + '%">' + ( s[i] != '|' ? '<ins>' + s[i] + '</ins>' : '' ) + '</span>'; + }; + return str; + } else return ""; + + return ""; + }; + + jSlider.prototype.drawScale = function(){ + this.domNode.find(OPTIONS.selector + "scale span ins").each(function(){ + $(this).css({ marginLeft: -$(this).outerWidth()/2 }); + }); + }; + + jSlider.prototype.onresize = function(){ + var self = this; + this.sizes = { + domWidth: this.domNode.width(), + domOffset: this.domNode.offset() + }; + + $.each(this.o.pointers, function(i){ + self.redraw(this); + }); + }; + + jSlider.prototype.update = function(){ + this.onresize(); + this.drawScale(); + }; + + jSlider.prototype.limits = function( x, pointer ){ + // smooth + if( !this.settings.smooth ){ + var step = this.settings.step*100 / ( this.settings.interval ); + x = Math.round( x/step ) * step; + } + + var another = this.o.pointers[1-pointer.uid]; + if( another && pointer.uid && x < another.value.prc ) x = another.value.prc; + if( another && !pointer.uid && x > another.value.prc ) x = another.value.prc; + + // base limit + if( x < 0 ) x = 0; + if( x > 100 ) x = 100; + + return Math.round( x*10 ) / 10; + }; + + jSlider.prototype.redraw = function( pointer ){ + if( !this.is.init ) return false; + + this.setValue(); + + // redraw range line + if( this.o.pointers[0] && this.o.pointers[1] ) + this.o.value.css({ left: this.o.pointers[0].value.prc + "%", width: ( this.o.pointers[1].value.prc - this.o.pointers[0].value.prc ) + "%" }); + + this.o.labels[pointer.uid].value.html( + this.nice( + pointer.value.origin + ) + ); + + // redraw position of labels + this.redrawLabels( pointer ); + + }; + + jSlider.prototype.redrawLabels = function( pointer ){ + + function setPosition( label, sizes, prc ){ + sizes.margin = -sizes.label/2; + + // left limit + label_left = sizes.border + sizes.margin; + if( label_left < 0 ) + sizes.margin -= label_left; + + // right limit + if( sizes.border+sizes.label / 2 > self.sizes.domWidth ){ + sizes.margin = 0; + sizes.right = true; + } else + sizes.right = false; + + label.o.css({ left: prc + "%", marginLeft: sizes.margin, right: "auto" }); + if( sizes.right ) label.o.css({ left: "auto", right: 0 }); + return sizes; + } + + var self = this; + var label = this.o.labels[pointer.uid]; + var prc = pointer.value.prc; + + var sizes = { + label: label.o.outerWidth(), + right: false, + border: ( prc * this.sizes.domWidth ) / 100 + }; + + if( !this.settings.single ){ + // glue if near; + var another = this.o.pointers[1-pointer.uid]; + var another_label = this.o.labels[another.uid]; + + switch( pointer.uid ){ + case 0: + if( sizes.border+sizes.label / 2 > another_label.o.offset().left-this.sizes.domOffset.left ){ + another_label.o.css({ visibility: "hidden" }); + another_label.value.html( this.nice( another.value.origin ) ); + + label.o.css({ visibility: "visible" }); + + prc = ( another.value.prc - prc ) / 2 + prc; + if( another.value.prc != pointer.value.prc ){ + label.value.html( this.nice(pointer.value.origin) + " – " + this.nice(another.value.origin) ); + sizes.label = label.o.outerWidth(); + sizes.border = ( prc * this.sizes.domWidth ) / 100; + } + } else { + another_label.o.css({ visibility: "visible" }); + } + break; + + case 1: + if( sizes.border - sizes.label / 2 < another_label.o.offset().left - this.sizes.domOffset.left + another_label.o.outerWidth() ){ + another_label.o.css({ visibility: "hidden" }); + another_label.value.html( this.nice(another.value.origin) ); + + label.o.css({ visibility: "visible" }); + + prc = ( prc - another.value.prc ) / 2 + another.value.prc; + if( another.value.prc != pointer.value.prc ){ + label.value.html( this.nice(another.value.origin) + " – " + this.nice(pointer.value.origin) ); + sizes.label = label.o.outerWidth(); + sizes.border = ( prc * this.sizes.domWidth ) / 100; + } + } else { + another_label.o.css({ visibility: "visible" }); + } + break; + } + } + + sizes = setPosition( label, sizes, prc ); + + /* draw second label */ + if( another_label ){ + var sizes = { + label: another_label.o.outerWidth(), + right: false, + border: ( another.value.prc * this.sizes.domWidth ) / 100 + }; + sizes = setPosition( another_label, sizes, another.value.prc ); + } + + this.redrawLimits(); + }; + + jSlider.prototype.redrawLimits = function(){ + if( this.settings.limits ){ + + var limits = [ true, true ]; + + for( key in this.o.pointers ){ + + if( !this.settings.single || key == 0 ){ + + var pointer = this.o.pointers[key]; + var label = this.o.labels[pointer.uid]; + var label_left = label.o.offset().left - this.sizes.domOffset.left; + + var limit = this.o.limits[0]; + if( label_left < limit.outerWidth() ) + limits[0] = false; + + var limit = this.o.limits[1]; + if( label_left + label.o.outerWidth() > this.sizes.domWidth - limit.outerWidth() ) + limits[1] = false; + } + + }; + + for( var i=0; i < limits.length; i++ ){ + if( limits[i] ) + this.o.limits[i].fadeIn("fast"); + else + this.o.limits[i].fadeOut("fast"); + }; + + } + }; + + jSlider.prototype.setValue = function(){ + var value = this.getValue(); + this.inputNode.attr( "value", value ); + this.onstatechange.call( this, value ); + }; + + jSlider.prototype.getValue = function(){ + if(!this.is.init) return false; + var $this = this; + + var value = ""; + $.each( this.o.pointers, function(i){ + if( this.value.prc != undefined && !isNaN(this.value.prc) ) value += (i > 0 ? ";" : "") + $this.prcToValue( this.value.prc ); + }); + return value; + }; + + jSlider.prototype.getPrcValue = function(){ + if(!this.is.init) return false; + var $this = this; + + var value = ""; + $.each( this.o.pointers, function(i){ + if( this.value.prc != undefined && !isNaN(this.value.prc) ) value += (i > 0 ? ";" : "") + this.value.prc; + }); + return value; + }; + + jSlider.prototype.prcToValue = function( prc ){ + + if( this.settings.heterogeneity && this.settings.heterogeneity.length > 0 ){ + var h = this.settings.heterogeneity; + + var _start = 0; + var _from = this.settings.from; + + for( var i=0; i <= h.length; i++ ){ + if( h[i] ) var v = h[i].split("/"); + else var v = [100, this.settings.to]; + + v[0] = new Number(v[0]); + v[1] = new Number(v[1]); + + if( prc >= _start && prc <= v[0] ) { + var value = _from + ( (prc-_start) * (v[1]-_from) ) / (v[0]-_start); + } + + _start = v[0]; + _from = v[1]; + }; + + } else { + var value = this.settings.from + ( prc * this.settings.interval ) / 100; + } + + return this.round( value ); + }; + + jSlider.prototype.valueToPrc = function( value, pointer ){ + if( this.settings.heterogeneity && this.settings.heterogeneity.length > 0 ){ + var h = this.settings.heterogeneity; + + var _start = 0; + var _from = this.settings.from; + + for (var i=0; i <= h.length; i++) { + if(h[i]) var v = h[i].split("/"); + else var v = [100, this.settings.to]; + v[0] = new Number(v[0]); v[1] = new Number(v[1]); + + if(value >= _from && value <= v[1]){ + var prc = pointer.limits(_start + (value-_from)*(v[0]-_start)/(v[1]-_from)); + } + + _start = v[0]; _from = v[1]; + }; + + } else { + var prc = pointer.limits((value-this.settings.from)*100/this.settings.interval); + } + + return prc; + }; + + jSlider.prototype.round = function( value ){ + value = Math.round( value / this.settings.step ) * this.settings.step; + if( this.settings.round ) value = Math.round( value * Math.pow(10, this.settings.round) ) / Math.pow(10, this.settings.round); + else value = Math.round( value ); + return value; + }; + + jSlider.prototype.nice = function( value ){ + value = value.toString().replace(/,/gi, ".").replace(/ /gi, "");; + + if( $.formatNumber ){ + return $.formatNumber( new Number(value), this.settings.format || {} ).replace( /-/gi, "−" ); + } + + else { + return new Number(value); + } + }; + + + function jSliderPointer(){ + Draggable.apply( this, arguments ); + } + jSliderPointer.prototype = new Draggable(); + + jSliderPointer.prototype.oninit = function( ptr, id, _constructor ){ + this.uid = id; + this.parent = _constructor; + this.value = {}; + this.settings = this.parent.settings; + }; + + jSliderPointer.prototype.onmousedown = function(evt){ + this._parent = { + offset: this.parent.domNode.offset(), + width: this.parent.domNode.width() + }; + this.ptr.addDependClass("hover"); + this.setIndexOver(); + }; + + jSliderPointer.prototype.onmousemove = function( evt, x ){ + var coords = this._getPageCoords( evt ); + this._set( this.calc( coords.x ) ); + }; + + jSliderPointer.prototype.onmouseup = function( evt ){ + if( this.parent.settings.callback && $.isFunction(this.parent.settings.callback) ) + this.parent.settings.callback.call( this.parent, this.parent.getValue() ); + + this.ptr.removeDependClass("hover"); + }; + + jSliderPointer.prototype.setIndexOver = function(){ + this.parent.setPointersIndex( 1 ); + this.index( 2 ); + }; + + jSliderPointer.prototype.index = function( i ){ + this.ptr.css({ zIndex: i }); + }; + + jSliderPointer.prototype.limits = function( x ){ + return this.parent.limits( x, this ); + }; + + jSliderPointer.prototype.calc = function(coords){ + var x = this.limits(((coords-this._parent.offset.left)*100)/this._parent.width); + return x; + }; + + jSliderPointer.prototype.set = function( value, opt_origin ){ + this.value.origin = this.parent.round(value); + this._set( this.parent.valueToPrc( value, this ), opt_origin ); + }; + + jSliderPointer.prototype._set = function( prc, opt_origin ){ + if( !opt_origin ) + this.value.origin = this.parent.prcToValue(prc); + + this.value.prc = prc; + this.ptr.css({ left: prc + "%" }); + this.parent.redraw(this); + }; + +})(jQuery);
\ No newline at end of file |