vendor: 17,985 bytes, lines 1-498
1/*! rangeslider.js - v2.3.2 | (c) 2018 @andreruffert | MIT license | https://github.com/andreruffert/rangeslider.js */ 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 module.exports = factory(require('jquery')); 11 } else { 12 // Browser globals 13 factory(jQuery); 14 } 15}(function($) { 16 'use strict'; 17 18 // Polyfill Number.isNaN(value) 19 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN 20 Number.isNaN = Number.isNaN || function(value) { 21 return typeof value === 'number' && value !== value; 22 }; 23 24 /** 25 * Range feature detection 26 * @return {Boolean} 27 */ 28 function supportsRange() { 29 var input = document.createElement('input'); 30 input.setAttribute('type', 'range'); 31 return input.type !== 'text'; 32 } 33 34 var pluginName = 'rangeslider', 35 pluginIdentifier = 0, 36 hasInputRangeSupport = supportsRange(), 37 defaults = { 38 polyfill: true, 39 orientation: 'horizontal', 40 rangeClass: 'rangeslider', 41 disabledClass: 'rangeslider--disabled', 42 activeClass: 'rangeslider--active', 43 horizontalClass: 'rangeslider--horizontal', 44 verticalClass: 'rangeslider--vertical', 45 fillClass: 'rangeslider__fill', 46 handleClass: 'rangeslider__handle', 47 startEvent: ['mousedown', 'touchstart', 'pointerdown'], 48 moveEvent: ['mousemove', 'touchmove', 'pointermove'], 49 endEvent: ['mouseup', 'touchend', 'pointerup'] 50 }, 51 constants = { 52 orientation: { 53 horizontal: { 54 dimension: 'width', 55 direction: 'left', 56 directionStyle: 'left', 57 coordinate: 'x' 58 }, 59 vertical: { 60 dimension: 'height', 61 direction: 'top', 62 directionStyle: 'bottom', 63 coordinate: 'y' 64 } 65 } 66 }; 67 68 /** 69 * Delays a function for the given number of milliseconds, and then calls 70 * it with the arguments supplied. 71 * 72 * @param {Function} fn [description] 73 * @param {Number} wait [description] 74 * @return {Function} 75 */ 76 function delay(fn, wait) { 77 var args = Array.prototype.slice.call(arguments, 2); 78 return setTimeout(function(){ return fn.apply(null, args); }, wait); 79 } 80 81 /** 82 * Returns a debounced function that will make sure the given 83 * function is not triggered too much. 84 * 85 * @param {Function} fn Function to debounce. 86 * @param {Number} debounceDuration OPTIONAL. The amount of time in milliseconds for which we will debounce the function. (defaults to 100ms) 87 * @return {Function} 88 */ 89 function debounce(fn, debounceDuration) { 90 debounceDuration = debounceDuration || 100; 91 return function() { 92 if (!fn.debouncing) { 93 var args = Array.prototype.slice.apply(arguments); 94 fn.lastReturnVal = fn.apply(window, args); 95 fn.debouncing = true; 96 } 97 clearTimeout(fn.debounceTimeout); 98 fn.debounceTimeout = setTimeout(function(){ 99 fn.debouncing = false; 100 }, debounceDuration); 101 return fn.lastReturnVal; 102 }; 103 } 104 105 /** 106 * Check if a `element` is visible in the DOM 107 * 108 * @param {Element} element 109 * @return {Boolean} 110 */ 111 function isHidden(element) { 112 return ( 113 element && ( 114 element.offsetWidth === 0 || 115 element.offsetHeight === 0 || 116 // Also Consider native `<details>` elements. 117 element.open === false 118 ) 119 ); 120 } 121 122 /** 123 * Get hidden parentNodes of an `element` 124 * 125 * @param {Element} element 126 * @return {[type]} 127 */ 128 function getHiddenParentNodes(element) { 129 var parents = [], 130 node = element.parentNode; 131 132 while (isHidden(node)) { 133 parents.push(node); 134 node = node.parentNode; 135 } 136 return parents; 137 } 138 139 /** 140 * Returns dimensions for an element even if it is not visible in the DOM. 141 * 142 * @param {Element} element 143 * @param {String} key (e.g. offsetWidth â¦) 144 * @return {Number} 145 */ 146 function getDimension(element, key) { 147 var hiddenParentNodes = getHiddenParentNodes(element), 148 hiddenParentNodesLength = hiddenParentNodes.length, 149 inlineStyle = [], 150 dimension = element[key]; 151 152 // Used for native `<details>` elements 153 function toggleOpenProperty(element) { 154 if (typeof element.open !== 'undefined') { 155 element.open = (element.open) ? false : true; 156 } 157 } 158 159 if (hiddenParentNodesLength) { 160 for (var i = 0; i < hiddenParentNodesLength; i++) { 161 162 // Cache style attribute to restore it later. 163 inlineStyle[i] = hiddenParentNodes[i].style.cssText; 164 165 // visually hide 166 if (hiddenParentNodes[i].style.setProperty) { 167 hiddenParentNodes[i].style.setProperty('display', 'block', 'important'); 168 } else { 169 hiddenParentNodes[i].style.cssText += ';display: block !important'; 170 } 171 hiddenParentNodes[i].style.height = '0'; 172 hiddenParentNodes[i].style.overflow = 'hidden'; 173 hiddenParentNodes[i].style.visibility = 'hidden'; 174 toggleOpenProperty(hiddenParentNodes[i]); 175 } 176 177 // Update dimension 178 dimension = element[key]; 179 180 for (var j = 0; j < hiddenParentNodesLength; j++) { 181 182 // Restore the style attribute 183 hiddenParentNodes[j].style.cssText = inlineStyle[j]; 184 toggleOpenProperty(hiddenParentNodes[j]); 185 } 186 } 187 return dimension; 188 } 189 190 /** 191 * Returns the parsed float or the default if it failed. 192 * 193 * @param {String} str 194 * @param {Number} defaultValue 195 * @return {Number} 196 */ 197 function tryParseFloat(str, defaultValue) { 198 var value = parseFloat(str); 199 return Number.isNaN(value) ? defaultValue : value; 200 } 201 202 /** 203 * Capitalize the first letter of string 204 * 205 * @param {String} str 206 * @return {String} 207 */ 208 function ucfirst(str) { 209 return str.charAt(0).toUpperCase() + str.substr(1); 210 } 211 212 /** 213 * Plugin 214 * @param {String} element 215 * @param {Object} options 216 */ 217 function Plugin(element, options) { 218 this.$window = $(window); 219 this.$document = $(document); 220 this.$element = $(element); 221 this.options = $.extend( {}, defaults, options ); 222 this.polyfill = this.options.polyfill; 223 this.orientation = this.$element[0].getAttribute('data-orientation') || this.options.orientation; 224 this.onInit = this.options.onInit; 225 this.onSlide = this.options.onSlide; 226 this.onSlideEnd = this.options.onSlideEnd; 227 this.DIMENSION = constants.orientation[this.orientation].dimension; 228 this.DIRECTION = constants.orientation[this.orientation].direction; 229 this.DIRECTION_STYLE = constants.orientation[this.orientation].directionStyle; 230 this.COORDINATE = constants.orientation[this.orientation].coordinate; 231 232 // Plugin should only be used as a polyfill 233 if (this.polyfill) { 234 // Input range support? 235 if (hasInputRangeSupport) { return false; } 236 } 237 238 this.identifier = 'js-' + pluginName + '-' +(pluginIdentifier++); 239 this.startEvent = this.options.startEvent.join('.' + this.identifier + ' ') + '.' + this.identifier; 240 this.moveEvent = this.options.moveEvent.join('.' + this.identifier + ' ') + '.' + this.identifier; 241 this.endEvent = this.options.endEvent.join('.' + this.identifier + ' ') + '.' + this.identifier; 242 this.toFixed = (this.step + '').replace('.', '').length - 1; 243 this.$fill = $('<div class="' + this.options.fillClass + '" />'); 244 this.$handle = $('<div class="' + this.options.handleClass + '" />'); 245 this.$range = $('<div class="' + this.options.rangeClass + ' ' + this.options[this.orientation + 'Class'] + '" id="' + this.identifier + '" />').insertAfter(this.$element).prepend(this.$fill, this.$handle); 246 247 // visually hide the input 248 this.$element.css({ 249 'position': 'absolute', 250 'width': '1px', 251 'height': '1px', 252 'overflow': 'hidden', 253 'opacity': '0' 254 }); 255 256 // Store context 257 this.handleDown = $.proxy(this.handleDown, this); 258 this.handleMove = $.proxy(this.handleMove, this); 259 this.handleEnd = $.proxy(this.handleEnd, this); 260 261 this.init(); 262 263 // Attach Events 264 var _this = this; 265 this.$window.on('resize.' + this.identifier, debounce(function() { 266 // Simulate resizeEnd event. 267 delay(function() { _this.update(false, false); }, 300); 268 }, 20)); 269 270 this.$document.on(this.startEvent, '#' + this.identifier + ':not(.' + this.options.disabledClass + ')', this.handleDown); 271 272 // Listen to programmatic value changes 273 this.$element.on('change.' + this.identifier, function(e, data) { 274 if (data && data.origin === _this.identifier) { 275 return; 276 } 277 278 var value = e.target.value, 279 pos = _this.getPositionFromValue(value); 280 _this.setPosition(pos); 281 }); 282 } 283 284 Plugin.prototype.init = function() { 285 this.update(true, false); 286 287 if (this.onInit && typeof this.onInit === 'function') { 288 this.onInit(); 289 } 290 }; 291 292 Plugin.prototype.update = function(updateAttributes, triggerSlide) { 293 updateAttributes = updateAttributes || false; 294 295 if (updateAttributes) { 296 this.min = tryParseFloat(this.$element[0].getAttribute('min'), 0); 297 this.max = tryParseFloat(this.$element[0].getAttribute('max'), 100); 298 this.value = tryParseFloat(this.$element[0].value, Math.round(this.min + (this.max-this.min)/2)); 299 this.step = tryParseFloat(this.$element[0].getAttribute('step'), 1); 300 } 301 302 this.handleDimension = getDimension(this.$handle[0], 'offset' + ucfirst(this.DIMENSION)); 303 this.rangeDimension = getDimension(this.$range[0], 'offset' + ucfirst(this.DIMENSION)); 304 this.maxHandlePos = this.rangeDimension - this.handleDimension; 305 this.grabPos = this.handleDimension / 2; 306 this.position = this.getPositionFromValue(this.value); 307 308 // Consider disabled state 309 if (this.$element[0].disabled) { 310 this.$range.addClass(this.options.disabledClass); 311 } else { 312 this.$range.removeClass(this.options.disabledClass); 313 } 314 315 this.setPosition(this.position, triggerSlide); 316 }; 317 318 Plugin.prototype.handleDown = function(e) { 319 e.preventDefault(); 320 321 // Only respond to mouse main button clicks (usually the left button) 322 if (e.button && e.button !== 0) { return; } 323 324 this.$document.on(this.moveEvent, this.handleMove); 325 this.$document.on(this.endEvent, this.handleEnd); 326 327 // add active class because Firefox is ignoring 328 // the handle:active pseudo selector because of `e.preventDefault();` 329 this.$range.addClass(this.options.activeClass); 330 331 // If we click on the handle don't set the new position 332 if ((' ' + e.target.className + ' ').replace(/[\n\t]/g, ' ').indexOf(this.options.handleClass) > -1) { 333 return; 334 } 335 336 var pos = this.getRelativePosition(e), 337 rangePos = this.$range[0].getBoundingClientRect()[this.DIRECTION], 338 handlePos = this.getPositionFromNode(this.$handle[0]) - rangePos, 339 setPos = (this.orientation === 'vertical') ? (this.maxHandlePos - (pos - this.grabPos)) : (pos - this.grabPos); 340 341 this.setPosition(setPos); 342 343 if (pos >= handlePos && pos < handlePos + this.handleDimension) { 344 this.grabPos = pos - handlePos; 345 } 346 }; 347 348 Plugin.prototype.handleMove = function(e) { 349 e.preventDefault(); 350 var pos = this.getRelativePosition(e); 351 var setPos = (this.orientation === 'vertical') ? (this.maxHandlePos - (pos - this.grabPos)) : (pos - this.grabPos); 352 this.setPosition(setPos); 353 }; 354 355 Plugin.prototype.handleEnd = function(e) { 356 e.preventDefault(); 357 this.$document.off(this.moveEvent, this.handleMove); 358 this.$document.off(this.endEvent, this.handleEnd); 359 360 this.$range.removeClass(this.options.activeClass); 361 362 // Ok we're done fire the change event 363 this.$element.trigger('change', { origin: this.identifier }); 364 365 if (this.onSlideEnd && typeof this.onSlideEnd === 'function') { 366 this.onSlideEnd(this.position, this.value); 367 } 368 }; 369 370 Plugin.prototype.cap = function(pos, min, max) { 371 if (pos < min) { return min; } 372 if (pos > max) { return max; } 373 return pos; 374 }; 375 376 Plugin.prototype.setPosition = function(pos, triggerSlide) { 377 var value, newPos; 378 379 if (triggerSlide === undefined) { 380 triggerSlide = true; 381 } 382 383 // Snapping steps 384 value = this.getValueFromPosition(this.cap(pos, 0, this.maxHandlePos)); 385 newPos = this.getPositionFromValue(value); 386 387 // Update ui 388 this.$fill[0].style[this.DIMENSION] = (newPos + this.grabPos) + 'px'; 389 this.$handle[0].style[this.DIRECTION_STYLE] = newPos + 'px'; 390 this.setValue(value); 391 392 // Update globals 393 this.position = newPos; 394 this.value = value; 395 396 if (triggerSlide && this.onSlide && typeof this.onSlide === 'function') { 397 this.onSlide(newPos, value); 398 } 399 }; 400 401 // Returns element position relative to the parent 402 Plugin.prototype.getPositionFromNode = function(node) { 403 var i = 0; 404 while (node !== null) { 405 i += node.offsetLeft; 406 node = node.offsetParent; 407 } 408 return i; 409 }; 410 411 Plugin.prototype.getRelativePosition = function(e) { 412 // Get the offset DIRECTION relative to the viewport 413 var ucCoordinate = ucfirst(this.COORDINATE), 414 rangePos = this.$range[0].getBoundingClientRect()[this.DIRECTION], 415 pageCoordinate = 0; 416 417 if (typeof e.originalEvent['client' + ucCoordinate] !== 'undefined') { 418 pageCoordinate = e.originalEvent['client' + ucCoordinate]; 419 } 420 else if ( 421 e.originalEvent.touches && 422 e.originalEvent.touches[0] && 423 typeof e.originalEvent.touches[0]['client' + ucCoordinate] !== 'undefined' 424 ) { 425 pageCoordinate = e.originalEvent.touches[0]['client' + ucCoordinate]; 426 } 427 else if(e.currentPoint && typeof e.currentPoint[this.COORDINATE] !== 'undefined') { 428 pageCoordinate = e.currentPoint[this.COORDINATE]; 429 } 430 431 return pageCoordinate - rangePos; 432 }; 433 434 Plugin.prototype.getPositionFromValue = function(value) { 435 var percentage, pos; 436 percentage = (value - this.min)/(this.max - this.min); 437 pos = (!Number.isNaN(percentage)) ? percentage * this.maxHandlePos : 0; 438 return pos; 439 }; 440 441 Plugin.prototype.getValueFromPosition = function(pos) { 442 var percentage, value; 443 percentage = ((pos) / (this.maxHandlePos || 1)); 444 value = this.step * Math.round(percentage * (this.max - this.min) / this.step) + this.min; 445 return Number((value).toFixed(this.toFixed)); 446 }; 447 448 Plugin.prototype.setValue = function(value) { 449 if (value === this.value && this.$element[0].value !== '') { 450 return; 451 } 452 453 // Set the new value and fire the `input` event 454 this.$element 455 .val(value) 456 .trigger('input', { origin: this.identifier }); 457 }; 458 459 Plugin.prototype.destroy = function() { 460 this.$document.off('.' + this.identifier); 461 this.$window.off('.' + this.identifier); 462 463 this.$element 464 .off('.' + this.identifier) 465 .removeAttr('style') 466 .removeData('plugin_' + pluginName); 467 468 // Remove the generated markup 469 if (this.$range && this.$range.length) { 470 this.$range[0].parentNode.removeChild(this.$range[0]); 471 } 472 }; 473 474 // A really lightweight plugin wrapper around the constructor, 475 // preventing against multiple instantiations 476 $.fn[pluginName] = function(options) { 477 var args = Array.prototype.slice.call(arguments, 1); 478 479 return this.each(function() { 480 var $this = $(this), 481 data = $this.data('plugin_' + pluginName); 482 483 // Create a new instance. 484 if (!data) { 485 $this.data('plugin_' + pluginName, (data = new Plugin(this, options))); 486 } 487 488 // Make it possible to access methods from public. 489 // e.g `$element.rangeslider('method');` 490 if (typeof options === 'string') { 491 data[options].apply(data, args); 492 } 493 }); 494 }; 495 496 return 'rangeslider.js is available in jQuery context e.g $(selector).rangeslider(options);'; 497 498}));
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.