Slider.js 5.14 KB
/**
 * Slider.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * Slider control.
 *
 * @-x-less Slider.less
 * @class tinymce.ui.Slider
 * @extends tinymce.ui.Widget
 */
define("tinymce/ui/Slider", [
	"tinymce/ui/Widget",
	"tinymce/ui/DragHelper",
	"tinymce/ui/DomUtils"
], function(Widget, DragHelper, DomUtils) {
	"use strict";

	function constrain(value, minVal, maxVal) {
		if (value < minVal) {
			value = minVal;
		}

		if (value > maxVal) {
			value = maxVal;
		}

		return value;
	}

	function setAriaProp(el, name, value) {
		el.setAttribute('aria-' + name, value);
	}

	function updateSliderHandle(ctrl, value) {
		var maxHandlePos, shortSizeName, sizeName, stylePosName, styleValue, handleEl;

		if (ctrl.settings.orientation == "v") {
			stylePosName = "top";
			sizeName = "height";
			shortSizeName = "h";
		} else {
			stylePosName = "left";
			sizeName = "width";
			shortSizeName = "w";
		}

		handleEl = ctrl.getEl('handle');
		maxHandlePos = (ctrl.layoutRect()[shortSizeName] || 100) - DomUtils.getSize(handleEl)[sizeName];

		styleValue = (maxHandlePos * ((value - ctrl._minValue) / (ctrl._maxValue - ctrl._minValue))) + 'px';
		handleEl.style[stylePosName] = styleValue;
		handleEl.style.height = ctrl.layoutRect().h + 'px';

		setAriaProp(handleEl, 'valuenow', value);
		setAriaProp(handleEl, 'valuetext', '' + ctrl.settings.previewFilter(value));
		setAriaProp(handleEl, 'valuemin', ctrl._minValue);
		setAriaProp(handleEl, 'valuemax', ctrl._maxValue);
	}

	return Widget.extend({
		init: function(settings) {
			var self = this;

			if (!settings.previewFilter) {
				settings.previewFilter = function(value) {
					return Math.round(value * 100) / 100.0;
				};
			}

			self._super(settings);
			self.classes.add('slider');

			if (settings.orientation == "v") {
				self.classes.add('vertical');
			}

			self._minValue = settings.minValue || 0;
			self._maxValue = settings.maxValue || 100;
			self._initValue = self.state.get('value');
		},

		renderHtml: function() {
			var self = this, id = self._id, prefix = self.classPrefix;

			return (
				'<div id="' + id + '" class="' + self.classes + '">' +
					'<div id="' + id + '-handle" class="' + prefix + 'slider-handle" role="slider" tabindex="-1"></div>' +
				'</div>'
			);
		},

		reset: function() {
			this.value(this._initValue).repaint();
		},

		postRender: function() {
			var self = this, minValue, maxValue, screenCordName,
					stylePosName, sizeName, shortSizeName;

			function toFraction(min, max, val) {
				return (val + min) / (max - min);
			}

			function fromFraction(min, max, val) {
				return (val * (max - min)) - min;
			}

			function handleKeyboard(minValue, maxValue) {
				function alter(delta) {
					var value;

					value = self.value();
					value = fromFraction(minValue, maxValue, toFraction(minValue, maxValue, value) + (delta * 0.05));
					value = constrain(value, minValue, maxValue);

					self.value(value);

					self.fire('dragstart', {value: value});
					self.fire('drag', {value: value});
					self.fire('dragend', {value: value});
				}

				self.on('keydown', function(e) {
					switch (e.keyCode) {
						case 37:
						case 38:
							alter(-1);
							break;

						case 39:
						case 40:
							alter(1);
							break;
					}
				});
			}

			function handleDrag(minValue, maxValue, handleEl) {
				var startPos, startHandlePos, maxHandlePos, handlePos, value;

				self._dragHelper = new DragHelper(self._id, {
					handle: self._id + "-handle",

					start: function(e) {
						startPos = e[screenCordName];
						startHandlePos = parseInt(self.getEl('handle').style[stylePosName], 10);
						maxHandlePos = (self.layoutRect()[shortSizeName] || 100) - DomUtils.getSize(handleEl)[sizeName];
						self.fire('dragstart', {value: value});
					},

					drag: function(e) {
						var delta = e[screenCordName] - startPos;

						handlePos = constrain(startHandlePos + delta, 0, maxHandlePos);
						handleEl.style[stylePosName] = handlePos + 'px';

						value = minValue + (handlePos / maxHandlePos) * (maxValue - minValue);
						self.value(value);

						self.tooltip().text('' + self.settings.previewFilter(value)).show().moveRel(handleEl, 'bc tc');

						self.fire('drag', {value: value});
					},

					stop: function() {
						self.tooltip().hide();
						self.fire('dragend', {value: value});
					}
				});
			}

			minValue = self._minValue;
			maxValue = self._maxValue;

			if (self.settings.orientation == "v") {
				screenCordName = "screenY";
				stylePosName = "top";
				sizeName = "height";
				shortSizeName = "h";
			} else {
				screenCordName = "screenX";
				stylePosName = "left";
				sizeName = "width";
				shortSizeName = "w";
			}

			self._super();

			handleKeyboard(minValue, maxValue, self.getEl('handle'));
			handleDrag(minValue, maxValue, self.getEl('handle'));
		},

		repaint: function() {
			this._super();
			updateSliderHandle(this, this.value());
		},

		bindStates: function() {
			var self = this;

			self.state.on('change:value', function(e) {
				updateSliderHandle(self, e.value);
			});

			return self._super();
		}
	});
});