/** * External dependencies. * */ var mouse = require('ui-component-mouse') , events = require('component-events') , classes = require('component-classes') , percentage = require('abpetkov-percentage-calc'); /** * Expose `Powerange`. */ module.exports = Powerange; /** * Create Powerange object. * * @constructor * @param {Object} element * @param {Object} options * @api public */ function Powerange(element, options) { if (!(this instanceof Powerange)) return new Powerange(element, options); this.element = element; this.options = options || {}; this.slider = this.create('span', 'range-bar'); if (this.element !== null && this.element.type === 'text') this.init(); } /** * Bind events on handle element. * * @api private */ Powerange.prototype.bindEvents = function () { this.handle = this.slider.querySelector('.range-handle'); this.touch = events(this.handle, this); this.touch.bind('touchstart', 'onmousedown'); this.touch.bind('touchmove', 'onmousemove'); this.touch.bind('touchend', 'onmouseup'); this.mouse = mouse(this.handle, this); this.mouse.bind(); }; /** * Hide the target element. * * @api private */ Powerange.prototype.hide = function() { this.element.style.display = 'none'; }; /** * Append the target after the element. * * @api private */ Powerange.prototype.append = function() { var slider = this.generate(); this.insertAfter(this.element, slider); }; /** * Generate the appropriate type of slider. * * @returns {Object} this.slider * @api private */ Powerange.prototype.generate = function() { var elems = { 'handle': { 'type': 'span' , 'selector': 'range-handle' } , 'min': { 'type': 'span' , 'selector': 'range-min' } , 'max': { 'type': 'span' , 'selector': 'range-max' } , 'quantity': { 'type': 'span' , 'selector': 'range-quantity' } }; for (var key in elems) { if (elems.hasOwnProperty(key)) { var temp = this.create(elems[key].type, elems[key].selector); this.slider.appendChild(temp); } } return this.slider; }; /** * Create HTML element. * * @param {String} type * @param {String} name * @returns {Object} elem * @api private */ Powerange.prototype.create = function(type, name) { var elem = document.createElement(type); elem.className = name; return elem; }; /** * Insert element after another element. * * @param {Object} reference * @param {Object} target * @api private */ Powerange.prototype.insertAfter = function(reference, target) { reference.parentNode.insertBefore(target, reference.nextSibling); }; /** * Add an additional class for extra customization. * * @param {String} klass * @api private */ Powerange.prototype.extraClass = function(klass) { if (this.options.klass) classes(this.slider).add(klass); }; /** * Set min and max values. * * @param {Number} min * @param {Number} max * @api private */ Powerange.prototype.setRange = function(min, max) { if (typeof min === 'number' && typeof max === 'number' && !this.options.hideRange) { this.slider.querySelector('.range-min').innerHTML = min; this.slider.querySelector('.range-max').innerHTML = max; } }; /** * Set slider current value. * * @param {Number} offset * @param {Number} size * @api private */ Powerange.prototype.setValue = function (offset, size) { var part = percentage.from(parseFloat(offset), size) , value = percentage.of(part, this.options.max - this.options.min) + this.options.min , changed = false; value = (this.options.decimal) ? (Math.round(value * 100) / 100) : Math.round(value); changed = (this.element.value != value) ? true : false; this.element.value = value; this.options.callback(); if (changed) this.changeEvent(); }; /** * Set step. * * @param {Number} sliderSize * @param {Number} handleSize * @returns {Array} this.steps * @api private */ Powerange.prototype.step = function(sliderSize, handleSize) { var dimension = sliderSize - handleSize , part = percentage.from(this.checkStep(this.options.step), this.options.max - this.options.min) , interval = percentage.of(part, dimension) , steps = []; for (i = 0; i <= dimension; i += interval) { steps.push(i); } this.steps = steps; return this.steps; }; /** * Check values. * * @param {Number} start * @api private */ Powerange.prototype.checkValues = function(start) { if (start < this.options.min) this.options.start = this.options.min; if (start > this.options.max) this.options.start = this.options.max; if (this.options.min >= this.options.max) this.options.min = this.options.max; }; /** * Make sure `step` is positive. * * @param {Number} value * @returns {Number} this.options.step * @api private */ Powerange.prototype.checkStep = function(value) { if (value < 0) value = Math.abs(value); this.options.step = value; return this.options.step; }; /** * Disable range slider. * * @api private */ Powerange.prototype.disable = function() { if (this.options.min == this.options.max || this.options.min > this.options.max || this.options.disable) { this.mouse.unbind(); this.touch.unbind(); this.slider.style.opacity = this.options.disableOpacity; } }; /** * Make element unselectable. * * @param {Object} element * @param {Boolean} set * @api private */ Powerange.prototype.unselectable = function(element, set) { if (!classes(this.slider).has('unselectable') && set === true) { classes(this.slider).add('unselectable'); } else { classes(this.slider).remove('unselectable'); } }; /** * Handle the onchange event. * * @param {Boolean} state * @api private */ Powerange.prototype.changeEvent = function(state) { if (typeof Event === 'function' || !document.fireEvent) { var event = document.createEvent('HTMLEvents'); event.initEvent('change', false, true); this.element.dispatchEvent(event); } else { this.element.fireEvent('onchange'); } }; /** * Initialize main class. * * @api private */ Powerange.prototype.init = function() { this.hide(); this.append(); this.bindEvents(); this.extraClass(this.options.klass); this.checkValues(this.options.start); this.setRange(this.options.min, this.options.max); this.disable(); };