1jQuery(document).ready(function ($) { 2 (function (factory) { 3 'use strict'; 4 5 if (typeof define === 'function' && define.amd) { 6 // AMD. Register as an anonymous module. 7 define(['jquery'], factory); 8 } else if (typeof exports === 'object') { 9 // CommonJS 10 factory(require('jquery')); 11 } else { 12 // Browser globals 13 factory(jQuery); 14 } 15 }(function ($) { 16 'use strict'; 17 18 /** 19 * Range feature detection 20 * @return {Boolean} 21 */ 22 function supportsRange() { 23 var input = document.createElement('input'); 24 input.setAttribute('type', 'range'); 25 return input.type !== 'text'; 26 } 27 28 var pluginName = 'rangeslider', 29 pluginInstances = [], 30 inputrange = supportsRange(), 31 defaults = { 32 polyfill: true, 33 rangeClass: 'rangeslider', 34 disabledClass: 'rangeslider--disabled', 35 fillClass: 'rangeslider__fill', 36 handleClass: 'rangeslider__handle', 37 startEvent: ['mousedown', 'touchstart', 'pointerdown'], 38 moveEvent: ['mousemove', 'touchmove', 'pointermove'], 39 endEvent: ['mouseup', 'touchend', 'pointerup'] 40 }; 41 42 /** 43 * Delays a function for the given number of milliseconds, and then calls 44 * it with the arguments supplied. 45 * 46 * @param {Function} fn [description] 47 * @param {Number} wait [description] 48 * @return {Function} 49 */ 50 function delay(fn, wait) { 51 var args = Array.prototype.slice.call(arguments, 2); 52 return setTimeout(function () { 53 return fn.apply(null, args); 54 }, wait); 55 } 56 57 /** 58 * Returns a debounced function that will make sure the given 59 * function is not triggered too much. 60 * 61 * @param {Function} fn Function to debounce. 62 * @param {Number} debounceDuration OPTIONAL. The amount of time in milliseconds for which we will debounce the function. (defaults to 100ms) 63 * @return {Function} 64 */ 65 function debounce(fn, debounceDuration) { 66 debounceDuration = debounceDuration || 100; 67 return function () { 68 if (!fn.debouncing) { 69 var args = Array.prototype.slice.apply(arguments); 70 fn.lastReturnVal = fn.apply(window, args); 71 fn.debouncing = true; 72 } 73 clearTimeout(fn.debounceTimeout); 74 fn.debounceTimeout = setTimeout(function () { 75 fn.debouncing = false; 76 }, debounceDuration); 77 return fn.lastReturnVal; 78 }; 79 } 80 81 /** 82 * Plugin 83 * @param {String} element 84 * @param {Object} options 85 */ 86 function Plugin(element, options) { 87 this.$window = $(window); 88 this.$document = $(document); 89 this.$element = $(element); 90 this.options = $.extend({}, defaults, options); 91 this._defaults = defaults; 92 this._name = pluginName; 93 this.startEvent = this.options.startEvent.join('.' + pluginName + ' ') + '.' + pluginName; 94 this.moveEvent = this.options.moveEvent.join('.' + pluginName + ' ') + '.' + pluginName; 95 this.endEvent = this.options.endEvent.join('.' + pluginName + ' ') + '.' + pluginName; 96 this.polyfill = this.options.polyfill; 97 this.onInit = this.options.onInit; 98 this.onSlide = this.options.onSlide; 99 this.onSlideEnd = this.options.onSlideEnd; 100 101 // Plugin should only be used as a polyfill 102 if (this.polyfill) { 103 // Input range support? 104 if (inputrange) { 105 return false; 106 } 107 } 108 109 this.identifier = 'js-' + pluginName + '-' + (+new Date()); 110 this.min = parseFloat(this.$element[0].getAttribute('min') || 0); 111 this.max = parseFloat(this.$element[0].getAttribute('max') || 100); 112 this.value = parseFloat(this.$element[0].value || this.min + (this.max - this.min) / 2); 113 this.step = parseFloat(this.$element[0].getAttribute('step') || 1); 114 this.$fill = $('<div class="' + this.options.fillClass + '" />'); 115 this.$handle = $('<div class="' + this.options.handleClass + '" />'); 116 this.$range = $('<div class="' + this.options.rangeClass + '" id="' + this.identifier + '" />').insertAfter(this.$element).prepend(this.$fill, this.$handle); 117 118 // visually hide the input 119 this.$element.css({ 120 'position': 'absolute', 121 'width': '1px', 122 'height': '1px', 123 'overflow': 'hidden', 124 'opacity': '0' 125 }); 126 127 // Store context 128 this.handleDown = $.proxy(this.handleDown, this); 129 this.handleMove = $.proxy(this.handleMove, this); 130 this.handleEnd = $.proxy(this.handleEnd, this); 131 132 this.init(); 133 134 // Attach Events 135 var _this = this; 136 this.$window.on('resize' + '.' + pluginName, debounce(function () { 137 // Simulate resizeEnd event. 138 delay(function () { 139 _this.update(); 140 }, 300); 141 }, 20)); 142 143 this.$document.on(this.startEvent, '#' + this.identifier + ':not(.' + this.options.disabledClass + ')', this.handleDown); 144 145 // Listen to programmatic value changes 146 this.$element.on('change' + '.' + pluginName, function (e, data) { 147 if (data && data.origin === pluginName) { 148 return; 149 } 150 151 var value = e.target.value, 152 pos = _this.getPositionFromValue(value); 153 _this.setPosition(pos); 154 }); 155 } 156 157 Plugin.prototype.init = function () { 158 if (this.onInit && typeof this.onInit === 'function') { 159 this.onInit(); 160 } 161 this.update(); 162 }; 163 164 Plugin.prototype.update = function () { 165 this.handleWidth = this.$handle[0].offsetWidth; 166 this.rangeWidth = this.$range[0].offsetWidth; 167 this.maxHandleX = this.rangeWidth - this.handleWidth; 168 this.grabX = this.handleWidth / 2; 169 this.position = this.getPositionFromValue(this.value); 170 171 // Consider disabled state 172 if (this.$element[0].disabled) { 173 this.$range.addClass(this.options.disabledClass); 174 } else { 175 this.$range.removeClass(this.options.disabledClass); 176 } 177 178 this.setPosition(this.position); 179 }; 180 181 Plugin.prototype.handleDown = function (e) { 182 e.preventDefault(); 183 this.$document.on(this.moveEvent, this.handleMove); 184 this.$document.on(this.endEvent, this.handleEnd); 185 186 // If we click on the handle don't set the new position 187 if ((' ' + e.target.className + ' ').replace(/[\n\t]/g, ' ').indexOf(this.options.handleClass) > -1) { 188 return; 189 } 190 191 var posX = this.getRelativePosition(this.$range[0], e), 192 handleX = this.getPositionFromNode(this.$handle[0]) - this.getPositionFromNode(this.$range[0]); 193 194 this.setPosition(posX - this.grabX); 195 196 if (posX >
196= handleX && posX < handleX + this.handleWidth) { 197 this.grabX = posX - handleX; 198 } 199 }; 200 201 Plugin.prototype.handleMove = function (e) { 202 e.preventDefault(); 203 var posX = this.getRelativePosition(this.$range[0], e); 204 this.setPosition(posX - this.grabX); 205 }; 206 207 Plugin.prototype.handleEnd = function (e) { 208 e.preventDefault(); 209 this.$document.off(this.moveEvent, this.handleMove); 210 this.$document.off(this.endEvent, this.handleEnd); 211 212 if (this.onSlideEnd && typeof this.onSlideEnd === 'function') { 213 this.onSlideEnd(this.position, this.value); 214 } 215 }; 216 217 Plugin.prototype.cap = function (pos, min, max) { 218 if (pos < min) { 219 return min; 220 } 221 if (pos > max) { 222 return max; 223 } 224 return pos; 225 }; 226 227 Plugin.prototype.setPosition = function (pos) { 228 var value, left; 229 230 // Snapping steps 231 value = (this.getValueFromPosition(this.cap(pos, 0, this.maxHandleX)) / this.step) * this.step; 232 left = this.getPositionFromValue(value); 233 234 // Update ui 235 this.$fill[0].style.width = (left + this.grabX) + 'px'; 236 this.$handle[0].style.left = left + 'px'; 237 this.setValue(value); 238 239 // Update globals 240 this.position = left; 241 this.value = value; 242 243 if (this.onSlide && typeof this.onSlide === 'function') { 244 this.onSlide(left, value); 245 } 246 }; 247 248 Plugin.prototype.getPositionFromNode = function (node) { 249 var i = 0; 250 while (node !== null) { 251 i += node.offsetLeft; 252 node = node.offsetParent; 253 } 254 return i; 255 }; 256 257 Plugin.prototype.getRelativePosition = function (node, e) { 258 return (e.pageX || e.originalEvent.clientX || e.originalEvent.touches[0].clientX || e.currentPoint.x) - this.getPositionFromNode(node); 259 }; 260 261 Plugin.prototype.getPositionFromValue = function (value) { 262 var percentage, pos; 263 percentage = (value - this.min) / (this.max - this.min); 264 pos = percentage * this.maxHandleX; 265 return pos; 266 }; 267 268 Plugin.prototype.getValueFromPosition = function (pos) { 269 var percentage, value; 270 percentage = ((pos) / (this.maxHandleX || 1)); 271 value = this.step * Math.ceil((((percentage) * (this.max - this.min)) + this.min) / this.step); 272 return Number((value).toFixed(2)); 273 }; 274 275 Plugin.prototype.setValue = function (value) { 276 if (value !== this.value) { 277 this.$element.val(value).trigger('change', {origin: pluginName}); 278 } 279 }; 280 281 Plugin.prototype.destroy = function () { 282 this.$document.off(this.startEvent, '#' + this.identifier, this.handleDown); 283 this.$element 284 .off('.' + pluginName) 285 .removeAttr('style') 286 .removeData('plugin_' + pluginName); 287 288 // Remove the generated markup 289 if (this.$range && this.$range.length) { 290 this.$range[0].parentNode.removeChild(this.$range[0]); 291 } 292 293 // Remove global events if there isn't any instance anymore. 294 pluginInstances.splice(pluginInstances.indexOf(this.$element[0]), 1); 295 if (!pluginInstances.length) { 296 this.$window.off('.' + pluginName); 297 } 298 }; 299 300 // A really lightweight plugin wrapper around the constructor, 301 // preventing against multiple instantiations 302 $.fn[pluginName] = function (options) { 303 return this.each(function () { 304 var $this = $(this), 305 data = $this.data('plugin_' + pluginName); 306 307 // Create a new instance. 308 if (!data) { 309 $this.data('plugin_' + pluginName, (data = new Plugin(this, options))); 310 pluginInstances.push(this); 311 } 312 313 // Make it possible to access methods from public. 314 // e.g `$element.rangeslider('method');` 315 if (typeof options === 'string') { 316 data[options](); 317 } 318 }); 319 }; 320 321 322 var $document = $(document), selector = "[data-rangeslider]", $inputRange = $(selector); 323 324 function valueOutput(element) { 325 var value = element.value, output = element.parentNode.getElementsByTagName("output")[0]; 326 output.innerHTML = value; 327 } 328 329 for (var i = $inputRange.length - 1; i >= 0; i--) { 330 valueOutput($inputRange[i]); 331 } 332 ; 333 $document.on("change", selector, function (e) { 334 valueOutput(e.target); 335 }); 336 $inputRange.rangeslider({polyfill: false,}); 337 338 339 })); 340});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.