jellyfin-web/dashboard-ui/thirdparty/jquerymobile-1.4.5/jqm.slider.js
2015-09-07 11:54:57 -04:00

959 lines
35 KiB
JavaScript

(function ($, undefined) {
$.widget("mobile.slider", $.extend({
initSelector: "input[type='range']:not([data-role='none'])",
widgetEventPrefix: "slide",
options: {
theme: null,
trackTheme: null,
corners: true,
mini: false,
highlight: false
},
_create: function () {
// TODO: Each of these should have comments explain what they're for
var self = this,
control = this.element,
trackTheme = this.options.trackTheme || $.mobile.getAttribute(control[0], "theme"),
trackThemeClass = trackTheme ? " ui-bar-" + trackTheme : " ui-bar-inherit",
cornerClass = (this.options.corners || control.jqmData("corners")) ? " ui-corner-all" : "",
miniClass = (this.options.mini || control.jqmData("mini")) ? " ui-mini" : "",
cType = control[0].nodeName.toLowerCase(),
isToggleSwitch = (cType === "select"),
isRangeslider = control.parent().is(":jqmData(role='rangeslider')"),
selectClass = (isToggleSwitch) ? "ui-slider-switch" : "",
controlID = control.attr("id"),
$label = $("[for='" + controlID + "']"),
labelID = $label.attr("id") || controlID + "-label",
min = !isToggleSwitch ? parseFloat(control.attr("min")) : 0,
max = !isToggleSwitch ? parseFloat(control.attr("max")) : control.find("option").length - 1,
step = window.parseFloat(control.attr("step") || 1),
domHandle = document.createElement("a"),
handle = $(domHandle),
domSlider = document.createElement("div"),
slider = $(domSlider),
valuebg = this.options.highlight && !isToggleSwitch ? (function () {
var bg = document.createElement("div");
bg.className = "ui-slider-bg " + $.mobile.activeBtnClass;
return $(bg).prependTo(slider);
})() : false,
options,
wrapper,
j, length,
i, optionsCount, origTabIndex,
side, activeClass, sliderImg;
$label.attr("id", labelID);
this.isToggleSwitch = isToggleSwitch;
domHandle.setAttribute("href", "#");
domSlider.setAttribute("role", "application");
domSlider.className = [this.isToggleSwitch ? "ui-slider ui-slider-track ui-shadow-inset " : "ui-slider-track ui-shadow-inset ", selectClass, trackThemeClass, cornerClass, miniClass].join("");
domHandle.className = "ui-slider-handle";
domSlider.appendChild(domHandle);
handle.attr({
"role": "slider",
"aria-valuemin": min,
"aria-valuemax": max,
"aria-valuenow": this._value(),
"aria-valuetext": this._value(),
"title": this._value(),
"aria-labelledby": labelID
});
$.extend(this, {
slider: slider,
handle: handle,
control: control,
type: cType,
step: step,
max: max,
min: min,
valuebg: valuebg,
isRangeslider: isRangeslider,
dragging: false,
beforeStart: null,
userModified: false,
mouseMoved: false
});
if (isToggleSwitch) {
// TODO: restore original tabindex (if any) in a destroy method
origTabIndex = control.attr("tabindex");
if (origTabIndex) {
handle.attr("tabindex", origTabIndex);
}
control.attr("tabindex", "-1").focus(function () {
$(this).blur();
handle.focus();
});
wrapper = document.createElement("div");
wrapper.className = "ui-slider-inneroffset";
for (j = 0, length = domSlider.childNodes.length; j < length; j++) {
wrapper.appendChild(domSlider.childNodes[j]);
}
domSlider.appendChild(wrapper);
// slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
// make the handle move with a smooth transition
handle.addClass("ui-slider-handle-snapping");
options = control.find("option");
for (i = 0, optionsCount = options.length; i < optionsCount; i++) {
side = !i ? "b" : "a";
activeClass = !i ? "" : " " + $.mobile.activeBtnClass;
sliderImg = document.createElement("span");
sliderImg.className = ["ui-slider-label ui-slider-label-", side, activeClass].join("");
sliderImg.setAttribute("role", "img");
sliderImg.appendChild(document.createTextNode(options[i].innerHTML));
$(sliderImg).prependTo(slider);
}
self._labels = $(".ui-slider-label", slider);
}
// monitor the input for updated values
control.addClass(isToggleSwitch ? "ui-slider-switch" : "ui-slider-input");
this._on(control, {
"change": "_controlChange",
"keyup": "_controlKeyup",
"blur": "_controlBlur",
"mouseup": "_controlVMouseUp"
});
slider.bind("mousedown", $.proxy(this._sliderVMouseDown, this))
.bind("click", false);
// We have to instantiate a new function object for the unbind to work properly
// since the method itself is defined in the prototype (causing it to unbind everything)
this._on(document, { "mousemove": "_preventDocumentDrag" });
this._on(slider.add(document), { "mouseup": "_sliderVMouseUp" });
slider.insertAfter(control);
// wrap in a div for styling purposes
if (!isToggleSwitch && !isRangeslider) {
wrapper = this.options.mini ? "<div class='ui-slider ui-mini'>" : "<div class='ui-slider'>";
control.add(slider).wrapAll(wrapper);
}
// bind the handle event callbacks and set the context to the widget instance
this._on(this.handle, {
"mousedown": "_handleVMouseDown",
"keydown": "_handleKeydown",
"keyup": "_handleKeyup"
});
this.handle.bind("click", false);
this._handleFormReset();
this.refresh(undefined, undefined, true);
},
_setOptions: function (options) {
if (options.theme !== undefined) {
this._setTheme(options.theme);
}
if (options.trackTheme !== undefined) {
this._setTrackTheme(options.trackTheme);
}
if (options.corners !== undefined) {
this._setCorners(options.corners);
}
if (options.mini !== undefined) {
this._setMini(options.mini);
}
if (options.highlight !== undefined) {
this._setHighlight(options.highlight);
}
if (options.disabled !== undefined) {
this._setDisabled(options.disabled);
}
this._super(options);
},
_controlChange: function (event) {
// if the user dragged the handle, the "change" event was triggered from inside refresh(); don't call refresh() again
if (this._trigger("controlchange", event) === false) {
return false;
}
if (!this.mouseMoved) {
this.refresh(this._value(), true);
}
},
_controlKeyup: function (/* event */) { // necessary?
this.refresh(this._value(), true, true);
},
_controlBlur: function (/* event */) {
this.refresh(this._value(), true);
},
// it appears the clicking the up and down buttons in chrome on
// range/number inputs doesn't trigger a change until the field is
// blurred. Here we check thif the value has changed and refresh
_controlVMouseUp: function (/* event */) {
this._checkedRefresh();
},
// NOTE force focus on handle
_handleVMouseDown: function (/* event */) {
this.handle.focus();
},
_handleKeydown: function (event) {
var index = this._value();
if (this.options.disabled) {
return;
}
// In all cases prevent the default and mark the handle as active
switch (event.keyCode) {
case $.mobile.keyCode.HOME:
case $.mobile.keyCode.END:
case $.mobile.keyCode.PAGE_UP:
case $.mobile.keyCode.PAGE_DOWN:
case $.mobile.keyCode.UP:
case $.mobile.keyCode.RIGHT:
case $.mobile.keyCode.DOWN:
case $.mobile.keyCode.LEFT:
event.preventDefault();
if (!this._keySliding) {
this._keySliding = true;
this.handle.addClass("ui-state-active"); /* TODO: We don't use this class for styling. Do we need to add it? */
}
break;
}
// move the slider according to the keypress
switch (event.keyCode) {
case $.mobile.keyCode.HOME:
this.refresh(this.min);
break;
case $.mobile.keyCode.END:
this.refresh(this.max);
break;
case $.mobile.keyCode.PAGE_UP:
case $.mobile.keyCode.UP:
case $.mobile.keyCode.RIGHT:
this.refresh(index + this.step);
break;
case $.mobile.keyCode.PAGE_DOWN:
case $.mobile.keyCode.DOWN:
case $.mobile.keyCode.LEFT:
this.refresh(index - this.step);
break;
}
}, // remove active mark
_handleKeyup: function (/* event */) {
if (this._keySliding) {
this._keySliding = false;
this.handle.removeClass("ui-state-active"); /* See comment above. */
}
},
_sliderVMouseDown: function (event) {
// NOTE: we don't do this in refresh because we still want to
// support programmatic alteration of disabled inputs
if (this.options.disabled || !(event.which === 1 || event.which === 0 || event.which === undefined)) {
return false;
}
if (this._trigger("beforestart", event) === false) {
return false;
}
this.dragging = true;
this.userModified = false;
this.mouseMoved = false;
if (this.isToggleSwitch) {
this.beforeStart = this.element[0].selectedIndex;
}
this.refresh(event);
this._trigger("start");
return false;
},
_sliderVMouseUp: function () {
if (this.dragging) {
this.dragging = false;
if (this.isToggleSwitch) {
// make the handle move with a smooth transition
this.handle.addClass("ui-slider-handle-snapping");
if (this.mouseMoved) {
// this is a drag, change the value only if user dragged enough
if (this.userModified) {
this.refresh(this.beforeStart === 0 ? 1 : 0);
} else {
this.refresh(this.beforeStart);
}
} else {
// this is just a click, change the value
this.refresh(this.beforeStart === 0 ? 1 : 0);
}
}
this.mouseMoved = false;
this._trigger("stop");
return false;
}
},
_preventDocumentDrag: function (event) {
// NOTE: we don't do this in refresh because we still want to
// support programmatic alteration of disabled inputs
if (this._trigger("drag", event) === false) {
return false;
}
if (this.dragging && !this.options.disabled) {
// this.mouseMoved must be updated before refresh() because it will be used in the control "change" event
this.mouseMoved = true;
if (this.isToggleSwitch) {
// make the handle move in sync with the mouse
this.handle.removeClass("ui-slider-handle-snapping");
}
this.refresh(event);
// only after refresh() you can calculate this.userModified
this.userModified = this.beforeStart !== this.element[0].selectedIndex;
return false;
}
},
_checkedRefresh: function () {
if (this.value !== this._value()) {
this.refresh(this._value());
}
},
_value: function () {
return this.isToggleSwitch ? this.element[0].selectedIndex : parseFloat(this.element.val());
},
_reset: function () {
this.refresh(undefined, false, true);
},
refresh: function (val, isfromControl, preventInputUpdate) {
// NOTE: we don't return here because we want to support programmatic
// alteration of the input value, which should still update the slider
var self = this,
parentTheme = $.mobile.getAttribute(this.element[0], "theme"),
theme = this.options.theme || parentTheme,
themeClass = theme ? " ui-btn-" + theme : "",
trackTheme = this.options.trackTheme || parentTheme,
trackThemeClass = trackTheme ? " ui-bar-" + trackTheme : " ui-bar-inherit",
cornerClass = this.options.corners ? " ui-corner-all" : "",
miniClass = this.options.mini ? " ui-mini" : "",
left, width, data, tol,
pxStep, percent,
control, isInput, optionElements, min, max, step,
newval, valModStep, alignValue, percentPerStep,
handlePercent, aPercent, bPercent,
valueChanged;
self.slider[0].className = [this.isToggleSwitch ? "ui-slider ui-slider-switch ui-slider-track ui-shadow-inset" : "ui-slider-track ui-shadow-inset", trackThemeClass, cornerClass, miniClass].join("");
if (this.options.disabled || this.element.prop("disabled")) {
this.disable();
}
// set the stored value for comparison later
this.value = this._value();
if (this.options.highlight && !this.isToggleSwitch && this.slider.find(".ui-slider-bg").length === 0) {
this.valuebg = (function () {
var bg = document.createElement("div");
bg.className = "ui-slider-bg " + $.mobile.activeBtnClass;
return $(bg).prependTo(self.slider);
})();
}
this.handle.addClass("ui-btn" + themeClass + " ui-shadow");
control = this.element;
isInput = !this.isToggleSwitch;
optionElements = isInput ? [] : control.find("option");
min = isInput ? parseFloat(control.attr("min")) : 0;
max = isInput ? parseFloat(control.attr("max")) : optionElements.length - 1;
step = (isInput && parseFloat(control.attr("step")) > 0) ? parseFloat(control.attr("step")) : 1;
if (typeof val === "object") {
data = val;
// a slight tolerance helped get to the ends of the slider
tol = 8;
left = this.slider.offset().left;
width = this.slider.width();
pxStep = width / ((max - min) / step);
if (!this.dragging ||
data.pageX < left - tol ||
data.pageX > left + width + tol) {
return;
}
if (pxStep > 1) {
percent = ((data.pageX - left) / width) * 100;
} else {
percent = Math.round(((data.pageX - left) / width) * 100);
}
} else {
if (val == null) {
val = isInput ? parseFloat(control.val() || 0) : control[0].selectedIndex;
}
percent = (parseFloat(val) - min) / (max - min) * 100;
}
if (isNaN(percent)) {
return;
}
newval = (percent / 100) * (max - min) + min;
//from jQuery UI slider, the following source will round to the nearest step
valModStep = (newval - min) % step;
alignValue = newval - valModStep;
if (Math.abs(valModStep) * 2 >= step) {
alignValue += (valModStep > 0) ? step : (-step);
}
percentPerStep = 100 / ((max - min) / step);
// Since JavaScript has problems with large floats, round
// the final value to 5 digits after the decimal point (see jQueryUI: #4124)
newval = parseFloat(alignValue.toFixed(5));
if (typeof pxStep === "undefined") {
pxStep = width / ((max - min) / step);
}
if (pxStep > 1 && isInput) {
percent = (newval - min) * percentPerStep * (1 / step);
}
if (percent < 0) {
percent = 0;
}
if (percent > 100) {
percent = 100;
}
if (newval < min) {
newval = min;
}
if (newval > max) {
newval = max;
}
this.handle.css("left", percent + "%");
this.handle[0].setAttribute("aria-valuenow", isInput ? newval : optionElements.eq(newval).attr("value"));
this.handle[0].setAttribute("aria-valuetext", isInput ? newval : optionElements.eq(newval).getEncodedText());
this.handle[0].setAttribute("title", isInput ? newval : optionElements.eq(newval).getEncodedText());
if (this.valuebg) {
this.valuebg.css("width", percent + "%");
}
// drag the label widths
if (this._labels) {
handlePercent = this.handle.width() / this.slider.width() * 100;
aPercent = percent && handlePercent + (100 - handlePercent) * percent / 100;
bPercent = percent === 100 ? 0 : Math.min(handlePercent + 100 - aPercent, 100);
this._labels.each(function () {
var ab = $(this).hasClass("ui-slider-label-a");
$(this).width((ab ? aPercent : bPercent) + "%");
});
}
if (!preventInputUpdate) {
valueChanged = false;
// update control"s value
if (isInput) {
valueChanged = parseFloat(control.val()) !== newval;
control.val(newval);
} else {
valueChanged = control[0].selectedIndex !== newval;
control[0].selectedIndex = newval;
}
if (this._trigger("beforechange", val) === false) {
return false;
}
if (!isfromControl && valueChanged) {
control.trigger("change");
}
}
},
_setHighlight: function (value) {
value = !!value;
if (value) {
this.options.highlight = !!value;
this.refresh();
} else if (this.valuebg) {
this.valuebg.remove();
this.valuebg = false;
}
},
_setTheme: function (value) {
this.handle
.removeClass("ui-btn-" + this.options.theme)
.addClass("ui-btn-" + value);
var currentTheme = this.options.theme ? this.options.theme : "inherit",
newTheme = value ? value : "inherit";
this.control
.removeClass("ui-body-" + currentTheme)
.addClass("ui-body-" + newTheme);
},
_setTrackTheme: function (value) {
var currentTrackTheme = this.options.trackTheme ? this.options.trackTheme : "inherit",
newTrackTheme = value ? value : "inherit";
this.slider
.removeClass("ui-body-" + currentTrackTheme)
.addClass("ui-body-" + newTrackTheme);
},
_setMini: function (value) {
value = !!value;
if (!this.isToggleSwitch && !this.isRangeslider) {
this.slider.parent().toggleClass("ui-mini", value);
this.element.toggleClass("ui-mini", value);
}
this.slider.toggleClass("ui-mini", value);
},
_setCorners: function (value) {
this.slider.toggleClass("ui-corner-all", value);
if (!this.isToggleSwitch) {
this.control.toggleClass("ui-corner-all", value);
}
},
_setDisabled: function (value) {
value = !!value;
this.element.prop("disabled", value);
this.slider
.toggleClass("ui-state-disabled", value)
.attr("aria-disabled", value);
this.element.toggleClass("ui-state-disabled", value);
}
}, $.mobile.behaviors.formReset));
})(jQuery);
(function ($, undefined) {
$.widget("mobile.rangeslider", $.extend({
options: {
theme: null,
trackTheme: null,
corners: true,
mini: false,
highlight: true
},
_create: function () {
var $el = this.element,
elClass = this.options.mini ? "ui-rangeslider ui-mini" : "ui-rangeslider",
_inputFirst = $el.find("input").first(),
_inputLast = $el.find("input").last(),
_label = $el.find("label").first(),
_sliderWidgetFirst = $.data(_inputFirst.get(0), "mobile-slider") ||
$.data(_inputFirst.slider().get(0), "mobile-slider"),
_sliderWidgetLast = $.data(_inputLast.get(0), "mobile-slider") ||
$.data(_inputLast.slider().get(0), "mobile-slider"),
_sliderFirst = _sliderWidgetFirst.slider,
_sliderLast = _sliderWidgetLast.slider,
firstHandle = _sliderWidgetFirst.handle,
_sliders = $("<div class='ui-rangeslider-sliders' />").appendTo($el);
_inputFirst.addClass("ui-rangeslider-first");
_inputLast.addClass("ui-rangeslider-last");
$el.addClass(elClass);
_sliderFirst.appendTo(_sliders);
_sliderLast.appendTo(_sliders);
_label.insertBefore($el);
firstHandle.prependTo(_sliderLast);
$.extend(this, {
_inputFirst: _inputFirst,
_inputLast: _inputLast,
_sliderFirst: _sliderFirst,
_sliderLast: _sliderLast,
_label: _label,
_targetVal: null,
_sliderTarget: false,
_sliders: _sliders,
_proxy: false
});
this.refresh();
this._on(this.element.find("input.ui-slider-input"), {
"slidebeforestart": "_slidebeforestart",
"slidestop": "_slidestop",
"slidedrag": "_slidedrag",
"slidebeforechange": "_change",
"blur": "_change",
"keyup": "_change"
});
this._on({
"mousedown": "_change"
});
this._on(this.element.closest("form"), {
"reset": "_handleReset"
});
this._on(firstHandle, {
"mousedown": "_dragFirstHandle"
});
},
_handleReset: function () {
var self = this;
//we must wait for the stack to unwind before updateing other wise sliders will not have updated yet
setTimeout(function () {
self._updateHighlight();
}, 0);
},
_dragFirstHandle: function (event) {
//if the first handle is dragged send the event to the first slider
$.data(this._inputFirst.get(0), "mobile-slider").dragging = true;
$.data(this._inputFirst.get(0), "mobile-slider").refresh(event);
$.data(this._inputFirst.get(0), "mobile-slider")._trigger("start");
return false;
},
_slidedrag: function (event) {
var first = $(event.target).is(this._inputFirst),
otherSlider = (first) ? this._inputLast : this._inputFirst;
this._sliderTarget = false;
//if the drag was initiated on an extreme and the other handle is focused send the events to
//the closest handle
if ((this._proxy === "first" && first) || (this._proxy === "last" && !first)) {
$.data(otherSlider.get(0), "mobile-slider").dragging = true;
$.data(otherSlider.get(0), "mobile-slider").refresh(event);
return false;
}
},
_slidestop: function (event) {
var first = $(event.target).is(this._inputFirst);
this._proxy = false;
//this stops dragging of the handle and brings the active track to the front
//this makes clicks on the track go the the last handle used
this.element.find("input").trigger("mouseup");
this._sliderFirst.css("z-index", first ? 1 : "");
},
_slidebeforestart: function (event) {
this._sliderTarget = false;
//if the track is the target remember this and the original value
if ($(event.originalEvent.target).hasClass("ui-slider-track")) {
this._sliderTarget = true;
this._targetVal = $(event.target).val();
}
},
_setOptions: function (options) {
if (options.theme !== undefined) {
this._setTheme(options.theme);
}
if (options.trackTheme !== undefined) {
this._setTrackTheme(options.trackTheme);
}
if (options.mini !== undefined) {
this._setMini(options.mini);
}
if (options.highlight !== undefined) {
this._setHighlight(options.highlight);
}
if (options.disabled !== undefined) {
this._setDisabled(options.disabled);
}
this._super(options);
this.refresh();
},
refresh: function () {
var $el = this.element,
o = this.options;
if (this._inputFirst.is(":disabled") || this._inputLast.is(":disabled")) {
this.options.disabled = true;
}
$el.find("input").slider({
theme: o.theme,
trackTheme: o.trackTheme,
disabled: o.disabled,
corners: o.corners,
mini: o.mini,
highlight: o.highlight
}).slider("refresh");
this._updateHighlight();
},
_change: function (event) {
if (event.type === "keyup") {
this._updateHighlight();
return false;
}
var self = this,
min = parseFloat(this._inputFirst.val(), 10),
max = parseFloat(this._inputLast.val(), 10),
first = $(event.target).hasClass("ui-rangeslider-first"),
thisSlider = first ? this._inputFirst : this._inputLast,
otherSlider = first ? this._inputLast : this._inputFirst;
if ((this._inputFirst.val() > this._inputLast.val() && event.type === "mousedown" && !$(event.target).hasClass("ui-slider-handle"))) {
thisSlider.blur();
} else if (event.type === "mousedown") {
return;
}
if (min > max && !this._sliderTarget) {
//this prevents min from being greater then max
thisSlider.val(first ? max : min).slider("refresh");
this._trigger("normalize");
} else if (min > max) {
//this makes it so clicks on the target on either extreme go to the closest handle
thisSlider.val(this._targetVal).slider("refresh");
//You must wait for the stack to unwind so first slider is updated before updating second
setTimeout(function () {
otherSlider.val(first ? min : max).slider("refresh");
$.data(otherSlider.get(0), "mobile-slider").handle.focus();
self._sliderFirst.css("z-index", first ? "" : 1);
self._trigger("normalize");
}, 0);
this._proxy = (first) ? "first" : "last";
}
//fixes issue where when both _sliders are at min they cannot be adjusted
if (min === max) {
$.data(thisSlider.get(0), "mobile-slider").handle.css("z-index", 1);
$.data(otherSlider.get(0), "mobile-slider").handle.css("z-index", 0);
} else {
$.data(otherSlider.get(0), "mobile-slider").handle.css("z-index", "");
$.data(thisSlider.get(0), "mobile-slider").handle.css("z-index", "");
}
this._updateHighlight();
if (min >= max) {
return false;
}
},
_updateHighlight: function () {
var min = parseInt($.data(this._inputFirst.get(0), "mobile-slider").handle.get(0).style.left, 10),
max = parseInt($.data(this._inputLast.get(0), "mobile-slider").handle.get(0).style.left, 10),
width = (max - min);
this.element.find(".ui-slider-bg").css({
"margin-left": min + "%",
"width": width + "%"
});
},
_setTheme: function (value) {
this._inputFirst.slider("option", "theme", value);
this._inputLast.slider("option", "theme", value);
},
_setTrackTheme: function (value) {
this._inputFirst.slider("option", "trackTheme", value);
this._inputLast.slider("option", "trackTheme", value);
},
_setMini: function (value) {
this._inputFirst.slider("option", "mini", value);
this._inputLast.slider("option", "mini", value);
this.element.toggleClass("ui-mini", !!value);
},
_setHighlight: function (value) {
this._inputFirst.slider("option", "highlight", value);
this._inputLast.slider("option", "highlight", value);
},
_setDisabled: function (value) {
this._inputFirst.prop("disabled", value);
this._inputLast.prop("disabled", value);
},
_destroy: function () {
this._label.prependTo(this.element);
this.element.removeClass("ui-rangeslider ui-mini");
this._inputFirst.after(this._sliderFirst);
this._inputLast.after(this._sliderLast);
this._sliders.remove();
this.element.find("input").removeClass("ui-rangeslider-first ui-rangeslider-last").slider("destroy");
}
}, $.mobile.behaviors.formReset));
})(jQuery);
(function ($, undefined) {
var popup;
function getPopup() {
if (!popup) {
popup = $("<div></div>", {
"class": "ui-slider-popup ui-shadow ui-corner-all"
});
}
return popup.clone();
}
$.widget("mobile.slider", $.mobile.slider, {
options: {
popupEnabled: false,
showValue: false
},
_create: function () {
this._super();
$.extend(this, {
_currentValue: null,
_popup: null,
_popupVisible: false
});
this._setOption("popupEnabled", this.options.popupEnabled);
this._on(this.handle, { "mousedown": "_showPopup" });
this._on(this.slider.add(this.document), { "mouseup": "_hidePopup" });
this._refresh();
},
// position the popup centered 5px above the handle
_positionPopup: function () {
var dstOffset = this.handle.offset();
this._popup.offset({
left: dstOffset.left + (this.handle.width() - this._popup.width()) / 2,
top: dstOffset.top - this._popup.outerHeight() - 5
});
},
_setOption: function (key, value) {
this._super(key, value);
if (key === "showValue") {
this.handle.html(value && !this.options.mini ? this._value() : "");
} else if (key === "popupEnabled") {
if (value && !this._popup) {
this._popup = getPopup()
.addClass("ui-body-" + (this.options.theme || "a"))
.hide()
.insertBefore(this.element);
}
}
},
// show value on the handle and in popup
refresh: function () {
this._super.apply(this, arguments);
this._refresh();
},
_refresh: function () {
var o = this.options, newValue;
if (o.popupEnabled) {
// remove the title attribute from the handle (which is
// responsible for the annoying tooltip); NB we have
// to do it here as the jqm slider sets it every time
// the slider's value changes :(
this.handle.removeAttr("title");
}
newValue = this._value();
if (newValue === this._currentValue) {
return;
}
this._currentValue = newValue;
if (o.popupEnabled && this._popup) {
this._positionPopup();
this._popup.html(newValue);
}
if (o.showValue && !this.options.mini) {
this.handle.html(newValue);
}
},
_showPopup: function () {
if (this.options.popupEnabled && !this._popupVisible) {
this.handle.html("");
this._popup.show();
this._positionPopup();
this._popupVisible = true;
}
},
_hidePopup: function () {
var o = this.options;
if (o.popupEnabled && this._popupVisible) {
if (o.showValue && !o.mini) {
this.handle.html(this._value());
}
this._popup.hide();
this._popupVisible = false;
}
}
});
})(jQuery);