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