vendor: 7,676 bytes, lines 1-255
1/*! ========================================================= 2 * bootstrap-slider.js 3 * 4 * Maintainers: 5 * Kyle Kemp 6 * - Twitter: @seiyria 7 * - Github: seiyria 8 * Rohit Kalkur 9 * - Twitter: @Rovolutionary 10 * - Github: rovolution 11 * 12 * ========================================================= 13 * 14 * bootstrap-slider is released under the MIT License 15 * Copyright (c) 2017 Kyle Kemp, Rohit Kalkur, and contributors 16 * 17 * Permission is hereby granted, free of charge, to any person 18 * obtaining a copy of this software and associated documentation 19 * files (the "Software"), to deal in the Software without 20 * restriction, including without limitation the rights to use, 21 * copy, modify, merge, publish, distribute, sublicense, and/or sell 22 * copies of the Software, and to permit persons to whom the 23 * Software is furnished to do so, subject to the following 24 * conditions: 25 * 26 * The above copyright notice and this permission notice shall be 27 * included in all copies or substantial portions of the Software. 28 * 29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 30 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 31 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 32 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 33 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 34 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 35 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 36 * OTHER DEALINGS IN THE SOFTWARE. 37 * 38 * ========================================================= */ 39 40 41/** 42 * Bridget makes jQuery widgets 43 * v1.0.1 44 * MIT license 45 */ 46const windowIsDefined = (typeof window === "object"); 47 48 49(function(factory) { 50 if(typeof define === "function" && define.amd) { 51 define(["jquery"], factory); 52 } 53 else if(typeof module === "object" && module.exports) { 54 var jQuery; 55 try { 56 jQuery = require("jquery"); 57 } 58 catch (err) { 59 jQuery = null; 60 } 61 module.exports = factory(jQuery); 62 } 63 else if(window) { 64 window.Slider = factory(window.jQuery); 65 } 66}(function($) { 67 // Constants 68 const NAMESPACE_MAIN = 'slider'; 69 const NAMESPACE_ALTERNATE = 'bootstrapSlider'; 70 71 // Polyfill console methods 72 if (windowIsDefined && !window.console) { 73 window.console = {}; 74 } 75 if (windowIsDefined && !window.console.log) { 76 window.console.log = function () { }; 77 } 78 if (windowIsDefined && !window.console.warn) { 79 window.console.warn = function () { }; 80 } 81 82 // Reference to Slider constructor 83 var Slider; 84 85 86 (function( $ ) { 87 88 'use strict'; 89 90 // -------------------------- utils -------------------------- // 91 92 var slice = Array.prototype.slice; 93 94 function noop() {} 95 96 // -------------------------- definition -------------------------- // 97 98 function defineBridget( $ ) { 99 100 // bail if no jQuery 101 if ( !$ ) { 102 return; 103 } 104 105 // -------------------------- addOptionMethod -------------------------- // 106 107 /** 108 * adds option method -> $().plugin('option', {...}) 109 * @param {Function} PluginClass - constructor class 110 */ 111 function addOptionMethod( PluginClass ) { 112 // don't overwrite original option method 113 if ( PluginClass.prototype.option ) { 114 return; 115 } 116 117 // option setter 118 PluginClass.prototype.option = function( opts ) { 119 // bail out if not an object 120 if ( !$.isPlainObject( opts ) ){ 121 return; 122 } 123 this.options = $.extend( true, this.options, opts ); 124 }; 125 } 126 127 128 // -------------------------- plugin bridge -------------------------- // 129 130 // helper function for logging errors 131 // $.error breaks jQuery chaining 132 var logError = typeof console === 'undefined' ? noop : 133 function( message ) { 134 console.error( message ); 135 }; 136 137 /** 138 * jQuery plugin bridge, access methods like $elem.plugin('method') 139 * @param {String} namespace - plugin name 140 * @param {Function} PluginClass - constructor class 141 */ 142 function bridge( namespace, PluginClass ) { 143 // add to jQuery fn namespace 144 $.fn[ namespace ] = function( options ) { 145 if ( typeof options === 'string' ) { 146 // call plugin method when first argument is a string 147 // get arguments for method 148 var args = slice.call( arguments, 1 ); 149 150 for ( var i=0, len = this.length; i < len; i++ ) { 151 var elem = this[i]; 152 var instance = $.data( elem, namespace ); 153 if ( !instance ) { 154 logError( "cannot call methods on " + namespace + " prior to initialization; " + 155 "attempted to call '" + options + "'" ); 156 continue; 157 } 158 if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) { 159 logError( "no such method '" + options + "' for " + namespace + " instance" ); 160 continue; 161 } 162 163 // trigger method with arguments 164 var returnValue = instance[ options ].apply( instance, args); 165 166 // break look and return first value if provided 167 if ( returnValue !== undefined && returnValue !== instance) { 168 return returnValue; 169 } 170 } 171 // return this if no return value 172 return this; 173 } else { 174 var objects = this.map( function() { 175 var instance = $.data( this, namespace ); 176 if ( instance ) { 177 // apply options & init 178 instance.option( options ); 179 instance._init(); 180 } else { 181 // initialize new instance 182 instance = new PluginClass( this, options ); 183 $.data( this, namespace, instance ); 184 } 185 return $(this); 186 }); 187 188 if(!objects || objects.length > 1) { 189 return objects; 190 } else { 191 return objects[0]; 192 } 193 } 194 }; 195 196 } 197 198 // -------------------------- bridget -------------------------- // 199 200 /** 201 * converts a Prototypical class into a proper jQuery plugin 202 * the class must have a ._init method 203 * @param {String} namespace - plugin name, used in $().pluginName 204 * @param {Function} PluginClass - constructor class 205 */ 206 $.bridget = function( namespace, PluginClass ) { 207 addOptionMethod( PluginClass ); 208 bridge( namespace, PluginClass ); 209 }; 210 211 return $.bridget; 212 213 } 214 215 // get jquery from browser global 216 defineBridget( $ ); 217 218 })( $ ); 219 220 221 /************************************************* 222 223 BOOTSTRAP-SLIDER SOURCE CODE 224 225 **************************************************/ 226 227 (function($) { 228 229 var ErrorMsgs = { 230 formatInvalidInputErrorMsg : function(input) { 231 return "Invalid input value '" + input + "' passed in"; 232 }, 233 callingContextNotSliderInstance : "Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method" 234 }; 235 236 var SliderScale = { 237 linear: { 238 toValue: function(percentage) { 239 var rawValue = percentage/100 * (this.options.max - this.options.min); 240 var shouldAdjustWithBase = true; 241 if (this.options.ticks_positions.length > 0) { 242 var minv, maxv, minp, maxp = 0; 243 for (var i = 1; i < this.options.ticks_positions.length; i++) { 244 if (percentage <= this.options.ticks_positions[i]) { 245 minv = this.options.ticks[i-1]; 246 minp = this.options.ticks_positions[i-1]; 247 maxv = this.options.ticks[i]; 248 maxp = this.options.ticks_positions[i]; 249 250 break; 251 } 252 } 253 var partialPercentage = (percentage - minp) / (maxp - minp); 254 rawValue = minv + partialPercentage * (maxv - minv); 255 shouldAdjustWithBase = false;
256 } 257 258 var adjustment = shouldAdjustWithBase ? this.options.min : 0; 259 var value = adjustment + Math.round(rawValue / this.options.step) * this.options.step; 260 if (value < this.options.min) { 261 return this.options.min; 262 } else if (value > this.options.max) { 263 return this.options.max; 264 } else { 265 return value; 266 } 267 }, 268 toPercentage: function(value) { 269 if (this.options.max === this.options.min) { 270 return 0; 271 } 272 273 if (this.options.ticks_positions.length > 0) { 274 var minv, maxv, minp, maxp = 0; 275 for (var i = 0; i < this.options.ticks.length; i++) { 276 if (value <= this.options.ticks[i]) { 277 minv = (i > 0) ? this.options.ticks[i-1] : 0; 278 minp = (i > 0) ? this.options.ticks_positions[i-1] : 0; 279 maxv = this.options.ticks[i]; 280 maxp = this.options.ticks_positions[i]; 281 282 break; 283 } 284 } 285 if (i > 0) { 286 var partialPercentage = (value - minv) / (maxv - minv); 287 return minp + partialPercentage * (maxp - minp); 288 } 289 } 290 291 return 100 * (value - this.options.min) / (this.options.max - this.options.min); 292 } 293 }, 294 295 logarithmic: { 296 /* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */ 297 toValue: function(percentage) { 298 var min = (this.options.min === 0) ? 0 : Math.log(this.options.min); 299 var max = Math.log(this.options.max); 300 var value = Math.exp(min + (max - min) * percentage / 100); 301 value = this.options.min + Math.round((value - this.options.min) / this.options.step) * this.options.step; 302 /* Rounding to the nearest step could exceed the min or 303 * max, so clip to those values. */ 304 if (value < this.options.min) { 305 return this.options.min; 306 } else if (value > this.options.max) { 307 return this.options.max; 308 } else { 309 return value; 310 } 311 }, 312 toPercentage: function(value) { 313 if (this.options.max === this.options.min) { 314 return 0; 315 } else { 316 var max = Math.log(this.options.max); 317 var min = this.options.min === 0 ? 0 : Math.log(this.options.min); 318 var v = value === 0 ? 0 : Math.log(value); 319 return 100 * (v - min) / (max - min); 320 } 321 } 322 } 323 }; 324 325 326 /************************************************* 327 328 CONSTRUCTOR 329 330 **************************************************/ 331 Slider = function(element, options) { 332 createNewSlider.call(this, element, options); 333 return this; 334 }; 335 336 function createNewSlider(element, options) { 337 338 /* 339 The internal state object is used to store data about the current 'state' of slider. 340 This includes values such as the `value`, `enabled`, etc... 341 */ 342 this._state = { 343 value: null, 344 enabled: null, 345 offset: null, 346 size: null, 347 percentage: null, 348 inDrag: false, 349 over: false 350 }; 351 352 // The objects used to store the reference to the tick methods if ticks_tooltip is on 353 this.ticksCallbackMap = {}; 354 this.handleCallbackMap = {}; 355 356 if(typeof element === "string") { 357 this.element = document.querySelector(element); 358 } else if(element instanceof HTMLElement) { 359 this.element = element; 360 } 361 362 /************************************************* 363 364 Process Options 365 366 **************************************************/ 367 options = options ? options : {}; 368 var optionTypes = Object.keys(this.defaultOptions); 369 370 for(var i = 0; i < optionTypes.length; i++) { 371 var optName = optionTypes[i]; 372 373 // First check if an option was passed in via the constructor 374 var val = options[optName]; 375 // If no data attrib, then check data atrributes 376 val = (typeof val !== 'undefined') ? val : getDataAttrib(this.element, optName); 377 // Finally, if nothing was specified, use the defaults 378 val = (val !== null) ? val : this.defaultOptions[optName]; 379 380 // Set all options on the instance of the Slider 381 if(!this.options) { 382 this.options = {}; 383 } 384 this.options[optName] = val; 385 } 386 387 // Check options.rtl 388 if(this.options.rtl==='auto'){ 389 this.options.rtl = window.getComputedStyle(this.element).direction==='rtl'; 390 } 391 392 /* 393 Validate `tooltip_position` against 'orientation` 394 - if `tooltip_position` is incompatible with orientation, swith it to a default compatible with specified `orientation` 395 -- default for "vertical" -> "right", "left" if rtl 396 -- default for "horizontal" -> "top" 397 */ 398 if(this.options.orientation === "vertical" && (this.options.tooltip_position === "top" || this.options.tooltip_position === "bottom")) { 399 if(this.options.rtl) { 400 this.options.tooltip_position = "left"; 401 }else{ 402 this.options.tooltip_position = "right"; 403 } 404 } 405 else if(this.options.orientation === "horizontal" && (this.options.tooltip_position === "left" || this.options.tooltip_position === "right")) { 406 407 this.options.tooltip_position = "top"; 408 409 } 410 411 function getDataAttrib(element, optName) {
vendor: 12,710 bytes, lines 412-764
412 var dataName = "data-slider-" + optName.replace(/_/g, '-'); 413 var dataValString = element.getAttribute(dataName); 414 415 try { 416 return JSON.parse(dataValString); 417 } 418 catch(err) { 419 return dataValString; 420 } 421 } 422 423 /************************************************* 424 425 Create Markup 426 427 **************************************************/ 428 429 var origWidth = this.element.style.width; 430 var updateSlider = false; 431 var parent = this.element.parentNode; 432 var sliderTrackSelection; 433 var sliderTrackLow, sliderTrackHigh; 434 var sliderMinHandle; 435 var sliderMaxHandle; 436 437 if (this.sliderElem) { 438 updateSlider = true; 439 } else { 440 /* Create elements needed for slider */ 441 this.sliderElem = document.createElement("div"); 442 this.sliderElem.className = "slider"; 443 444 /* Create slider track elements */ 445 var sliderTrack = document.createElement("div"); 446 sliderTrack.className = "slider-track"; 447 448 sliderTrackLow = document.createElement("div"); 449 sliderTrackLow.className = "slider-track-low"; 450 451 sliderTrackSelection = document.createElement("div"); 452 sliderTrackSelection.className = "slider-selection"; 453 454 sliderTrackHigh = document.createElement("div"); 455 sliderTrackHigh.className = "slider-track-high"; 456 457 sliderMinHandle = document.createElement("div"); 458 sliderMinHandle.className = "slider-handle min-slider-handle"; 459 sliderMinHandle.setAttribute('role', 'slider'); 460 sliderMinHandle.setAttribute('aria-valuemin', this.options.min); 461 sliderMinHandle.setAttribute('aria-valuemax', this.options.max); 462 463 sliderMaxHandle = document.createElement("div"); 464 sliderMaxHandle.className = "slider-handle max-slider-handle"; 465 sliderMaxHandle.setAttribute('role', 'slider'); 466 sliderMaxHandle.setAttribute('aria-valuemin', this.options.min); 467 sliderMaxHandle.setAttribute('aria-valuemax', this.options.max); 468 469 sliderTrack.appendChild(sliderTrackLow); 470 sliderTrack.appendChild(sliderTrackSelection); 471 sliderTrack.appendChild(sliderTrackHigh); 472 473 /* Create highlight range elements */ 474 this.rangeHighlightElements = []; 475 if (Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) { 476 for (let j = 0; j < this.options.rangeHighlights.length; j++) { 477 478 var rangeHighlightElement = document.createElement("div"); 479 rangeHighlightElement.className = "slider-rangeHighlight slider-selection"; 480 481 this.rangeHighlightElements.push(rangeHighlightElement); 482 sliderTrack.appendChild(rangeHighlightElement); 483 } 484 } 485 486 /* Add aria-labelledby to handle's */ 487 var isLabelledbyArray = Array.isArray(this.options.labelledby); 488 if (isLabelledbyArray && this.options.labelledby[0]) { 489 sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby[0]); 490 } 491 if (isLabelledbyArray && this.options.labelledby[1]) { 492 sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby[1]); 493 } 494 if (!isLabelledbyArray && this.options.labelledby) { 495 sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby); 496 sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby); 497 } 498 499 /* Create ticks */ 500 this.ticks = []; 501 if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { 502 this.ticksContainer = document.createElement('div'); 503 this.ticksContainer.className = 'slider-tick-container'; 504 505 for (i = 0; i < this.options.ticks.length; i++) { 506 var tick = document.createElement('div'); 507 tick.className = 'slider-tick'; 508 if (this.options.ticks_tooltip) { 509 var tickListenerReference = this._addTickListener(); 510 var enterCallback = tickListenerReference.addMouseEnter(this, tick, i); 511 var leaveCallback = tickListenerReference.addMouseLeave(this, tick); 512 513 this.ticksCallbackMap[i] = { 514 mouseEnter: enterCallback, 515 mouseLeave: leaveCallback 516 }; 517 } 518 this.ticks.push(tick); 519 this.ticksContainer.appendChild(tick); 520 } 521 522 sliderTrackSelection.className += " tick-slider-selection"; 523 } 524 525 this.tickLabels = []; 526 if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) { 527 this.tickLabelContainer = document.createElement('div'); 528 this.tickLabelContainer.className = 'slider-tick-label-container'; 529 530 for (i = 0; i < this.options.ticks_labels.length; i++) { 531 var label = document.createElement('div'); 532 var noTickPositionsSpecified = this.options.ticks_positions.length === 0; 533 var tickLabelsIndex = (this.options.reversed && noTickPositionsSpecified) ? (this.options.ticks_labels.length - (i + 1)) : i; 534 label.className = 'slider-tick-label'; 535 label.innerHTML = this.options.ticks_labels[tickLabelsIndex]; 536 537 this.tickLabels.push(label); 538 this.tickLabelContainer.appendChild(label); 539 } 540 } 541 542 const createAndAppendTooltipSubElements = function(tooltipElem) { 543 var arrow = document.createElement("div"); 544 arrow.className = "tooltip-arrow"; 545 546 var inner = document.createElement("div"); 547 inner.className = "tooltip-inner"; 548 549 tooltipElem.appendChild(arrow); 550 tooltipElem.appendChild(inner); 551 }; 552 553 /* Create tooltip elements */ 554 const sliderTooltip = document.createElement("div"); 555 sliderTooltip.className = "tooltip tooltip-main"; 556 sliderTooltip.setAttribute('role', 'presentation'); 557 createAndAppendTooltipSubElements(sliderTooltip); 558 559 const sliderTooltipMin = document.createElement("div"); 560 sliderTooltipMin.className = "tooltip tooltip-min"; 561 sliderTooltipMin.setAttribute('role', 'presentation'); 562 createAndAppendTooltipSubElements(sliderTooltipMin); 563 564 const sliderTooltipMax = document.createElement("div"); 565 sliderTooltipMax.className = "tooltip tooltip-max"; 566 sliderTooltipMax.setAttribute('role', 'presentation'); 567 createAndAppendTooltipSubElements(sliderTooltipMax); 568 569 /* Append components to sliderElem */ 570 this.sliderElem.appendChild(sliderTrack); 571 this.sliderElem.appendChild(sliderTooltip); 572 this.sliderElem.appendChild(sliderTooltipMin); 573 this.sliderElem.appendChild(sliderTooltipMax); 574 575 if (this.tickLabelContainer) { 576 this.sliderElem.appendChild(this.tickLabelContainer); 577 } 578 if (this.ticksContainer) { 579 this.sliderElem.appendChild(this.ticksContainer); 580 } 581 582 this.sliderElem.appendChild(sliderMinHandle); 583 this.sliderElem.appendChild(sliderMaxHandle); 584 585 /* Append slider element to parent container, right before the original <input> element */ 586 parent.insertBefore(this.sliderElem, this.element); 587 588 /* Hide original <input> element */ 589 this.element.style.display = "none"; 590 } 591 /* If JQuery exists, cache JQ references */ 592 if($) { 593 this.$element = $(this.element); 594 this.$sliderElem = $(this.sliderElem); 595 } 596 597 /************************************************* 598 599 Setup 600 601 **************************************************/ 602 this.eventToCallbackMap = {}; 603 this.sliderElem.id = this.options.id; 604 605 this.touchCapable = 'ontouchstart' in window || (window.DocumentTouch && document instanceof window.DocumentTouch); 606 607 this.touchX = 0; 608 this.touchY = 0; 609 610 this.tooltip = this.sliderElem.querySelector('.tooltip-main'); 611 this.tooltipInner = this.tooltip.querySelector('.tooltip-inner'); 612 613 this.tooltip_min = this.sliderElem.querySelector('.tooltip-min'); 614 this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner'); 615 616 this.tooltip_max = this.sliderElem.querySelector('.tooltip-max'); 617 this.tooltipInner_max= this.tooltip_max.querySelector('.tooltip-inner'); 618 619 if (SliderScale[this.options.scale]) { 620 this.options.scale = SliderScale[this.options.scale]; 621 } 622 623 if (updateSlider === true) { 624 // Reset classes 625 this._removeClass(this.sliderElem, 'slider-horizontal'); 626 this._removeClass(this.sliderElem, 'slider-vertical'); 627 this._removeClass(this.sliderElem, 'slider-rtl'); 628 this._removeClass(this.tooltip, 'hide'); 629 this._removeClass(this.tooltip_min, 'hide'); 630 this._removeClass(this.tooltip_max, 'hide'); 631 632 // Undo existing inline styles for track 633 ["left", "right", "top", "width", "height"].forEach(function(prop) { 634 this._removeProperty(this.trackLow, prop); 635 this._removeProperty(this.trackSelection, prop); 636 this._removeProperty(this.trackHigh, prop); 637 }, this); 638 639 // Undo inline styles on handles 640 [this.handle1, this.handle2].forEach(function(handle) { 641 this._removeProperty(handle, 'left'); 642 this._removeProperty(handle, 'right'); 643 this._removeProperty(handle, 'top'); 644 }, this); 645 646 // Undo inline styles and classes on tooltips 647 [this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function(tooltip) { 648 this._removeProperty(tooltip, 'left'); 649 this._removeProperty(tooltip, 'right'); 650 this._removeProperty(tooltip, 'top'); 651 this._removeProperty(tooltip, 'margin-left'); 652 this._removeProperty(tooltip, 'margin-right'); 653 this._removeProperty(tooltip, 'margin-top'); 654 655 this._removeClass(tooltip, 'right'); 656 this._removeClass(tooltip, 'left'); 657 this._removeClass(tooltip, 'top'); 658 }, this); 659 } 660 661 if(this.options.orientation === 'vertical') { 662 this._addClass(this.sliderElem,'slider-vertical'); 663 this.stylePos = 'top'; 664 this.mousePos = 'pageY'; 665 this.sizePos = 'offsetHeight'; 666 } else { 667 this._addClass(this.sliderElem, 'slider-horizontal'); 668 this.sliderElem.style.width = origWidth; 669 this.options.orientation = 'horizontal'; 670 if(this.options.rtl) { 671 this.stylePos = 'right'; 672 } else { 673 this.stylePos = 'left'; 674 } 675 this.mousePos = 'pageX'; 676 this.sizePos = 'offsetWidth'; 677 } 678 // specific rtl class 679 if (this.options.rtl) { 680 this._addClass(this.sliderElem, 'slider-rtl'); 681 } 682 this._setTooltipPosition(); 683 /* In case ticks are specified, overwrite the min and max bounds */ 684 if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { 685 this.options.max = Math.max.apply(Math, this.options.ticks); 686 this.options.min = Math.min.apply(Math, this.options.ticks); 687 } 688 689 if (Array.isArray(this.options.value)) { 690 this.options.range = true; 691 this._state.value = this.options.value; 692 } 693 else if (this.options.range) { 694 // User wants a range, but value is not an array 695 this._state.value = [this.options.value, this.options.max]; 696 } 697 else { 698 this._state.value = this.options.value; 699 } 700 701 this.trackLow = sliderTrackLow || this.trackLow; 702 this.trackSelection = sliderTrackSelection || this.trackSelection; 703 this.trackHigh = sliderTrackHigh || this.trackHigh; 704 705 if (this.options.selection === 'none') { 706 this._addClass(this.trackLow, 'hide'); 707 this._addClass(this.trackSelection, 'hide'); 708 this._addClass(this.trackHigh, 'hide'); 709 } 710 711 else if (this.options.selection === 'after' || this.options.selection === 'before') { 712 this._removeClass(this.trackLow, 'hide'); 713 this._removeClass(this.trackSelection, 'hide'); 714 this._removeClass(this.trackHigh, 'hide'); 715 } 716 717 this.handle1 = sliderMinHandle || this.handle1; 718 this.handle2 = sliderMaxHandle || this.handle2; 719 720 if (updateSlider === true) { 721 // Reset classes 722 this._removeClass(this.handle1, 'round triangle'); 723 this._removeClass(this.handle2, 'round triangle hide'); 724 725 for (i = 0; i < this.ticks.length; i++) { 726 this._removeClass(this.ticks[i], 'round triangle hide'); 727 } 728 } 729 730 var availableHandleModifiers = ['round', 'triangle', 'custom']; 731 var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1; 732 if (isValidHandleType) { 733 this._addClass(this.handle1, this.options.handle); 734 this._addClass(this.handle2, this.options.handle); 735 736 for (i = 0; i < this.ticks.length; i++) { 737 this._addClass(this.ticks[i], this.options.handle); 738 } 739 } 740 741 this._state.offset = this._offset(this.sliderElem); 742 this._state.size = this.sliderElem[this.sizePos]; 743 this.setValue(this._state.value); 744 745 /****************************************** 746 747 Bind Event Listeners 748 749 ******************************************/ 750 751 // Bind keyboard handlers 752 this.handle1Keydown = this._keydown.bind(this, 0); 753 this.handle1.addEventListener("keydown", this.handle1Keydown, false); 754 755 this.handle2Keydown = this._keydown.bind(this, 1); 756 this.handle2.addEventListener("keydown", this.handle2Keydown, false); 757 758 this.mousedown = this._mousedown.bind(this); 759 this.touchstart = this._touchstart.bind(this); 760 this.touchmove = this._touchmove.bind(this); 761 762 if (this.touchCapable) { 763 // Test for passive event support 764 let supportsPassive = false;
765 try { 766 let opts = Object.defineProperty({}, 'passive', { 767 get: function() { 768 supportsPassive = true; 769 } 770 }); 771 window.addEventListener("test", null, opts); 772 } catch (e) {} 773 // Use our detect's results. passive applied if supported, capture will be false either way. 774 let eventOptions = supportsPassive ? { passive: true } : false; 775 // Bind touch handlers 776 this.sliderElem.addEventListener("touchstart", this.touchstart, eventOptions); 777 this.sliderElem.addEventListener("touchmove", this.touchmove, eventOptions); 778 } 779 this.sliderElem.addEventListener("mousedown", this.mousedown, false); 780 781 // Bind window handlers 782 this.resize = this._resize.bind(this); 783 window.addEventListener("resize", this.resize, false); 784 785 786 // Bind tooltip-related handlers 787 if(this.options.tooltip === 'hide') { 788 this._addClass(this.tooltip, 'hide'); 789 this._addClass(this.tooltip_min, 'hide'); 790 this._addClass(this.tooltip_max, 'hide'); 791 } 792 else if(this.options.tooltip === 'always') { 793 this._showTooltip(); 794 this._alwaysShowTooltip = true; 795 } 796 else { 797 this.showTooltip = this._showTooltip.bind(this); 798 this.hideTooltip = this._hideTooltip.bind(this); 799 800 if (this.options.ticks_tooltip) { 801 var callbackHandle = this._addTickListener(); 802 //create handle1 listeners and store references in map 803 var mouseEnter = callbackHandle.addMouseEnter(this, this.handle1); 804 var mouseLeave = callbackHandle.addMouseLeave(this, this.handle1); 805 this.handleCallbackMap.handle1 = { 806 mouseEnter: mouseEnter, 807 mouseLeave: mouseLeave 808 }; 809 //create handle2 listeners and store references in map 810 mouseEnter = callbackHandle.addMouseEnter(this, this.handle2); 811 mouseLeave = callbackHandle.addMouseLeave(this, this.handle2); 812 this.handleCallbackMap.handle2 = { 813 mouseEnter: mouseEnter, 814 mouseLeave: mouseLeave 815 }; 816 } else { 817 this.sliderElem.addEventListener("mouseenter", this.showTooltip, false); 818 this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false); 819 } 820 821 this.handle1.addEventListener("focus", this.showTooltip, false); 822 this.handle1.addEventListener("blur", this.hideTooltip, false); 823 824 this.handle2.addEventListener("focus", this.showTooltip, false); 825 this.handle2.addEventListener("blur", this.hideTooltip, false); 826 } 827 828 if(this.options.enabled) { 829 this.enable(); 830 } else { 831 this.disable(); 832 } 833 834 } 835 836 /************************************************* 837 838 INSTANCE PROPERTIES/METHODS 839 840 - Any methods bound to the prototype are considered 841 part of the plugin's `public` interface 842 843 **************************************************/ 844 Slider.prototype = { 845 _init: function() {}, // NOTE: Must exist to support bridget 846 847 constructor: Slider, 848 849 defaultOptions: { 850 id: "", 851 min: 0, 852 max: 10, 853 step: 1, 854 precision: 0, 855 orientation: 'horizontal', 856 value: 5, 857 range: false, 858 selection: 'before', 859 tooltip: 'show', 860 tooltip_split: false, 861 handle: 'round', 862 reversed: false, 863 rtl: 'auto', 864 enabled: true, 865 formatter: function(val) { 866 if (Array.isArray(val)) { 867 return val[0] + " : " + val[1]; 868 } else { 869 return val; 870 } 871 }, 872 natural_arrow_keys: false, 873 ticks: [], 874 ticks_positions: [], 875 ticks_labels: [], 876 ticks_snap_bounds: 0, 877 ticks_tooltip: false, 878 scale: 'linear', 879 focus: false, 880 tooltip_position: null, 881 labelledby: null, 882 rangeHighlights: [] 883 }, 884 885 getElement: function() { 886 return this.sliderElem; 887 }, 888 889 getValue: function() { 890 if (this.options.range) { 891 return this._state.value; 892 } 893 else { 894 return this._state.value[0]; 895 } 896 }, 897 898 setValue: function(val, triggerSlideEvent, triggerChangeEvent) { 899 if (!val) { 900 val = 0; 901 } 902 var oldValue = this.getValue(); 903 this._state.value = this._validateInputValue(val); 904 var applyPrecision = this._applyPrecision.bind(this); 905 906 if (this.options.range) { 907 this._state.value[0] = applyPrecision(this._state.value[0]); 908 this._state.value[1] = applyPrecision(this._state.value[1]); 909 910 this._state.value[0] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[0])); 911 this._state.value[1] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[1])); 912 } 913 else { 914 this._state.value = applyPrecision(this._state.value); 915 this._state.value = [ Math.max(this.options.min, Math.min(this.options.max, this._state.value))]; 916 this._addClass(this.handle2, 'hide'); 917 if (this.options.selection === 'after') { 918 this._state.value[1] = this.options.max; 919 } else { 920 this._state.value[1] = this.options.min; 921 } 922 } 923 924 if (this.options.max > this.options.min) { 925 this._state.percentage = [ 926 this._toPercentage(this._state.value[0]), 927 this._toPercentage(this._state.value[1]), 928 this.options.step * 100 / (this.options.max - this.options.min) 929 ]; 930 } else { 931 this._state.percentage = [0, 0, 100]; 932 } 933 934 this._layout(); 935 var newValue = this.options.range ? this._state.value : this._state.value[0]; 936 937 this._setDataVal(newValue); 938 if(triggerSlideEvent === true) { 939 this._trigger('slide', newValue); 940 } 941 if( (oldValue !== newValue) && (triggerChangeEvent === true) ) { 942 this._trigger('change', { 943 oldValue: oldValue, 944 newValue: newValue 945 }); 946 } 947 948 return this; 949 }, 950 951 destroy: function(){ 952 // Remove event handlers on slider elements 953 this._removeSliderEventHandlers(); 954 955 // Remove the slider from the DOM 956 this.sliderElem.parentNode.removeChild(this.sliderElem); 957 /* Show original <input> element */ 958 this.element.style.display = ""; 959 960 // Clear out custom event bindings 961 this._cleanUpEventCallbacksMap(); 962 963 // Remove data values 964 this.element.removeAttribute("data"); 965 966 // Remove JQuery handlers/data 967 if($) { 968 this._unbindJQueryEventHandlers(); 969 this.$element.removeData('slider'); 970 } 971 }, 972 973 disable: function() { 974 this._state.enabled = false;
975 this.handle1.removeAttribute("tabindex"); 976 this.handle2.removeAttribute("tabindex"); 977 this._addClass(this.sliderElem, 'slider-disabled'); 978 this._trigger('slideDisabled'); 979 980 return this; 981 }, 982 983 enable: function() { 984 this._state.enabled = true; 985 this.handle1.setAttribute("tabindex", 0); 986 this.handle2.setAttribute("tabindex", 0); 987 this._removeClass(this.sliderElem, 'slider-disabled'); 988 this._trigger('slideEnabled'); 989 990 return this; 991 }, 992 993 toggle: function() { 994 if(this._state.enabled) { 995 this.disable(); 996 } else { 997 this.enable(); 998 } 999 return this; 1000 }, 1001 1002 isEnabled: function() { 1003 return this._state.enabled; 1004 }, 1005 1006 on: function(evt, callback) { 1007 this._bindNonQueryEventHandler(evt, callback); 1008 return this; 1009 }, 1010 1011 off: function(evt, callback) { 1012 if($) { 1013 this.$element.off(evt, callback); 1014 this.$sliderElem.off(evt, callback); 1015 } else { 1016 this._unbindNonQueryEventHandler(evt, callback); 1017 } 1018 }, 1019 1020 getAttribute: function(attribute) { 1021 if(attribute) { 1022 return this.options[attribute]; 1023 } else { 1024 return this.options; 1025 } 1026 }, 1027 1028 setAttribute: function(attribute, value) { 1029 this.options[attribute] = value; 1030 return this; 1031 }, 1032 1033 refresh: function() { 1034 this._removeSliderEventHandlers(); 1035 createNewSlider.call(this, this.element, this.options); 1036 if($) { 1037 // Bind new instance of slider to the element 1038 $.data(this.element, 'slider', this); 1039 } 1040 return this; 1041 }, 1042 1043 relayout: function() { 1044 this._resize(); 1045 this._layout(); 1046 return this; 1047 }, 1048 1049 /******************************+ 1050 1051 HELPERS 1052 1053 - Any method that is not part of the public interface. 1054 - Place it underneath this comment block and write its signature like so: 1055 1056 _fnName : function() {...} 1057 1058 ********************************/ 1059 _removeSliderEventHandlers: function() { 1060 // Remove keydown event listeners 1061 this.handle1.removeEventListener("keydown", this.handle1Keydown, false); 1062 this.handle2.removeEventListener("keydown", this.handle2Keydown, false); 1063 1064 //remove the listeners from the ticks and handles if they had their own listeners 1065 if (this.options.ticks_tooltip) { 1066 var ticks = this.ticksContainer.getElementsByClassName('slider-tick'); 1067 for(var i = 0; i < ticks.length; i++ ){ 1068 ticks[i].removeEventListener('mouseenter', this.ticksCallbackMap[i].mouseEnter, false); 1069 ticks[i].removeEventListener('mouseleave', this.ticksCallbackMap[i].mouseLeave, false); 1070 } 1071 this.handle1.removeEventListener('mouseenter', this.handleCallbackMap.handle1.mouseEnter, false); 1072 this.handle2.removeEventListener('mouseenter', this.handleCallbackMap.handle2.mouseEnter, false); 1073 this.handle1.removeEventListener('mouseleave', this.handleCallbackMap.handle1.mouseLeave, false); 1074 this.handle2.removeEventListener('mouseleave', this.handleCallbackMap.handle2.mouseLeave, false); 1075 } 1076 1077 this.handleCallbackMap = null; 1078 this.ticksCallbackMap = null; 1079 1080 if (this.showTooltip) { 1081 this.handle1.removeEventListener("focus", this.showTooltip, false); 1082 this.handle2.removeEventListener("focus", this.showTooltip, false); 1083 } 1084 if (this.hideTooltip) { 1085 this.handle1.removeEventListener("blur", this.hideTooltip, false); 1086 this.handle2.removeEventListener("blur", this.hideTooltip, false); 1087 } 1088 1089 // Remove event listeners from sliderElem 1090 if (this.showTooltip) { 1091 this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false); 1092 } 1093 if (this.hideTooltip) { 1094 this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false); 1095 } 1096 this.sliderElem.removeEventListener("touchstart", this.touchstart, false); 1097 this.sliderElem.removeEventListener("touchmove", this.touchmove, false); 1098 this.sliderElem.removeEventListener("mousedown", this.mousedown, false); 1099 1100 // Remove window event listener 1101 window.removeEventListener("resize", this.resize, false); 1102 }, 1103 _bindNonQueryEventHandler: function(evt, callback) { 1104 if(this.eventToCallbackMap[evt] === undefined) { 1105 this.eventToCallbackMap[evt] = []; 1106 } 1107 this.eventToCallbackMap[evt].push(callback); 1108 }, 1109 _unbindNonQueryEventHandler: function(evt, callback) { 1110 var callbacks = this.eventToCallbackMap[evt]; 1111 if(callbacks !== undefined) { 1112 for (var i = 0; i < callbacks.length; i++) { 1113 if (callbacks[i] === callback) { 1114 callbacks.splice(i, 1); 1115 break; 1116 } 1117 } 1118 } 1119 }, 1120 _cleanUpEventCallbacksMap: function() { 1121 var eventNames = Object.keys(this.eventToCallbackMap); 1122 for(var i = 0; i < eventNames.length; i++) { 1123 var eventName = eventNames[i]; 1124 delete this.eventToCallbackMap[eventName]; 1125 } 1126 }, 1127 _showTooltip: function() { 1128 if (this.options.tooltip_split === false ){ 1129 this._addClass(this.tooltip, 'in'); 1130 this.tooltip_min.style.display = 'none'; 1131 this.tooltip_max.style.display = 'none'; 1132 } else { 1133 this._addClass(this.tooltip_min, 'in'); 1134 this._addClass(this.tooltip_max, 'in'); 1135 this.tooltip.style.display = 'none'; 1136 } 1137 this._state.over = true; 1138 }, 1139 _hideTooltip: function() { 1140 if (this._state.inDrag === false && this.alwaysShowTooltip !== true) { 1141 this._removeClass(this.tooltip, 'in'); 1142 this._removeClass(this.tooltip_min, 'in'); 1143 this._removeClass(this.tooltip_max, 'in'); 1144 } 1145 this._state.over = false;
1146 }, 1147 _setToolTipOnMouseOver: function _setToolTipOnMouseOver(tempState){ 1148 var formattedTooltipVal = this.options.formatter(!tempState ? this._state.value[0]: tempState.value[0]); 1149 var positionPercentages = !tempState ? getPositionPercentages(this._state, this.options.reversed) : getPositionPercentages(tempState, this.options.reversed); 1150 this._setText(this.tooltipInner, formattedTooltipVal); 1151 1152 this.tooltip.style[this.stylePos] = `${positionPercentages[0]}%`; 1153 if (this.options.orientation === 'vertical') { 1154 this._css(this.tooltip, `margin-${this.stylePos}`, `${-this.tooltip.offsetHeight / 2}px`); 1155 } else { 1156 this._css(this.tooltip, `margin-${this.stylePos}`, `${-this.tooltip.offsetWidth / 2}px`); 1157 } 1158 1159 function getPositionPercentages(state, reversed){ 1160 if (reversed) { 1161 return [100 - state.percentage[0], this.options.range ? 100 - state.percentage[1] : state.percentage[1]]; 1162 } 1163 return [state.percentage[0], state.percentage[1]]; 1164 } 1165 }, 1166 _addTickListener: function _addTickListener() { 1167 return { 1168 addMouseEnter: function(reference, tick, index){ 1169 var enter = function(){ 1170 var tempState = reference._state; 1171 var idString = index >= 0 ? index : this.attributes['aria-valuenow'].value; 1172 var hoverIndex = parseInt(idString, 10); 1173 tempState.value[0] = hoverIndex; 1174 tempState.percentage[0] = reference.options.ticks_positions[hoverIndex]; 1175 reference._setToolTipOnMouseOver(tempState); 1176 reference._showTooltip(); 1177 }; 1178 tick.addEventListener("mouseenter", enter, false); 1179 return enter; 1180 }, 1181 addMouseLeave: function(reference, tick){ 1182 var leave = function(){ 1183 reference._hideTooltip(); 1184 }; 1185 tick.addEventListener("mouseleave", leave, false); 1186 return leave; 1187 } 1188 }; 1189 }, 1190 _layout: function() { 1191 var positionPercentages; 1192 1193 if(this.options.reversed) { 1194 positionPercentages = [ 100 - this._state.percentage[0], this.options.range ? 100 - this._state.percentage[1] : this._state.percentage[1]]; 1195 } 1196 else { 1197 positionPercentages = [ this._state.percentage[0], this._state.percentage[1] ]; 1198 } 1199 1200 this.handle1.style[this.stylePos] = `${positionPercentages[0]}%`; 1201 this.handle1.setAttribute('aria-valuenow', this._state.value[0]); 1202 if (isNaN(this.options.formatter(this._state.value[0])) ) { 1203 this.handle1.setAttribute('aria-valuetext', this.options.formatter(this._state.value[0])); 1204 } 1205 1206 this.handle2.style[this.stylePos] =`${positionPercentages[1]}%`; 1207 this.handle2.setAttribute('aria-valuenow', this._state.value[1]); 1208 if (isNaN(this.options.formatter(this._state.value[1])) ) { 1209 this.handle2.setAttribute('aria-valuetext', this.options.formatter(this._state.value[1])); 1210 } 1211 1212 /* Position highlight range elements */ 1213 if (this.rangeHighlightElements.length > 0 && Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) { 1214 for (let i = 0; i < this.options.rangeHighlights.length; i++) { 1215 var startPercent = this._toPercentage(this.options.rangeHighlights[i].start); 1216 var endPercent = this._toPercentage(this.options.rangeHighlights[i].end); 1217 1218 if (this.options.reversed) { 1219 var sp = 100-endPercent; 1220 endPercent = 100-startPercent; 1221 startPercent = sp; 1222 } 1223 1224 var currentRange = this._createHighlightRange(startPercent, endPercent); 1225 1226 if (currentRange) { 1227 if (this.options.orientation === 'vertical') { 1228 this.rangeHighlightElements[i].style.top = `${currentRange.start}%`; 1229 this.rangeHighlightElements[i].style.height = `${currentRange.size}%`; 1230 } else { 1231 if(this.options.rtl){ 1232 this.rangeHighlightElements[i].style.right = `${currentRange.start}%`; 1233 } else { 1234 this.rangeHighlightElements[i].style.left = `${currentRange.start}%`; 1235 } 1236 this.rangeHighlightElements[i].style.width = `${currentRange.size}%`; 1237 } 1238 } else { 1239 this.rangeHighlightElements[i].style.display = "none"; 1240 } 1241 } 1242 } 1243 1244 /* Position ticks and labels */ 1245 if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { 1246 1247 var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width'; 1248 var styleMargin; 1249 if( this.options.orientation === 'vertical' ){ 1250 styleMargin='marginTop'; 1251 }else { 1252 if( this.options.rtl ){ 1253 styleMargin='marginRight'; 1254 } else { 1255 styleMargin='marginLeft'; 1256 } 1257 } 1258 var labelSize = this._state.size / (this.options.ticks.length - 1); 1259 1260 if (this.tickLabelContainer) { 1261 var extraMargin = 0; 1262 if (this.options.ticks_positions.length === 0) { 1263 if (this.options.orientation !== 'vertical') { 1264 this.tickLabelContainer.style[styleMargin] = `${ -labelSize/2 }px`; 1265 } 1266 1267 extraMargin = this.tickLabelContainer.offsetHeight; 1268 } else { 1269 /* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */ 1270 for (i = 0 ; i < this.tickLabelContainer.childNodes.length; i++) { 1271 if (this.tickLabelContainer.childNodes[i].offsetHeight > extraMargin) { 1272 extraMargin = this.tickLabelContainer.childNodes[i].offsetHeight; 1273 } 1274 } 1275 } 1276 if (this.options.orientation === 'horizontal') { 1277 this.sliderElem.style.marginBottom = `${ extraMargin }px`; 1278 } 1279 } 1280 for (var i = 0; i < this.options.ticks.length; i++) { 1281 1282 var percentage = this.options.ticks_positions[i] || this._toPercentage(this.options.ticks[i]); 1283 1284 if (this.options.reversed) { 1285 percentage = 100 - percentage; 1286 } 1287 1288 this.ticks[i].style[this.stylePos] = `${ percentage }%`; 1289 1290 /* Set class labels to denote whether ticks are in the selection */ 1291 this._removeClass(this.ticks[i], 'in-selection'); 1292 if (!this.options.range) { 1293 if (this.options.selection === 'after' && percentage >= positionPercentages[0]){ 1294 this._addClass(this.ticks[i], 'in-selection'); 1295 } else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) { 1296 this._addClass(this.ticks[i], 'in-selection'); 1297 } 1298 } else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) { 1299 this._addClass(this.ticks[i], 'in-selection'); 1300 } 1301 1302 if (this.tickLabels[i]) { 1303 this.tickLabels[i].style[styleSize] = `${labelSize}px`; 1304 1305 if (this.options.orientation !== 'vertical' && this.options.ticks_positions[i] !== undefined) { 1306 this.tickLabels[i].style.position = 'absolute'; 1307 this.tickLabels[i].style[this.stylePos] = `${percentage}%`; 1308 this.tickLabels[i].style[styleMargin] = -labelSize/2 + 'px'; 1309 } else if (this.options.orientation === 'vertical') { 1310 if(this.options.rtl){ 1311 this.tickLabels[i].style['marginRight'] = `${this.sliderElem.offsetWidth }px`; 1312 }else{ 1313 this.tickLabels[i].style['marginLeft'] = `${this.sliderElem.offsetWidth }px`; 1314 } 1315 this.tickLabelContainer.style[styleMargin] = this.sliderElem.offsetWidth / 2 * -1 + 'px'; 1316 } 1317 } 1318 } 1319 } 1320 1321 var formattedTooltipVal; 1322 1323 if (this.options.range) { 1324 formattedTooltipVal = this.options.formatter(this._state.value); 1325 this._setText(this.tooltipInner, formattedTooltipVal); 1326 this.tooltip.style[this.stylePos] = `${ (positionPercentages[1] + positionPercentages[0])/2 }%`; 1327 1328 if (this.options.orientation === 'vertical') { 1329 this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetHeight / 2 }px`); 1330 } else { 1331 this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetWidth / 2 }px`); 1332 } 1333 1334 var innerTooltipMinText = this.options.formatter(this._state.value[0]); 1335 this._setText(this.tooltipInner_min, innerTooltipMinText); 1336 1337 var innerTooltipMaxText = this.options.formatter(this._state.value[1]); 1338 this._setText(this.tooltipInner_max, innerTooltipMaxText); 1339 1340 this.tooltip_min.style[this.stylePos] = `${ positionPercentages[0] }%`; 1341 1342 if (this.options.orientation === 'vertical') { 1343 this._css(this.tooltip_min, `margin-${this.stylePos}`, `${ -this.tooltip_min.offsetHeight / 2 }px`); 1344 } else { 1345 this._css(this.tooltip_min, `margin-${this.stylePos}`, `${ -this.tooltip_min.offsetWidth / 2 }px`); 1346 } 1347 1348 this.tooltip_max.style[this.stylePos] = `${ positionPercentages[1] }%`; 1349 1350 if (this.options.orientation === 'vertical') { 1351 this._css(this.tooltip_max, `margin-${this.stylePos}`, `${ -this.tooltip_max.offsetHeight / 2 }px`); 1352 } else { 1353 this._css(this.tooltip_max, `margin-${this.stylePos}`, `${ -this.tooltip_max.offsetWidth / 2 }px`); 1354 } 1355 } else { 1356 formattedTooltipVal = this.options.formatter(this._state.value[0]); 1357 this._setText(this.tooltipInner, formattedTooltipVal); 1358 1359 this.tooltip.style[this.stylePos] = `${ positionPercentages[0] }%`; 1360 if (this.options.orientation === 'vertical') { 1361 this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetHeight / 2 }px`); 1362 } else { 1363 this._css(this.tooltip, `margin-${this.stylePos}`, `${ -this.tooltip.offsetWidth / 2 }px`); 1364 } 1365 } 1366 1367 if (this.options.orientation === 'vertical') { 1368 this.trackLow.style.top = '0'; 1369 this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) +'%'; 1370 1371 this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%'; 1372 this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%'; 1373 1374 this.trackHigh.style.bottom = '0'; 1375 this.trackHigh.style.height = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%'; 1376 } 1377 else { 1378 if(this.stylePos==='right') { 1379 this.trackLow.style.right = '0'; 1380 } else { 1381 this.trackLow.style.left = '0'; 1382 } 1383 this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) +'%'; 1384 1385 if(this.stylePos==='right') { 1386 this.trackSelection.style.right = Math.min(positionPercentages[0], positionPercentages[1]) + '%'; 1387 } else { 1388 this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) + '%'; 1389 } 1390 this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%'; 1391 1392 if(this.stylePos==='right') { 1393 this.trackHigh.style.left = '0'; 1394 } else { 1395 this.trackHigh.style.right = '0'; 1396 } 1397 this.trackHigh.style.width = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%'; 1398 1399 var offset_min = this.tooltip_min.getBoundingClientRect(); 1400 var offset_max = this.tooltip_max.getBoundingClientRect(); 1401 1402 if (this.options.tooltip_position === 'bottom') { 1403 if (offset_min.right > offset_max.left) { 1404 this._removeClass(this.tooltip_max, 'bottom'); 1405 this._addClass(this.tooltip_max, 'top'); 1406 this.tooltip_max.style.top = ''; 1407 this.tooltip_max.style.bottom = 22 + 'px'; 1408 } else { 1409 this._removeClass(this.tooltip_max, 'top'); 1410 this._addClass(this.tooltip_max, 'bottom'); 1411 this.tooltip_max.style.top = this.tooltip_min.style.top; 1412 this.tooltip_max.style.bottom = ''; 1413 } 1414 } else { 1415 if (offset_min.right > offset_max.left) { 1416 this._removeClass(this.tooltip_max, 'top'); 1417 this._addClass(this.tooltip_max, 'bottom'); 1418 this.tooltip_max.style.top = 18 + 'px'; 1419 } else { 1420 this._removeClass(this.tooltip_max, 'bottom'); 1421 this._addClass(this.tooltip_max, 'top'); 1422 this.tooltip_max.style.top = this.tooltip_min.style.top; 1423 } 1424 } 1425 } 1426 }, 1427 _createHighlightRange: function (start, end) { 1428 if (this._isHighlightRange(start, end)) { 1429 if (start > end) { 1430 return {'start': end, 'size': start - end}; 1431 } 1432 return {'start': start, 'size': end - start}; 1433 } 1434 return null; 1435 }, 1436 _isHighlightRange: function (start, end) { 1437 if (0 <= start && start <= 100 && 0 <= end && end <= 100) { 1438 return true; 1439 } 1440 else { 1441 return false;
1442 } 1443 }, 1444 _resize: function (ev) { 1445 /*jshint unused:false*/ 1446 this._state.offset = this._offset(this.sliderElem); 1447 this._state.size = this.sliderElem[this.sizePos]; 1448 this._layout(); 1449 }, 1450 _removeProperty: function(element, prop) { 1451 if (element.style.removeProperty) { 1452 element.style.removeProperty(prop); 1453 } else { 1454 element.style.removeAttribute(prop); 1455 } 1456 }, 1457 _mousedown: function(ev) { 1458 if(!this._state.enabled) { 1459 return false; 1460 } 1461 1462 this._state.offset = this._offset(this.sliderElem); 1463 this._state.size = this.sliderElem[this.sizePos]; 1464 1465 var percentage = this._getPercentage(ev); 1466 1467 if (this.options.range) { 1468 var diff1 = Math.abs(this._state.percentage[0] - percentage); 1469 var diff2 = Math.abs(this._state.percentage[1] - percentage); 1470 this._state.dragged = (diff1 < diff2) ? 0 : 1; 1471 this._adjustPercentageForRangeSliders(percentage); 1472 } else { 1473 this._state.dragged = 0; 1474 } 1475 1476 this._state.percentage[this._state.dragged] = percentage; 1477 this._layout(); 1478 1479 if (this.touchCapable) { 1480 document.removeEventListener("touchmove", this.mousemove, false); 1481 document.removeEventListener("touchend", this.mouseup, false); 1482 } 1483 1484 if(this.mousemove){ 1485 document.removeEventListener("mousemove", this.mousemove, false); 1486 } 1487 if(this.mouseup){ 1488 document.removeEventListener("mouseup", this.mouseup, false); 1489 } 1490 1491 this.mousemove = this._mousemove.bind(this); 1492 this.mouseup = this._mouseup.bind(this); 1493 1494 if (this.touchCapable) { 1495 // Touch: Bind touch events: 1496 document.addEventListener("touchmove", this.mousemove, false); 1497 document.addEventListener("touchend", this.mouseup, false); 1498 } 1499 // Bind mouse events: 1500 document.addEventListener("mousemove", this.mousemove, false); 1501 document.addEventListener("mouseup", this.mouseup, false); 1502 1503 this._state.inDrag = true; 1504 var newValue = this._calculateValue(); 1505 1506 this._trigger('slideStart', newValue); 1507 1508 this._setDataVal(newValue); 1509 this.setValue(newValue, false, true); 1510 1511 ev.returnValue = false; 1512 1513 if (this.options.focus) { 1514 this._triggerFocusOnHandle(this._state.dragged); 1515 } 1516 1517 return true; 1518 }, 1519 _touchstart: function(ev) { 1520 if (ev.changedTouches === undefined) { 1521 this._mousedown(ev); 1522 return; 1523 } 1524 1525 var touch = ev.changedTouches[0]; 1526 this.touchX = touch.pageX; 1527 this.touchY = touch.pageY; 1528 }, 1529 _triggerFocusOnHandle: function(handleIdx) { 1530 if(handleIdx === 0) { 1531 this.handle1.focus(); 1532 } 1533 if(handleIdx === 1) { 1534 this.handle2.focus(); 1535 } 1536 }, 1537 _keydown: function(handleIdx, ev) { 1538 if(!this._state.enabled) { 1539 return false; 1540 } 1541 1542 var dir; 1543 switch (ev.keyCode) { 1544 case 37: // left 1545 case 40: // down 1546 dir = -1; 1547 break; 1548 case 39: // right 1549 case 38: // up 1550 dir = 1; 1551 break; 1552 } 1553 if (!dir) { 1554 return; 1555 } 1556 1557 // use natural arrow keys instead of from min to max 1558 if (this.options.natural_arrow_keys) { 1559 var ifVerticalAndNotReversed = (this.options.orientation === 'vertical' && !this.options.reversed); 1560 var ifHorizontalAndReversed = (this.options.orientation === 'horizontal' && this.options.reversed); // @todo control with rtl 1561 1562 if (ifVerticalAndNotReversed || ifHorizontalAndReversed) { 1563 dir = -dir; 1564 } 1565 } 1566 1567 var val = this._state.value[handleIdx] + dir * this.options.step; 1568 const percentage = (val / this.options.max) * 100; 1569 this._state.keyCtrl = handleIdx; 1570 if (this.options.range) { 1571 this._adjustPercentageForRangeSliders(percentage); 1572 const val1 = (!this._state.keyCtrl) ? val : this._state.value[0]; 1573 const val2 = (this._state.keyCtrl) ? val : this._state.value[1]; 1574 val = [ val1, val2]; 1575 } 1576 1577 this._trigger('slideStart', val); 1578 this._setDataVal(val); 1579 this.setValue(val, true, true); 1580 1581 this._setDataVal(val); 1582 this._trigger('slideStop', val); 1583 this._layout(); 1584 1585 this._pauseEvent(ev); 1586 delete this._state.keyCtrl; 1587 1588 return false; 1589 }, 1590 _pauseEvent: function(ev) { 1591 if(ev.stopPropagation) { 1592 ev.stopPropagation(); 1593 } 1594 if(ev.preventDefault) { 1595 ev.preventDefault(); 1596 } 1597 ev.cancelBubble=true; 1598 ev.returnValue=false; 1599 }, 1600 _mousemove: function(ev) { 1601 if(!this._state.enabled) { 1602 return false;
1603 } 1604 1605 var percentage = this._getPercentage(ev); 1606 this._adjustPercentageForRangeSliders(percentage); 1607 this._state.percentage[this._state.dragged] = percentage; 1608 this._layout(); 1609 1610 var val = this._calculateValue(true); 1611 this.setValue(val, true, true); 1612 1613 return false; 1614 }, 1615 _touchmove: function(ev) { 1616 if (ev.changedTouches === undefined) { 1617 return; 1618 } 1619 1620 var touch = ev.changedTouches[0]; 1621 1622 var xDiff = touch.pageX - this.touchX; 1623 var yDiff = touch.pageY - this.touchY; 1624 1625 if (!this._state.inDrag) { 1626 // Vertical Slider 1627 if (this.options.orientation === 'vertical' && (xDiff <= 5 && xDiff >= -5) && (yDiff >=15 || yDiff <= -15)) { 1628 this._mousedown(ev); 1629 } 1630 // Horizontal slider. 1631 else if ((yDiff <= 5 && yDiff >= -5) && (xDiff >= 15 || xDiff <= -15)) { 1632 this._mousedown(ev); 1633 } 1634 } 1635 }, 1636 _adjustPercentageForRangeSliders: function(percentage) { 1637 if (this.options.range) { 1638 var precision = this._getNumDigitsAfterDecimalPlace(percentage); 1639 precision = precision ? precision - 1 : 0; 1640 var percentageWithAdjustedPrecision = this._applyToFixedAndParseFloat(percentage, precision); 1641 if (this._state.dragged === 0 && this._applyToFixedAndParseFloat(this._state.percentage[1], precision) < percentageWithAdjustedPrecision) { 1642 this._state.percentage[0] = this._state.percentage[1]; 1643 this._state.dragged = 1; 1644 } else if (this._state.dragged === 1 && this._applyToFixedAndParseFloat(this._state.percentage[0], precision) > percentageWithAdjustedPrecision) { 1645 this._state.percentage[1] = this._state.percentage[0]; 1646 this._state.dragged = 0; 1647 } 1648 else if (this._state.keyCtrl === 0 && (((this._state.value[1] / this.options.max) * 100) < percentage)) { 1649 this._state.percentage[0] = this._state.percentage[1]; 1650 this._state.keyCtrl = 1; 1651 this.handle2.focus(); 1652 } 1653 else if (this._state.keyCtrl === 1 && (((this._state.value[0] / this.options.max) * 100) > percentage)) { 1654 this._state.percentage[1] = this._state.percentage[0]; 1655 this._state.keyCtrl = 0; 1656 this.handle1.focus(); 1657 } 1658 } 1659 }, 1660 _mouseup: function() { 1661 if(!this._state.enabled) { 1662 return false; 1663 } 1664 if (this.touchCapable) { 1665 // Touch: Unbind touch event handlers: 1666 document.removeEventListener("touchmove", this.mousemove, false); 1667 document.removeEventListener("touchend", this.mouseup, false); 1668 } 1669 // Unbind mouse event handlers: 1670 document.removeEventListener("mousemove", this.mousemove, false); 1671 document.removeEventListener("mouseup", this.mouseup, false); 1672 1673 this._state.inDrag = false; 1674 if (this._state.over === false) { 1675 this._hideTooltip(); 1676 } 1677 var val = this._calculateValue(true); 1678 1679 this._layout(); 1680 this._setDataVal(val); 1681 this._trigger('slideStop', val); 1682 1683 return false; 1684 }, 1685 _calculateValue: function(snapToClosestTick) { 1686 var val; 1687 if (this.options.range) { 1688 val = [this.options.min,this.options.max]; 1689 if (this._state.percentage[0] !== 0){ 1690 val[0] = this._toValue(this._state.percentage[0]); 1691 val[0] = this._applyPrecision(val[0]); 1692 } 1693 if (this._state.percentage[1] !== 100){ 1694 val[1] = this._toValue(this._state.percentage[1]); 1695 val[1] = this._applyPrecision(val[1]); 1696 } 1697 } else { 1698 val = this._toValue(this._state.percentage[0]); 1699 val = parseFloat(val); 1700 val = this._applyPrecision(val); 1701 } 1702 1703 if (snapToClosestTick) { 1704 var min = [val, Infinity]; 1705 for (var i = 0; i < this.options.ticks.length; i++) { 1706 var diff = Math.abs(this.options.ticks[i] - val); 1707 if (diff <= min[1]) { 1708 min = [this.options.ticks[i], diff]; 1709 } 1710 } 1711 if (min[1] <= this.options.ticks_snap_bounds) { 1712 return min[0]; 1713 } 1714 } 1715 1716 return val; 1717 }, 1718 _applyPrecision: function(val) { 1719 var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step); 1720 return this._applyToFixedAndParseFloat(val, precision); 1721 }, 1722 _getNumDigitsAfterDecimalPlace: function(num) { 1723 var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); 1724 if (!match) { return 0; } 1725 return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0)); 1726 }, 1727 _applyToFixedAndParseFloat: function(num, toFixedInput) { 1728 var truncatedNum = num.toFixed(toFixedInput); 1729 return parseFloat(truncatedNum); 1730 }, 1731 /* 1732 Credits to Mike Samuel for the following method! 1733 Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number 1734 */ 1735 _getPercentage: function(ev) { 1736 if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) { 1737 ev = ev.touches[0]; 1738 } 1739 1740 var eventPosition = ev[this.mousePos]; 1741 var sliderOffset = this._state.offset[this.stylePos]; 1742 var distanceToSlide = eventPosition - sliderOffset; 1743 if(this.stylePos==='right') { 1744 distanceToSlide = -distanceToSlide; 1745 } 1746 // Calculate what percent of the length the slider handle has slid 1747 var percentage = (distanceToSlide / this._state.size) * 100; 1748 percentage = Math.round(percentage / this._state.percentage[2]) * this._state.percentage[2]; 1749 if (this.options.reversed) { 1750 percentage = 100 - percentage; 1751 } 1752 1753 // Make sure the percent is within the bounds of the slider. 1754 // 0% corresponds to the 'min' value of the slide 1755 // 100% corresponds to the 'max' value of the slide 1756 return Math.max(0, Math.min(100, percentage)); 1757 }, 1758 _validateInputValue: function(val) { 1759 if (!isNaN(+val)) { 1760 return +val; 1761 } else if (Array.isArray(val)) {
1762 this._validateArray(val); 1763 return val; 1764 } else { 1765 throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(val)); 1766 } 1767 }, 1768 _validateArray: function(val) { 1769 for(var i = 0; i < val.length; i++) { 1770 var input = val[i]; 1771 if (typeof input !== 'number') { throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(input) ); } 1772 } 1773 }, 1774 _setDataVal: function(val) { 1775 this.element.setAttribute('data-value', val); 1776 this.element.setAttribute('value', val); 1777 this.element.value = val; 1778 }, 1779 _trigger: function(evt, val) { 1780 val = (val || val === 0) ? val : undefined; 1781 1782 var callbackFnArray = this.eventToCallbackMap[evt]; 1783 if(callbackFnArray && callbackFnArray.length) { 1784 for(var i = 0; i < callbackFnArray.length; i++) { 1785 var callbackFn = callbackFnArray[i]; 1786 callbackFn(val); 1787 } 1788 } 1789 1790 /* If JQuery exists, trigger JQuery events */ 1791 if($) { 1792 this._triggerJQueryEvent(evt, val); 1793 } 1794 }, 1795 _triggerJQueryEvent: function(evt, val) { 1796 var eventData = { 1797 type: evt, 1798 value: val 1799 }; 1800 this.$element.trigger(eventData); 1801 this.$sliderElem.trigger(eventData); 1802 }, 1803 _unbindJQueryEventHandlers: function() { 1804 this.$element.off(); 1805 this.$sliderElem.off(); 1806 }, 1807 _setText: function(element, text) { 1808 if(typeof element.textContent !== "undefined") { 1809 element.textContent = text; 1810 } else if(typeof element.innerText !== "undefined") { 1811 element.innerText = text; 1812 } 1813 }, 1814 _removeClass: function(element, classString) { 1815 var classes = classString.split(" "); 1816 var newClasses = element.className; 1817 1818 for(var i = 0; i < classes.length; i++) { 1819 var classTag = classes[i]; 1820 var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)"); 1821 newClasses = newClasses.replace(regex, " "); 1822 } 1823 1824 element.className = newClasses.trim(); 1825 }, 1826 _addClass: function(element, classString) { 1827 var classes = classString.split(" "); 1828 var newClasses = element.className; 1829 1830 for(var i = 0; i < classes.length; i++) { 1831 var classTag = classes[i]; 1832 var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)"); 1833 var ifClassExists = regex.test(newClasses); 1834 1835 if(!ifClassExists) { 1836 newClasses += " " + classTag; 1837 } 1838 } 1839 1840 element.className = newClasses.trim(); 1841 }, 1842 _offsetLeft: function(obj){ 1843 return obj.getBoundingClientRect().left; 1844 }, 1845 _offsetRight: function(obj){ 1846 return obj.getBoundingClientRect().right; 1847 }, 1848 _offsetTop: function(obj){ 1849 var offsetTop = obj.offsetTop; 1850 while((obj = obj.offsetParent) && !isNaN(obj.offsetTop)){ 1851 offsetTop += obj.offsetTop; 1852 if( obj.tagName !== 'BODY') { 1853 offsetTop -= obj.scrollTop; 1854 } 1855 } 1856 return offsetTop; 1857 }, 1858 _offset: function (obj) { 1859 return { 1860 left: this._offsetLeft(obj), 1861 right: this._offsetRight(obj), 1862 top: this._offsetTop(obj) 1863 }; 1864 }, 1865 _css: function(elementRef, styleName, value) { 1866 if ($) { 1867 $.style(elementRef, styleName, value); 1868 } else { 1869 var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) { 1870 return letter.toUpperCase(); 1871 }); 1872 elementRef.style[style] = value; 1873 } 1874 }, 1875 _toValue: function(percentage) { 1876 return this.options.scale.toValue.apply(this, [percentage]); 1877 }, 1878 _toPercentage: function(value) { 1879 return this.options.scale.toPercentage.apply(this, [value]); 1880 }, 1881 _setTooltipPosition: function(){ 1882 var tooltips = [this.tooltip, this.tooltip_min, this.tooltip_max]; 1883 if (this.options.orientation === 'vertical'){ 1884 var tooltipPos; 1885 if(this.options.tooltip_position) { 1886 tooltipPos = this.options.tooltip_position; 1887 } else { 1888 if(this.options.rtl) { 1889 tooltipPos = 'left'; 1890 } else { 1891 tooltipPos = 'right'; 1892 } 1893 } 1894 var oppositeSide = (tooltipPos === 'left') ? 'right' : 'left'; 1895 tooltips.forEach(function(tooltip){ 1896 this._addClass(tooltip, tooltipPos); 1897 tooltip.style[oppositeSide] = '100%'; 1898 }.bind(this)); 1899 } else if(this.options.tooltip_position === 'bottom') { 1900 tooltips.forEach(function(tooltip){ 1901 this._addClass(tooltip, 'bottom'); 1902 tooltip.style.top = 22 + 'px'; 1903 }.bind(this)); 1904 } else { 1905 tooltips.forEach(function(tooltip){ 1906 this._addClass(tooltip, 'top'); 1907 tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px'; 1908 }.bind(this)); 1909 } 1910 } 1911 }; 1912 1913 /********************************* 1914 1915 Attach to global namespace 1916 1917 *********************************/ 1918 if($ && $.fn) { 1919 let autoRegisterNamespace; 1920 1921 if (!$.fn.slider) { 1922 $.bridget(NAMESPACE_MAIN, Slider); 1923 autoRegisterNamespace = NAMESPACE_MAIN; 1924 } 1925 else { 1926 if (windowIsDefined) { 1927 window.console.warn("bootstrap-slider.js - WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSl
1927ider namespace instead."); 1928 } 1929 autoRegisterNamespace = NAMESPACE_ALTERNATE; 1930 } 1931 $.bridget(NAMESPACE_ALTERNATE, Slider); 1932 1933 // Auto-Register data-provide="slider" Elements 1934 $(function() { 1935 $("input[data-provide=slider]")[autoRegisterNamespace](); 1936 }); 1937 } 1938 1939 })( $ ); 1940 1941 return Slider; 1942}));
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.