﻿/*
* jQuery UI Slider 1.8.7
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Slider
*
* Depends:
*	jquery.ui.core.js
*	jquery.ui.mouse.js
*	jquery.ui.widget.js
*/
(function ($, undefined) {

    // number of pages in a slider
    // (how many times can you page up/down to go through the whole range)
    var numPages = 5;

    $.widget("ui.slider", $.ui.mouse, {

        widgetEventPrefix: "slide",

        options: {
            animate: false,
            distance: 0,
            max: 100,
            min: 0,
            orientation: "horizontal",
            range: false,
            step: 1,
            value: 0,
            values: null
        },

        _create: function () {
            var self = this,
			o = this.options;

            this._keySliding = false;
            this._mouseSliding = false;
            this._animateOff = true;
            this._handleIndex = null;
            this._detectOrientation();
            this._mouseInit();

            this.element
			.addClass("ui-slider" +
				" ui-slider-" + this.orientation +
				" ui-widget" +
				" ui-widget-content" +
				" ui-corner-all");

            if (o.disabled) {
                this.element.addClass("ui-slider-disabled ui-disabled");
            }

            this.range = $([]);

            if (o.range) {
                if (o.range === true) {
                    this.range = $("<div></div>");
                    if (!o.values) {
                        o.values = [this._valueMin(), this._valueMin()];
                    }
                    if (o.values.length && o.values.length !== 2) {
                        o.values = [o.values[0], o.values[0]];
                    }
                } else {
                    this.range = $("<div></div>");
                }

                this.range
				.appendTo(this.element)
				.addClass("ui-slider-range");

                if (o.range === "min" || o.range === "max") {
                    this.range.addClass("ui-slider-range-" + o.range);
                }

                // note: this isn't the most fittingly semantic framework class for this element,
                // but worked best visually with a variety of themes
                this.range.addClass("ui-widget-header");
            }

            if ($(".ui-slider-handle", this.element).length === 0) {
                $("<a href='#'></a>")
				.appendTo(this.element)
				.addClass("ui-slider-handle");
            }

            if (o.values && o.values.length) {
                while ($(".ui-slider-handle", this.element).length < o.values.length) {
                    $("<a href='#'></a>")
					.appendTo(this.element)
					.addClass("ui-slider-handle");
                }
            }

            this.handles = $(".ui-slider-handle", this.element)
			.addClass("ui-state-default" +
				" ui-corner-all");

            this.handle = this.handles.eq(0);

            this.handles.add(this.range).filter("a")
			.click(function (event) {
			    event.preventDefault();
			})
			.hover(function () {
			    if (!o.disabled) {
			        $(this).addClass("ui-state-hover");
			    }
			}, function () {
			    $(this).removeClass("ui-state-hover");
			})
			.focus(function () {
			    if (!o.disabled) {
			        $(".ui-slider .ui-state-focus").removeClass("ui-state-focus");
			        $(this).addClass("ui-state-focus");
			    } else {
			        $(this).blur();
			    }
			})
			.blur(function () {
			    $(this).removeClass("ui-state-focus");
			});

            this.handles.each(function (i) {
                $(this).data("index.ui-slider-handle", i);
            });

            this.handles
			.keydown(function (event) {
			    var ret = true,
					index = $(this).data("index.ui-slider-handle"),
					allowed,
					curVal,
					newVal,
					step;

			    if (self.options.disabled) {
			        return;
			    }

			    switch (event.keyCode) {
			        case $.ui.keyCode.HOME:
			        case $.ui.keyCode.END:
			        case $.ui.keyCode.PAGE_UP:
			        case $.ui.keyCode.PAGE_DOWN:
			        case $.ui.keyCode.UP:
			        case $.ui.keyCode.RIGHT:
			        case $.ui.keyCode.DOWN:
			        case $.ui.keyCode.LEFT:
			            ret = false;
			            if (!self._keySliding) {
			                self._keySliding = true;
			                $(this).addClass("ui-state-active");
			                allowed = self._start(event, index);
			                if (allowed === false) {
			                    return;
			                }
			            }
			            break;
			    }

			    step = self.options.step;
			    if (self.options.values && self.options.values.length) {
			        curVal = newVal = self.values(index);
			    } else {
			        curVal = newVal = self.value();
			    }

			    switch (event.keyCode) {
			        case $.ui.keyCode.HOME:
			            newVal = self._valueMin();
			            break;
			        case $.ui.keyCode.END:
			            newVal = self._valueMax();
			            break;
			        case $.ui.keyCode.PAGE_UP:
			            newVal = self._trimAlignValue(curVal + ((self._valueMax() - self._valueMin()) / numPages));
			            break;
			        case $.ui.keyCode.PAGE_DOWN:
			            newVal = self._trimAlignValue(curVal - ((self._valueMax() - self._valueMin()) / numPages));
			            break;
			        case $.ui.keyCode.UP:
			        case $.ui.keyCode.RIGHT:
			            if (curVal === self._valueMax()) {
			                return;
			            }
			            newVal = self._trimAlignValue(curVal + step);
			            break;
			        case $.ui.keyCode.DOWN:
			        case $.ui.keyCode.LEFT:
			            if (curVal === self._valueMin()) {
			                return;
			            }
			            newVal = self._trimAlignValue(curVal - step);
			            break;
			    }

			    self._slide(event, index, newVal);

			    return ret;

			})
			.keyup(function (event) {
			    var index = $(this).data("index.ui-slider-handle");

			    if (self._keySliding) {
			        self._keySliding = false;
			        self._stop(event, index);
			        self._change(event, index);
			        $(this).removeClass("ui-state-active");
			    }

			});

            this._refreshValue();

            this._animateOff = false;
        },

        destroy: function () {
            this.handles.remove();
            this.range.remove();

            this.element
			.removeClass("ui-slider" +
				" ui-slider-horizontal" +
				" ui-slider-vertical" +
				" ui-slider-disabled" +
				" ui-widget" +
				" ui-widget-content" +
				" ui-corner-all")
			.removeData("slider")
			.unbind(".slider");

            this._mouseDestroy();

            return this;
        },

        _mouseCapture: function (event) {
            var o = this.options,
			position,
			normValue,
			distance,
			closestHandle,
			self,
			index,
			allowed,
			offset,
			mouseOverHandle;

            if (o.disabled) {
                return false;
            }

            this.elementSize = {
                width: this.element.outerWidth(),
                height: this.element.outerHeight()
            };
            this.elementOffset = this.element.offset();

            position = { x: event.pageX, y: event.pageY };
            normValue = this._normValueFromMouse(position);
            distance = this._valueMax() - this._valueMin() + 1;
            self = this;
            this.handles.each(function (i) {
                var thisDistance = Math.abs(normValue - self.values(i));
                if (distance > thisDistance) {
                    distance = thisDistance;
                    closestHandle = $(this);
                    index = i;
                }
            });

            // workaround for bug #3736 (if both handles of a range are at 0,
            // the first is always used as the one with least distance,
            // and moving it is obviously prevented by preventing negative ranges)
            if (o.range === true && this.values(1) === o.min) {
                index += 1;
                closestHandle = $(this.handles[index]);
            }

            allowed = this._start(event, index);
            if (allowed === false) {
                return false;
            }
            this._mouseSliding = true;

            self._handleIndex = index;

            closestHandle
			.addClass("ui-state-active")
			.focus();

            offset = closestHandle.offset();
            mouseOverHandle = !$(event.target).parents().andSelf().is(".ui-slider-handle");
            this._clickOffset = mouseOverHandle ? { left: 0, top: 0} : {
                left: event.pageX - offset.left - (closestHandle.width() / 2),
                top: event.pageY - offset.top -
				(closestHandle.height() / 2) -
				(parseInt(closestHandle.css("borderTopWidth"), 10) || 0) -
				(parseInt(closestHandle.css("borderBottomWidth"), 10) || 0) +
				(parseInt(closestHandle.css("marginTop"), 10) || 0)
            };

            if (!this.handles.hasClass("ui-state-hover")) {
                this._slide(event, index, normValue);
            }
            this._animateOff = true;
            return true;
        },

        _mouseStart: function (event) {
            return true;
        },

        _mouseDrag: function (event) {
            var position = { x: event.pageX, y: event.pageY },
			normValue = this._normValueFromMouse(position);

            this._slide(event, this._handleIndex, normValue);

            return false;
        },

        _mouseStop: function (event) {
            this.handles.removeClass("ui-state-active");
            this._mouseSliding = false;

            this._stop(event, this._handleIndex);
            this._change(event, this._handleIndex);

            this._handleIndex = null;
            this._clickOffset = null;
            this._animateOff = false;

            return false;
        },

        _detectOrientation: function () {
            this.orientation = (this.options.orientation === "vertical") ? "vertical" : "horizontal";
        },

        _normValueFromMouse: function (position) {
            var pixelTotal,
			pixelMouse,
			percentMouse,
			valueTotal,
			valueMouse;

            if (this.orientation === "horizontal") {
                pixelTotal = this.elementSize.width;
                pixelMouse = position.x - this.elementOffset.left - (this._clickOffset ? this._clickOffset.left : 0);
            } else {
                pixelTotal = this.elementSize.height;
                pixelMouse = position.y - this.elementOffset.top - (this._clickOffset ? this._clickOffset.top : 0);
            }

            percentMouse = (pixelMouse / pixelTotal);
            if (percentMouse > 1) {
                percentMouse = 1;
            }
            if (percentMouse < 0) {
                percentMouse = 0;
            }
            if (this.orientation === "vertical") {
                percentMouse = 1 - percentMouse;
            }

            valueTotal = this._valueMax() - this._valueMin();
            valueMouse = this._valueMin() + percentMouse * valueTotal;

            return this._trimAlignValue(valueMouse);
        },

        _start: function (event, index) {
            var uiHash = {
                handle: this.handles[index],
                value: this.value()
            };
            if (this.options.values && this.options.values.length) {
                uiHash.value = this.values(index);
                uiHash.values = this.values();
            }
            return this._trigger("start", event, uiHash);
        },

        _slide: function (event, index, newVal) {
            var otherVal,
			newValues,
			allowed;

            if (this.options.values && this.options.values.length) {
                otherVal = this.values(index ? 0 : 1);

                if ((this.options.values.length === 2 && this.options.range === true) &&
					((index === 0 && newVal > otherVal) || (index === 1 && newVal < otherVal))
				) {
                    newVal = otherVal;
                }

                if (newVal !== this.values(index)) {
                    newValues = this.values();
                    newValues[index] = newVal;
                    // A slide can be canceled by returning false from the slide callback
                    allowed = this._trigger("slide", event, {
                        handle: this.handles[index],
                        value: newVal,
                        values: newValues
                    });
                    otherVal = this.values(index ? 0 : 1);
                    if (allowed !== false) {
                        this.values(index, newVal, true);
                    }
                }
            } else {
                if (newVal !== this.value()) {
                    // A slide can be canceled by returning false from the slide callback
                    allowed = this._trigger("slide", event, {
                        handle: this.handles[index],
                        value: newVal
                    });
                    if (allowed !== false) {
                        this.value(newVal);
                    }
                }
            }
        },

        _stop: function (event, index) {
            var uiHash = {
                handle: this.handles[index],
                value: this.value()
            };
            if (this.options.values && this.options.values.length) {
                uiHash.value = this.values(index);
                uiHash.values = this.values();
            }

            this._trigger("stop", event, uiHash);
        },

        _change: function (event, index) {
            if (!this._keySliding && !this._mouseSliding) {
                var uiHash = {
                    handle: this.handles[index],
                    value: this.value()
                };
                if (this.options.values && this.options.values.length) {
                    uiHash.value = this.values(index);
                    uiHash.values = this.values();
                }

                this._trigger("change", event, uiHash);
            }
        },

        value: function (newValue) {
            if (arguments.length) {
                this.options.value = this._trimAlignValue(newValue);
                this._refreshValue();
                this._change(null, 0);
            }

            return this._value();
        },

        values: function (index, newValue) {
            var vals,
			newValues,
			i;

            if (arguments.length > 1) {
                this.options.values[index] = this._trimAlignValue(newValue);
                this._refreshValue();
                this._change(null, index);
            }

            if (arguments.length) {
                if ($.isArray(arguments[0])) {
                    vals = this.options.values;
                    newValues = arguments[0];
                    for (i = 0; i < vals.length; i += 1) {
                        vals[i] = this._trimAlignValue(newValues[i]);
                        this._change(null, i);
                    }
                    this._refreshValue();
                } else {
                    if (this.options.values && this.options.values.length) {
                        return this._values(index);
                    } else {
                        return this.value();
                    }
                }
            } else {
                return this._values();
            }
        },

        _setOption: function (key, value) {
            var i,
			valsLength = 0;

            if ($.isArray(this.options.values)) {
                valsLength = this.options.values.length;
            }

            $.Widget.prototype._setOption.apply(this, arguments);

            switch (key) {
                case "disabled":
                    if (value) {
                        this.handles.filter(".ui-state-focus").blur();
                        this.handles.removeClass("ui-state-hover");
                        this.handles.attr("disabled", "disabled");
                        this.element.addClass("ui-disabled");
                    } else {
                        this.handles.removeAttr("disabled");
                        this.element.removeClass("ui-disabled");
                    }
                    break;
                case "orientation":
                    this._detectOrientation();
                    this.element
					.removeClass("ui-slider-horizontal ui-slider-vertical")
					.addClass("ui-slider-" + this.orientation);
                    this._refreshValue();
                    break;
                case "value":
                    this._animateOff = true;
                    this._refreshValue();
                    this._change(null, 0);
                    this._animateOff = false;
                    break;
                case "values":
                    this._animateOff = true;
                    this._refreshValue();
                    for (i = 0; i < valsLength; i += 1) {
                        this._change(null, i);
                    }
                    this._animateOff = false;
                    break;
            }
        },

        //internal value getter
        // _value() returns value trimmed by min and max, aligned by step
        _value: function () {
            var val = this.options.value;
            val = this._trimAlignValue(val);

            return val;
        },

        //internal values getter
        // _values() returns array of values trimmed by min and max, aligned by step
        // _values( index ) returns single value trimmed by min and max, aligned by step
        _values: function (index) {
            var val,
			vals,
			i;

            if (arguments.length) {
                val = this.options.values[index];
                val = this._trimAlignValue(val);

                return val;
            } else {
                // .slice() creates a copy of the array
                // this copy gets trimmed by min and max and then returned
                vals = this.options.values.slice();
                for (i = 0; i < vals.length; i += 1) {
                    vals[i] = this._trimAlignValue(vals[i]);
                }

                return vals;
            }
        },

        // returns the step-aligned value that val is closest to, between (inclusive) min and max
        _trimAlignValue: function (val) {
            if (val <= this._valueMin()) {
                return this._valueMin();
            }
            if (val >= this._valueMax()) {
                return this._valueMax();
            }
            var step = (this.options.step > 0) ? this.options.step : 1,
			valModStep = (val - this._valueMin()) % step;
            alignValue = val - valModStep;

            if (Math.abs(valModStep) * 2 >= step) {
                alignValue += (valModStep > 0) ? step : (-step);
            }

            // Since JavaScript has problems with large floats, round
            // the final value to 5 digits after the decimal point (see #4124)
            return parseFloat(alignValue.toFixed(5));
        },

        _valueMin: function () {
            return this.options.min;
        },

        _valueMax: function () {
            return this.options.max;
        },

        _refreshValue: function () {
            var oRange = this.options.range,
			o = this.options,
			self = this,
			animate = (!this._animateOff) ? o.animate : false,
			valPercent,
			_set = {},
			lastValPercent,
			value,
			valueMin,
			valueMax;

            if (this.options.values && this.options.values.length) {
                this.handles.each(function (i, j) {
                    valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100;
                    _set[self.orientation === "horizontal" ? "left" : "bottom"] = valPercent + "%";
                    $(this).stop(1, 1)[animate ? "animate" : "css"](_set, o.animate);
                    if (self.options.range === true) {
                        if (self.orientation === "horizontal") {
                            if (i === 0) {
                                self.range.stop(1, 1)[animate ? "animate" : "css"]({ left: valPercent + "%" }, o.animate);
                            }
                            if (i === 1) {
                                self.range[animate ? "animate" : "css"]({ width: (valPercent - lastValPercent) + "%" }, { queue: false, duration: o.animate });
                            }
                        } else {
                            if (i === 0) {
                                self.range.stop(1, 1)[animate ? "animate" : "css"]({ bottom: (valPercent) + "%" }, o.animate);
                            }
                            if (i === 1) {
                                self.range[animate ? "animate" : "css"]({ height: (valPercent - lastValPercent) + "%" }, { queue: false, duration: o.animate });
                            }
                        }
                    }
                    lastValPercent = valPercent;
                });
            } else {
                value = this.value();
                valueMin = this._valueMin();
                valueMax = this._valueMax();
                valPercent = (valueMax !== valueMin) ?
					(value - valueMin) / (valueMax - valueMin) * 100 :
					0;
                _set[self.orientation === "horizontal" ? "left" : "bottom"] = valPercent + "%";
                this.handle.stop(1, 1)[animate ? "animate" : "css"](_set, o.animate);

                if (oRange === "min" && this.orientation === "horizontal") {
                    this.range.stop(1, 1)[animate ? "animate" : "css"]({ width: valPercent + "%" }, o.animate);
                }
                if (oRange === "max" && this.orientation === "horizontal") {
                    this.range[animate ? "animate" : "css"]({ width: (100 - valPercent) + "%" }, { queue: false, duration: o.animate });
                }
                if (oRange === "min" && this.orientation === "vertical") {
                    this.range.stop(1, 1)[animate ? "animate" : "css"]({ height: valPercent + "%" }, o.animate);
                }
                if (oRange === "max" && this.orientation === "vertical") {
                    this.range[animate ? "animate" : "css"]({ height: (100 - valPercent) + "%" }, { queue: false, duration: o.animate });
                }
            }
        }

    });

    $.extend($.ui.slider, {
        version: "1.8.7"
    });

} (jQuery));


