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