jui.defineUI("ui.slider", [ "jquery", "util.base", "util.math" ], function($, _, math) {
/**
* @class ui.slider
* @extends core
* @alias Slider
* @requires jquery
* @requires util.base
*/
var UI = function() {
var self, isVertical, preFromValue, preToValue;
var $root, $track, $handle, $toHandle, $tooltipTrack, $progress;
var $tooltip, $tooltipMessage, $tooltip2, $tooltipMessage2;
function min() {
return self.options.min;
}
function max() {
return self.options.max;
}
function step() {
return self.options.step;
}
function type() {
return self.options.type;
}
function isDouble() {
return type() == 'double';
}
function isSingle() {
return type() == 'single';
}
function isShowProgress() {
return $root.data('progress') == false ? false : self.options.progress;
}
function isShowTooltip() {
return $root.data('tooltip') == false ? false : self.options.tooltip;
}
function getTooltip(type) {
return (type == 'from') ? $tooltip : $tooltip2;
}
function getTooltipMessage(type) {
return (type == 'from') ? $tooltipMessage : $tooltipMessage2;
}
function getHandle(type) {
if (type == 'to') {
return $toHandle;
}
return $handle;
}
function pos(e) {
if (_.isTouch) {
return e.originalEvent.touches[0];
}
return e;
}
function getStyleValue($node, key) {
return $node[0].style[key];
}
function setProgressBar() {
if (isSingle()) {
if (isVertical) {
$progress.height(getStyleValue($handle, 'bottom')).css({ bottom : 0 });
} else {
$progress.width(getStyleValue($handle, 'left'));
}
} else {
if (isVertical) {
var toDist = parseFloat(getStyleValue($toHandle, 'bottom').replace('%', ''));
var fromDist = parseFloat(getStyleValue($handle, 'bottom').replace('%', ''));
$progress.height((toDist - fromDist) + '%').css({
bottom : fromDist + '%'
});
} else {
var toDist = parseFloat(getStyleValue($toHandle, 'left').replace('%', ''));
var fromDist = parseFloat(getStyleValue($handle, 'left').replace('%', ''));
$progress.width((toDist - fromDist) + '%').css({
left : fromDist + '%'
});
}
}
}
function checkMaxFromTo(dist, type) {
if (isDouble()) {
if (type == 'from') {
if (isVertical) {
var toDist = parseFloat(getStyleValue($toHandle, 'bottom').replace('%', ''));
if (dist >= toDist) {
dist = toDist;
}
} else {
var toDist = parseFloat(getStyleValue($toHandle, 'left').replace('%', ''));
if (dist >= toDist) {
dist = toDist;
}
}
} else if (type == 'to') {
if (isVertical) {
var fromDist = parseFloat(getStyleValue($handle, 'bottom').replace('%', ''));
if (dist <= fromDist) {
dist = fromDist;
}
} else {
var fromDist = parseFloat(getStyleValue($handle, 'left').replace('%', ''));
if (dist <= fromDist) {
dist = fromDist;
}
}
}
}
return dist;
}
function setViewStatus(dist, type) {
var value = getValue(dist/100);
if (value < min()) value = min();
if (value > max()) value = max();
dist = (value - min()) / (max() - min()) * 100;
dist = checkMaxFromTo(dist, type);
// redefine value
value = getValue(dist/100);
var percent = dist + '%';
var $handle = getHandle(type)
if (isVertical) {
$handle.css({ bottom : percent });
} else {
$handle.css({ left : percent });
}
setProgressBar();
if (isShowTooltip()) {
var $tooltip = getTooltip(type);
var $tooltipMessage = getTooltipMessage(type);
if (_.typeCheck("function", self.options.format)) {
value = self.options.format.call(self, value);
}
$tooltipMessage.html(value);
if (isVertical) {
$tooltip.css({
bottom : $track.height() * (dist / 100),
'margin-bottom' : -1 * ($tooltip.height()/2)
});
} else {
$tooltip.css({
left : percent,
"margin-left" : -1 * ($tooltip.width()/2)
});
var xPos = $track.width() * ( dist/100);
var lastPos = xPos + $tooltip.width()/2;
var firstPos = xPos - $tooltip.width()/2;
if (lastPos >= $track.width() ) {
$tooltip.css({
left : $track.width() - $tooltip.width() + $handle.width()/2,
'margin-left' : 0
}).addClass('last');
} else if (firstPos <= 0 ) {
$tooltip.css({
'left' : -$handle.width()/2,
'margin-left' : 0
}).addClass('first');
} else {
$tooltip.removeClass('first last');
}
}
$tooltip.show();
}
if (type == 'from') {
if (preFromValue != value) {
self.emit("change", [ { type: type, from: value, to: self.getToValue() } ]);
preFromValue = value;
}
} else if (type == 'to') {
if (preToValue != value) {
self.emit("change", [ { type: type, from: self.getFromValue(), to: value } ]);
preToValue = value;
}
}
}
function setHandlePosition(e, type) {
var min, max, current;
var dist = undefined;
if (self.options.orient == 'vertical') {
min = $track.offset().top - $("body").scrollTop();
max = min + $track.height();
current = pos(e).clientY;
if (current <= min) {
dist = 100;
} else if (current >= max) {
dist = 0;
} else {
dist = (max - current) / (max - min) * 100;
}
} else {
min = $track.offset().left;
max = min + $track.width();
current = pos(e).clientX;
if (current < min) {
dist = 0;
} else if (current > max) {
dist = 100;
} else {
dist = (current - min) / (max - min) * 100;
}
}
setViewStatus(dist, type);
}
function getValue(dist) {
if (typeof dist == 'undefined') {
if (isVertical) {
dist = parseFloat($handle.css('bottom'))/$track.height();
} else {
dist = parseFloat($handle.css('left'))/$track.width();
}
}
var minValue = min();
var maxValue = max();
var value = (minValue + (maxValue - minValue) * dist);
var stepValue = step();
var temp = math.remain(value, stepValue);
value = math.minus(value, temp);
if (temp > math.div(stepValue, 2)) {
value = math.plus(value, stepValue);
}
return value;
}
function initElement() {
$root.addClass(self.options.orient);
$track = $("<div class='track' />");
$tooltipTrack = $("<div class='tooltip-track' />");
$progress = $("<div class='progress' />");
if (!isShowProgress()) {
$progress.hide();
}
$handle = $("<div class='handle from' />");
$track.html($progress);
$track.append($handle);
if (isDouble()) {
$toHandle = $("<div class='handle to' />");
$track.append($toHandle);
}
var tooltip_orient = isVertical ? 'right': 'top';
$tooltip = $('<div class="tooltip '+tooltip_orient+'"><div class="message" /></div>').hide();
$tooltipMessage = $tooltip.find(".message");
$tooltip2 = $('<div class="tooltip '+tooltip_orient+'"><div class="message" /></div>').hide();
$tooltipMessage2 = $tooltip2.find(".message");
$tooltipTrack.html($tooltip);
$tooltipTrack.append($tooltip2);
$root.html($track);
$root.append($tooltipTrack);
if (isShowTooltip()) {
$root.addClass('has-tooltip');
}
}
function initEvent() {
self.addEvent($handle, 'mousedown', function(e) {
$handle.data('select', true);
$("body").addClass("slider-cursor");
});
if (isDouble()) {
self.addEvent($toHandle, 'mousedown', function(e) {
$toHandle.data('select', true);
$("body").addClass("slider-cursor");
});
}
self.addEvent($track, 'mousedown', function(e) {
$("body").addClass("slider-cursor");
if (self.options.type == 'single') {
$handle.data('select', true);
setHandlePosition(e, 'from');
} else {
//TODO: if type is double, check position
}
});
self.addEvent('body', 'mouseup', function(e) {
$handle.data('select', false);
if (self.options.type == 'double') {
$toHandle.data('select', false);
}
$("body").removeClass("slider-cursor");
});
self.addEvent('body', 'mousemove', function(e) {
if ($handle.data('select')) {
setHandlePosition(e, 'from');
} else if (self.options.type == 'double' && $toHandle.data('select')) {
setHandlePosition(e, 'to');
}
});
}
this.init = function() {
self = this;
$root = $(this.root);
isVertical = (this.options.orient == 'vertical');
initElement();
initEvent();
this.setFromValue();
this.setToValue();
}
/**
* @method setFromValue
* set FromHandle's value
*
* @param {Number}
*/
this.setFromValue = function(value) {
var from = value || $root.data("from") || this.options.from,
dist = (from - min()) / (max() - min()) * 100;
setViewStatus(dist, "from");
}
/**
* @method setToValue
* set ToHandle's value
*
* @param {Number}
*/
this.setToValue = function(value) {
if (isDouble()) {
var to = value || $root.data("to") || this.options.to,
dist = (to - min()) / (max() - min()) * 100;
setViewStatus(dist, "to");
}
}
/**
* @method getFromValue
* get FromHandle's value
*
* @return {Number} value
*/
this.getFromValue = function() {
return getValue();
}
/**
* @method getToValue
* get ToHandle's value
*
* @return {Number} value
*/
this.getToValue = function () {
var dist;
if(isDouble()) {
if (isVertical) {
dist = parseFloat($toHandle.css("bottom")) / $track.height();
} else {
dist = parseFloat($toHandle.css("left")) / $track.width();
}
return getValue(dist);
}
return getValue();
}
}
UI.setup = function() {
return {
type : "single", // or double
orient : "horizontal", // or vertical,
min : 0,
max : 10,
step : 1,
from : 0,
to : 10,
tooltip : true,
format : null,
progress : true
}
}
/**
* @event change
* Event that occurs when dragging on a slider
*
* @param {Object} data Data of current from
* @param {jQueryEvent} e The event object
*/
return UI;
});