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 * Licensed under the Apache License, Version 2.0 (the "License"); 15 * you may not use this file except in compliance with the License. 16 * You may obtain a copy of the License at 17 * 18 * http://www.apache.org/licenses/LICENSE-2.0 19 * 20 * Unless required by applicable law or agreed to in writing, software 21 * distributed under the License is distributed on an "AS IS" BASIS, 22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 * See the License for the specific language governing permissions and 24 * limitations under the License. 25 * ========================================================= */ 26 27 28/** 29 * Bridget makes jQuery widgets 30 * v1.0.1 31 * MIT license 32 */ 33 34(function(root, factory) { 35 if(typeof define === "function" && define.amd) { 36 define(["jquery"], factory); 37 } else if(typeof module === "object" && module.exports) { 38 var jQuery; 39 try { 40 jQuery = require("jquery"); 41 } catch (err) { 42 jQuery = null; 43 } 44 module.exports = factory(jQuery); 45 } else { 46 root.Slider = factory(root.jQuery); 47 } 48}(this, function($) { 49 // Reference to Slider constructor 50 var Slider; 51 52 53 (function( $ ) { 54 55 'use strict'; 56 57 // -------------------------- utils -------------------------- // 58 59 var slice = Array.prototype.slice; 60 61 function noop() {} 62 63 // -------------------------- definition -------------------------- // 64 65 function defineBridget( $ ) { 66 67 // bail if no jQuery 68 if ( !$ ) { 69 return; 70 } 71 72 // -------------------------- addOptionMethod -------------------------- // 73 74 /** 75 * adds option method -> $().plugin('option', {...}) 76 * @param {Function} PluginClass - constructor class 77 */ 78 function addOptionMethod( PluginClass ) { 79 // don't overwrite original option method 80 if ( PluginClass.prototype.option ) { 81 return; 82 } 83 84 // option setter 85 PluginClass.prototype.option = function( opts ) { 86 // bail out if not an object 87 if ( !$.isPlainObject( opts ) ){ 88 return; 89 } 90 this.options = $.extend( true, this.options, opts ); 91 }; 92 } 93 94 95 // -------------------------- plugin bridge -------------------------- // 96 97 // helper function for logging errors 98 // $.error breaks jQuery chaining 99 var logError = typeof console === 'undefined' ? noop : 100 function( message ) { 101 console.error( message ); 102 }; 103 104 /** 105 * jQuery plugin bridge, access methods like $elem.plugin('method') 106 * @param {String} namespace - plugin name 107 * @param {Function} PluginClass - constructor class 108 */ 109 function bridge( namespace, PluginClass ) { 110 // add to jQuery fn namespace 111 $.fn[ namespace ] = function( options ) { 112 if ( typeof options === 'string' ) { 113 // call plugin method when first argument is a string 114 // get arguments for method 115 var args = slice.call( arguments, 1 ); 116 117 for ( var i=0, len = this.length; i < len; i++ ) { 118 var elem = this[i]; 119 var instance = $.data( elem, namespace ); 120 if ( !instance ) { 121 logError( "cannot call methods on " + namespace + " prior to initialization; " + 122 "attempted to call '" + options + "'" ); 123 continue; 124 } 125 if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) { 126 logError( "no such method '" + options + "' for " + namespace + " instance" ); 127 continue; 128 } 129 130 // trigger method with arguments 131 var returnValue = instance[ options ].apply( instance, args); 132 133 // break look and return first value if provided 134 if ( returnValue !== undefined && returnValue !== instance) { 135 return returnValue; 136 } 137 } 138 // return this if no return value 139 return this; 140 } else { 141 var objects = this.map( function() { 142 var instance = $.data( this, namespace ); 143 if ( instance ) { 144 // apply options & init 145 instance.option( options ); 146 instance._init(); 147 } else { 148 // initialize new instance 149 instance = new PluginClass( this, options ); 150 $.data( this, namespace, instance ); 151 } 152 return $(this); 153 }); 154 155 if(!objects || objects.length > 1) { 156 return objects; 157 } else { 158 return objects[0]; 159 } 160 } 161 }; 162 163 } 164 165 // -------------------------- bridget -------------------------- // 166 167 /** 168 * converts a Prototypical class into a proper jQuery plugin 169 * the class must have a ._init method 170 * @param {String} namespace - plugin name, used in $().pluginName 171 * @param {Function} PluginClass - constructor class 172 */ 173 $.bridget = function( namespace, PluginClass ) { 174 addOptionMethod( PluginClass ); 175 bridge( namespace, PluginClass ); 176 }; 177 178 return $.bridget; 179 180 } 181 182 // get jquery from browser global 183 defineBridget( $ ); 184 185 })( $ ); 186 187 188 /************************************************* 189 190 BOOTSTRAP-SLIDER SOURCE CODE 191 192 **************************************************/ 193 194 (function($) { 195 196 var ErrorMsgs = { 197 formatInvalidInputErrorMsg : function(input) { 198 return "Invalid input value '" + input + "' passed in"; 199 }, 200 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" 201 }; 202 203 var SliderScale = { 204 linear: { 205 toValue: function(percentage) { 206 var rawValue = percentage/100 * (this.options.max - this.options.min); 207 var value = this.options.min + Math.round(rawValue / this.options.step) * this.options.step; 208 209 if (value < this.options.min) { 210 return this.options.min; 211 } else if (value > this.options.max) { 212 return this.options.max; 213 } else { 214 return value; 215 } 216 }, 217 toPercentage: function(value) { 218 if (this.options.max === this.options.min) { 219 return 0; 220 } else { 221 return 100 * (value - this.options.min) / (this.options.max - this.options.min); 222 } 223 } 224 }, 225 226 logarithmic: { 227 /* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */ 228 toValue: function(percentage) { 229 var min = (this.options.min === 0) ? 0 : Math.log(this.options.min); 230 var max = Math.log(this.options.max); 231 return Math.exp(min + (max - min) * percentage / 100); 232 }, 233 toPercentage: function(value) { 234 if (this.options.max === this.options.min) { 235 return 0; 236 } else { 237 var max = Math.log(this.options.max); 238 var min = this.options.min === 0 ? 0 : Math.log(this.options.min); 239 var v = value === 0 ? 0 : Math.log(value); 240 return 100 * (v - min) / (max - min); 241 } 242 } 243 } 244 }; 245 246 247 /************************************************* 248 249 CONSTRUCTOR 250 251 **************************************************/ 252 Slider = function(element, options) { 253 createNewSlider.call(this, element, options); 254 return this; 255 }; 256 257 function createNewSlider(element, options) { 258 259 if(typeof element === "string") { 260 this.element = document.querySelector(element); 261 } else if(element instanceof HTMLElement) { 262 this.element = element; 263 } 264 265 /************************************************* 266 267 Process Options 268 269 **************************************************/ 270 options = options ? options : {}; 271 var optionTypes = Object.keys(this.defaultOptions); 272 273 for(var i = 0; i < optionTypes.length; i++) { 274 var optName = optionTypes[i]; 275 276 // First check if an option was passed in via the constructor 277 var val = options[optName]; 278 // If no data attrib, then check data atrributes 279 val = (typeof val !== 'undefined') ? val : getDataAttrib(this.element, optName); 280 // Finally, if nothing was specified, use the defaults 281 val = (val !== null) ? val : this.defaultOptions[optName]; 282 283 // Set all options on the instance of the Slider 284 if(!this.options) { 285 this.options = {}; 286 } 287 this.options[optName] = val; 288 } 289 290 function getDataAttrib(element, optName) {
291 var dataName = "data-slider-" + optName; 292 var dataValString = element.getAttribute(dataName); 293 294 try { 295 return JSON.parse(dataValString); 296 } 297 catch(err) { 298 return dataValString; 299 } 300 } 301 302 /************************************************* 303 304 Create Markup 305 306 **************************************************/ 307 308 var origWidth = this.element.style.width; 309 var updateSlider = false; 310 var parent = this.element.parentNode; 311 var sliderTrackSelection; 312 var sliderTrackLow, sliderTrackHigh; 313 var sliderMinHandle; 314 var sliderMaxHandle; 315 316 if (this.sliderElem) { 317 updateSlider = true; 318 } else { 319 /* Create elements needed for slider */ 320 this.sliderElem = document.createElement("div"); 321 this.sliderElem.className = "slider"; 322 323 /* Create slider track elements */ 324 var sliderTrack = document.createElement("div"); 325 sliderTrack.className = "slider-track"; 326 327 sliderTrackLow = document.createElement("div"); 328 sliderTrackLow.className = "slider-track-low"; 329 330 sliderTrackSelection = document.createElement("div"); 331 sliderTrackSelection.className = "slider-selection"; 332 333 sliderTrackHigh = document.createElement("div"); 334 sliderTrackHigh.className = "slider-track-high"; 335 336 sliderMinHandle = document.createElement("div"); 337 sliderMinHandle.className = "slider-handle min-slider-handle"; 338 339 sliderMaxHandle = document.createElement("div"); 340 sliderMaxHandle.className = "slider-handle max-slider-handle"; 341 342 sliderTrack.appendChild(sliderTrackLow); 343 sliderTrack.appendChild(sliderTrackSelection); 344 sliderTrack.appendChild(sliderTrackHigh); 345 346 /* Create ticks */ 347 this.ticks = []; 348 if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { 349 for (i = 0; i < this.options.ticks.length; i++) { 350 var tick = document.createElement('div'); 351 tick.className = 'slider-tick'; 352 353 this.ticks.push(tick); 354 sliderTrack.appendChild(tick); 355 } 356 357 sliderTrackSelection.className += " tick-slider-selection"; 358 } 359 360 sliderTrack.appendChild(sliderMinHandle); 361 sliderTrack.appendChild(sliderMaxHandle); 362 363 this.tickLabels = []; 364 if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) { 365 this.tickLabelContainer = document.createElement('div'); 366 this.tickLabelContainer.className = 'slider-tick-label-container'; 367 368 for (i = 0; i < this.options.ticks_labels.length; i++) { 369 var label = document.createElement('div'); 370 label.className = 'slider-tick-label'; 371 label.innerHTML = this.options.ticks_labels[i]; 372 373 this.tickLabels.push(label); 374 this.tickLabelContainer.appendChild(label); 375 } 376 } 377 378 379 var createAndAppendTooltipSubElements = function(tooltipElem) { 380 var arrow = document.createElement("div"); 381 arrow.className = "tooltip-arrow"; 382 383 var inner = document.createElement("div"); 384 inner.className = "tooltip-inner"; 385 386 tooltipElem.appendChild(arrow); 387 tooltipElem.appendChild(inner); 388 389 }; 390 391 /* Create tooltip elements */ 392 var sliderTooltip = document.createElement("div"); 393 sliderTooltip.className = "tooltip tooltip-main"; 394 createAndAppendTooltipSubElements(sliderTooltip); 395 396 var sliderTooltipMin = document.createElement("div"); 397 sliderTooltipMin.className = "tooltip tooltip-min"; 398 createAndAppendTooltipSubElements(sliderTooltipMin); 399 400 var sliderTooltipMax = document.createElement("div"); 401 sliderTooltipMax.className = "tooltip tooltip-max"; 402 createAndAppendTooltipSubElements(sliderTooltipMax); 403 404 405 /* Append components to sliderElem */ 406 this.sliderElem.appendChild(sliderTrack); 407 this.sliderElem.appendChild(sliderTooltip); 408 this.sliderElem.appendChild(sliderTooltipMin); 409 this.sliderElem.appendChild(sliderTooltipMax); 410 411 if (this.tickLabelContainer) { 412 this.sliderElem.appendChild(this.tickLabelContainer); 413 } 414 415 /* Append slider element to parent container, right before the original <input> element */ 416 parent.insertBefore(this.sliderElem, this.element); 417 418 /* Hide original <input> element */ 419 this.element.style.display = "none"; 420 }
vendor: 1,473 bytes, lines 421-460
421 /* If JQuery exists, cache JQ references */ 422 if($) { 423 this.$element = $(this.element); 424 this.$sliderElem = $(this.sliderElem); 425 } 426 427 /************************************************* 428 429 Setup 430 431 **************************************************/ 432 this.eventToCallbackMap = {}; 433 this.sliderElem.id = this.options.id; 434 435 this.touchCapable = 'ontouchstart' in window || (window.DocumentTouch && document instanceof window.DocumentTouch); 436 437 this.tooltip = this.sliderElem.querySelector('.tooltip-main'); 438 this.tooltipInner = this.tooltip.querySelector('.tooltip-inner'); 439 440 this.tooltip_min = this.sliderElem.querySelector('.tooltip-min'); 441 this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner'); 442 443 this.tooltip_max = this.sliderElem.querySelector('.tooltip-max'); 444 this.tooltipInner_max= this.tooltip_max.querySelector('.tooltip-inner'); 445 446 if (SliderScale[this.options.scale]) { 447 this.options.scale = SliderScale[this.options.scale]; 448 } 449 450 if (updateSlider === true) { 451 // Reset classes 452 this._removeClass(this.sliderElem, 'slider-horizontal'); 453 this._removeClass(this.sliderElem, 'slider-vertical'); 454 this._removeClass(this.tooltip, 'hide'); 455 this._removeClass(this.tooltip_min, 'hide'); 456 this._removeClass(this.tooltip_max, 'hide'); 457 458 // Undo existing inline styles for track 459 ["left", "top", "width", "height"].forEach(function(prop) { 460 this._removeProperty(this.trackLow, prop);
461 this._removeProperty(this.trackSelection, prop); 462 this._removeProperty(this.trackHigh, prop); 463 }, this); 464 465 // Undo inline styles on handles 466 [this.handle1, this.handle2].forEach(function(handle) { 467 this._removeProperty(handle, 'left'); 468 this._removeProperty(handle, 'top'); 469 }, this); 470 471 // Undo inline styles and classes on tooltips 472 [this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function(tooltip) { 473 this._removeProperty(tooltip, 'left'); 474 this._removeProperty(tooltip, 'top'); 475 this._removeProperty(tooltip, 'margin-left'); 476 this._removeProperty(tooltip, 'margin-top'); 477 478 this._removeClass(tooltip, 'right'); 479 this._removeClass(tooltip, 'top'); 480 }, this); 481 } 482 483 if(this.options.orientation === 'vertical') { 484 this._addClass(this.sliderElem,'slider-vertical'); 485 486 this.stylePos = 'top'; 487 this.mousePos = 'pageY'; 488 this.sizePos = 'offsetHeight'; 489 490 this._addClass(this.tooltip, 'right'); 491 this.tooltip.style.left = '100%'; 492 493 this._addClass(this.tooltip_min, 'right'); 494 this.tooltip_min.style.left = '100%'; 495 496 this._addClass(this.tooltip_max, 'right'); 497 this.tooltip_max.style.left = '100%'; 498 } else { 499 this._addClass(this.sliderElem, 'slider-horizontal'); 500 this.sliderElem.style.width = origWidth; 501 502 this.options.orientation = 'horizontal'; 503 this.stylePos = 'left'; 504 this.mousePos = 'pageX'; 505 this.sizePos = 'offsetWidth'; 506 507 this._addClass(this.tooltip, 'top'); 508 this.tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px'; 509 510 this._addClass(this.tooltip_min, 'top'); 511 this.tooltip_min.style.top = -this.tooltip_min.outerHeight - 14 + 'px'; 512 513 this._addClass(this.tooltip_max, 'top'); 514 this.tooltip_max.style.top = -this.tooltip_max.outerHeight - 14 + 'px'; 515 } 516 517 /* In case ticks are specified, overwrite the min and max bounds */ 518 if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { 519 this.options.max = Math.max.apply(Math, this.options.ticks); 520 this.options.min = Math.min.apply(Math, this.options.ticks); 521 } 522 523 524 if (Array.isArray(this.options.value)) { 525 this.options.range = true; 526 } else if (this.options.range) { 527 // User wants a range, but value is not an array 528 this.options.value = [this.options.value, this.options.max]; 529 } 530 531 this.trackLow = sliderTrackLow || this.trackLow; 532 this.trackSelection = sliderTrackSelection || this.trackSelection; 533 this.trackHigh = sliderTrackHigh || this.trackHigh; 534 535 if (this.options.selection === 'none') { 536 this._addClass(this.trackLow, 'hide'); 537 this._addClass(this.trackSelection, 'hide'); 538 this._addClass(this.trackHigh, 'hide'); 539 } 540 541 this.handle1 = sliderMinHandle || this.handle1; 542 this.handle2 = sliderMaxHandle || this.handle2; 543 544 if (updateSlider === true) { 545 // Reset classes 546 this._removeClass(this.handle1, 'round triangle'); 547 this._removeClass(this.handle2, 'round triangle hide'); 548 549 for (i = 0; i < this.ticks.length; i++) { 550 this._removeClass(this.ticks[i], 'round triangle hide'); 551 } 552 } 553 554 var availableHandleModifiers = ['round', 'triangle', 'custom']; 555 var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1; 556 if (isValidHandleType) { 557 this._addClass(this.handle1, this.options.handle); 558 this._addClass(this.handle2, this.options.handle); 559 560 for (i = 0; i < this.ticks.length; i++) { 561 this._addClass(this.ticks[i], this.options.handle); 562 } 563 } 564 565 this.offset = this._offset(this.sliderElem); 566 this.size = this.sliderElem[this.sizePos]; 567 this.setValue(this.options.value); 568 569 /****************************************** 570 571 Bind Event Listeners 572 573 ******************************************/ 574 575 // Bind keyboard handlers 576 this.handle1Keydown = this._keydown.bind(this, 0); 577 this.handle1.addEventListener("keydown", this.handle1Keydown, false); 578 579 this.handle2Keydown = this._keydown.bind(this, 1); 580 this.handle2.addEventListener("keydown", this.handle2Keydown, false); 581 582 if (this.touchCapable) { 583 // Bind touch handlers 584 this.mousedown = this._mousedown.bind(this); 585 this.sliderElem.addEventListener("touchstart", this.mousedown, false); 586 } else { 587 // Bind mouse handlers 588 this.mousedown = this._mousedown.bind(this); 589 this.sliderElem.addEventListener("mousedown", this.mousedown, false); 590 } 591 592 // Bind tooltip-related handlers 593 if(this.options.tooltip === 'hide') { 594 this._addClass(this.tooltip, 'hide'); 595 this._addClass(this.tooltip_min, 'hide'); 596 this._addClass(this.tooltip_max, 'hide'); 597 } else if(this.options.tooltip === 'always') { 598 this._showTooltip(); 599 this._alwaysShowTooltip = true; 600 } else { 601 this.showTooltip = this._showTooltip.bind(this); 602 this.hideTooltip = this._hideTooltip.bind(this); 603 604 this.sliderElem.addEventListener("mouseenter", this.showTooltip, false); 605 this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false); 606 607 this.handle1.addEventListener("focus", this.showTooltip, false); 608 this.handle1.addEventListener("blur", this.hideTooltip, false); 609 610 this.handle2.addEventListener("focus", this.showTooltip, false); 611 this.handle2.addEventListener("blur", this.hideTooltip, false); 612 } 613 614 if(this.options.enabled) { 615 this.enable(); 616 } else { 617 this.disable(); 618 } 619 } 620 621 622 623 /************************************************* 624 625 INSTANCE PROPERTIES/METHODS 626 627 - Any methods bound to the prototype are considered 628 part of the plugin's `public` interface 629 630 **************************************************/ 631 Slider.prototype = { 632 _init: function() {}
632, // NOTE: Must exist to support bridget 633 634 constructor: Slider, 635 636 defaultOptions: { 637 id: "", 638 min: 0, 639 max: 10, 640 step: 1, 641 precision: 0, 642 orientation: 'horizontal', 643 value: 5, 644 range: false, 645 selection: 'before', 646 tooltip: 'show', 647 tooltip_split: false, 648 handle: 'round', 649 reversed: false, 650 enabled: true, 651 formatter: function(val) { 652 if (Array.isArray(val)) { 653 return val[0] + " : " + val[1]; 654 } else { 655 return val; 656 } 657 }, 658 natural_arrow_keys: false, 659 ticks: [], 660 ticks_labels: [], 661 ticks_snap_bounds: 0, 662 scale: 'linear' 663 }, 664 665 over: false, 666 667 inDrag: false, 668 669 getValue: function() { 670 if (this.options.range) { 671 return this.options.value; 672 } 673 return this.options.value[0]; 674 }, 675 676 setValue: function(val, triggerSlideEvent) { 677 if (!val) { 678 val = 0; 679 } 680 var oldValue = this.getValue(); 681 this.options.value = this._validateInputValue(val); 682 var applyPrecision = this._applyPrecision.bind(this); 683 684 if (this.options.range) { 685 this.options.value[0] = applyPrecision(this.options.value[0]); 686 this.options.value[1] = applyPrecision(this.options.value[1]); 687 688 this.options.value[0] = Math.max(this.options.min, Math.min(this.options.max, this.options.value[0])); 689 this.options.value[1] = Math.max(this.options.min, Math.min(this.options.max, this.options.value[1])); 690 } else { 691 this.options.value = applyPrecision(this.options.value); 692 this.options.value = [ Math.max(this.options.min, Math.min(this.options.max, this.options.value))]; 693 this._addClass(this.handle2, 'hide'); 694 if (this.options.selection === 'after') { 695 this.options.value[1] = this.options.max; 696 } else { 697 this.options.value[1] = this.options.min; 698 } 699 } 700 701 if (this.options.max > this.options.min) { 702 this.percentage = [ 703 this._toPercentage(this.options.value[0]), 704 this._toPercentage(this.options.value[1]), 705 this.options.step * 100 / (this.options.max - this.options.min) 706 ]; 707 } else { 708 this.percentage = [0, 0, 100]; 709 } 710 711 this._layout(); 712 var newValue = this.options.range ? this.options.value : this.options.value[0]; 713 714 if(triggerSlideEvent === true) { 715 this._trigger('slide', newValue); 716 } 717 if(oldValue !== newValue) { 718 this._trigger('change', { 719 oldValue: oldValue, 720 newValue: newValue 721 }); 722 } 723 this._setDataVal(newValue); 724 725 return this; 726 }, 727 728 destroy: function(){ 729 // Remove event handlers on slider elements 730 this._removeSliderEventHandlers(); 731 732 // Remove the slider from the DOM 733 this.sliderElem.parentNode.removeChild(this.sliderElem); 734 /* Show original <input> element */ 735 this.element.style.display = ""; 736 737 // Clear out custom event bindings 738 this._cleanUpEventCallbacksMap(); 739 740 // Remove data values 741 this.element.removeAttribute("data"); 742 743 // Remove JQuery handlers/data 744 if($) { 745 this._unbindJQueryEventHandlers(); 746 this.$element.removeData('slider'); 747 } 748 }, 749 750 disable: function() { 751 this.options.enabled = false; 752 this.handle1.removeAttribute("tabindex"); 753 this.handle2.removeAttribute("tabindex"); 754 this._addClass(this.sliderElem, 'slider-disabled'); 755 this._trigger('slideDisabled'); 756 757 return this; 758 }, 759 760 enable: function() { 761 this.options.enabled = true; 762 this.handle1.setAttribute("tabindex", 0); 763 this.handle2.setAttribute("tabindex", 0); 764 this._removeClass(this.sliderElem, 'slider-disabled'); 765 this._trigger('slideEnabled'); 766 767 return this; 768 }, 769 770 toggle: function() { 771 if(this.options.enabled) { 772 this.disable(); 773 } else { 774 this.enable(); 775 } 776 777 return this; 778 }, 779 780 isEnabled: function() { 781 return this.options.enabled; 782 }, 783 784 on: function(evt, callback) { 785 if($) { 786 this.$element.on(evt, callback); 787 this.$sliderElem.on(evt, callback); 788 } else { 789 this._bindNonQueryEventHandler(evt, callback); 790 } 791 return this; 792 }, 793 794 getAttribute: function(attribute) { 795 if(attribute) { 796 return this.options[attribute]; 797 } else { 798 return this.options; 799 } 800 }, 801 802 setAttribute: function(attribute, value) { 803 this.options[attribute] = value; 804 return this; 805 }, 806 807 refresh: function() { 808 this._removeSliderEventHandlers(); 809 createNewSlider.call(this, this.element, this.options); 810 if($) { 811 // Bind new instance of slider to the element 812 $.data(this.element, 'slider', this); 813 } 814 return this; 815 }, 816 817 relayout: function() { 818 this._layout(); 819 return this; 820 }, 821 822 /******************************+ 823 824 HELPERS 825 826 - Any method that is not part of the public interface. 827 - Place it underneath this comment block and write its signature like so: 828 829 _fnName : function() {...} 830 831 ********************************/ 832 _removeSliderEventHandlers: function() { 833 // Remove event listeners from handle1 834 this.handle1.removeEventListener("keydown", this.handle1Keydown, false); 835 this.handle1.removeEventListener("focus", this.showTooltip, false); 836 this.handle1.removeEventListener("blur", this.hideTooltip, false); 837 838 // Remove event listeners from handle2 839 this.handle2.removeEventListener("keydown", this.handle2Keydown, false); 840 this.handle2.removeEventListener("focus", this.handle2Keydown, false); 841 this.handle2.removeEventListener("blur", this.handle2Keydown, false); 842 843 // Remove event listeners from sliderElem 844 this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false); 845 this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false); 846 this.sliderElem.removeEventListener("touchstart", this.mousedown, false); 847 this.sliderElem.removeEventListener("mousedown", this.mousedown, false); 848 }, 849 _bindNonQueryEventHandler: function(evt, callback) { 850 if(this.eventToCallbackMap[evt]===undefined) { 851 this.eventToCallbackMap[evt] = []; 852 } 853 this.eventToCallbackMap[evt].push(callback); 854 }, 855 _cleanUpEventCallbacksMap: function() { 856 var eventNames = Object.keys(this.eventToCallbackMap); 857 for(var i = 0; i < eventNames.length; i++) { 858 var eventName = eventNames[i]; 859 this.eventToCallbackMap[eventName] = null; 860 } 861 }, 862 _showTooltip: function() { 863 if (this.options.tooltip_split === false ){ 864 this._addClass(this.tooltip, 'in'); 865 } else { 866 this._addClass(this.tooltip_min, 'in'); 867 this._addClass(this.tooltip_max, 'in'); 868 } 869 this.over = true; 870 }, 871 _hideTooltip: function() { 872 if (this.inDrag === false && this.alwaysShowTooltip !== true) { 873 this._removeClass(this.tooltip, 'in'); 874 this._removeClass(this.tooltip_min, 'in'); 875 this._removeClass(this.tooltip_max, 'in'); 876 } 877 this.over = false;
878 }, 879 _layout: function() { 880 var positionPercentages; 881 882 if(this.options.reversed) { 883 positionPercentages = [ 100 - this.percentage[0], this.percentage[1] ]; 884 } else { 885 positionPercentages = [ this.percentage[0], this.percentage[1] ]; 886 } 887 888 this.handle1.style[this.stylePos] = positionPercentages[0]+'%'; 889 this.handle2.style[this.stylePos] = positionPercentages[1]+'%'; 890 891 /* Position ticks and labels */ 892 if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { 893 var maxTickValue = Math.max.apply(Math, this.options.ticks); 894 var minTickValue = Math.min.apply(Math, this.options.ticks); 895 896 var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width'; 897 var styleMargin = this.options.orientation === 'vertical' ? 'marginTop' : 'marginLeft'; 898 var labelSize = this.size / (this.options.ticks.length - 1); 899 900 if (this.tickLabelContainer) { 901 this.tickLabelContainer.style[styleMargin] = -labelSize/2 + 'px'; 902 if (this.options.orientation === 'horizontal') { 903 var extraHeight = this.tickLabelContainer.offsetHeight - this.sliderElem.offsetHeight; 904 this.sliderElem.style.marginBottom = extraHeight + 'px'; 905 } 906 } 907 for (var i = 0; i < this.options.ticks.length; i++) { 908 var percentage = 100 * (this.options.ticks[i] - minTickValue) / (maxTickValue - minTickValue); 909 this.ticks[i].style[this.stylePos] = percentage + '%'; 910 911 /* Set class labels to denote whether ticks are in the selection */ 912 this._removeClass(this.ticks[i], 'in-selection'); 913 if (percentage <= positionPercentages[0] && !this.options.range) { 914 this._addClass(this.ticks[i], 'in-selection'); 915 } else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) { 916 this._addClass(this.ticks[i], 'in-selection'); 917 } 918 919 if (this.tickLabels[i]) { 920 this.tickLabels[i].style[styleSize] = labelSize + 'px'; 921 } 922 } 923 } 924 925 if (this.options.orientation === 'vertical') { 926 this.trackLow.style.top = '0'; 927 this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) +'%'; 928 929 this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%'; 930 this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%'; 931 932 this.trackHigh.style.bottom = '0'; 933 this.trackHigh.style.height = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%'; 934 } else { 935 this.trackLow.style.left = '0'; 936 this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) +'%'; 937 938 this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) +'%'; 939 this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%'; 940 941 this.trackHigh.style.right = '0'; 942 this.trackHigh.style.width = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%'; 943 944 var offset_min = this.tooltip_min.getBoundingClientRect(); 945 var offset_max = this.tooltip_max.getBoundingClientRect(); 946 947 if (offset_min.right > offset_max.left) { 948 this._removeClass(this.tooltip_max, 'top'); 949 this._addClass(this.tooltip_max, 'bottom'); 950 this.tooltip_max.style.top = 18 + 'px'; 951 } else { 952 this._removeClass(this.tooltip_max, 'bottom'); 953 this._addClass(this.tooltip_max, 'top'); 954 this.tooltip_max.style.top = this.tooltip_min.style.top; 955 } 956 } 957 958 var formattedTooltipVal; 959 960 if (this.options.range) { 961 formattedTooltipVal = this.options.formatter(this.options.value); 962 this._setText(this.tooltipInner, formattedTooltipVal); 963 this.tooltip.style[this.stylePos] = (positionPercentages[1] + positionPercentages[0])/2 + '%'; 964 965 if (this.options.orientation === 'vertical') { 966 this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px'); 967 } else { 968 this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px'); 969 } 970 971 if (this.options.orientation === 'vertical') { 972 this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px'); 973 } else { 974 this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px'); 975 } 976 977 var innerTooltipMinText = this.options.formatter(this.options.value[0]); 978 this._setText(this.tooltipInner_min, innerTooltipMinText); 979 980 var innerTooltipMaxText = this.options.formatter(this.options.value[1]); 981 this._setText(this.tooltipInner_max, innerTooltipMaxText); 982 983 this.tooltip_min.style[this.stylePos] = positionPercentages[0] + '%'; 984 985 if (this.options.orientation === 'vertical') { 986 this._css(this.tooltip_min, 'margin-top', -this.tooltip_min.offsetHeight / 2 + 'px'); 987 } else { 988 this._css(this.tooltip_min, 'margin-left', -this.tooltip_min.offsetWidth / 2 + 'px'); 989 } 990 991 this.tooltip_max.style[this.stylePos] = positionPercentages[1] + '%'; 992 993 if (this.options.orientation === 'vertical') { 994 this._css(this.tooltip_max, 'margin-top', -this.tooltip_max.offsetHeight / 2 + 'px'); 995 } else { 996 this._css(this.tooltip_max, 'margin-left', -this.tooltip_max.offsetWidth / 2 + 'px'); 997 } 998 } else { 999 formattedTooltipVal = this.options.formatter(this.options.value[0]); 1000 this._setText(this.tooltipInner, formattedTooltipVal); 1001 1002 this.tooltip.style[this.stylePos] = positionPercentages[0] + '%'; 1003 if (this.options.orientation === 'vertical') { 1004 this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px'); 1005 } else { 1006 this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px'); 1007 } 1008 } 1009 }, 1010 _removeProperty: function(element, prop) { 1011 if (element.style.removeProperty) { 1012 element.style.removeProperty(prop); 1013 } else { 1014 element.style.removeAttribute(prop); 1015 } 1016 }, 1017 _mousedown: function(ev) { 1018 if(!this.options.enabled) { 1019 return false;
1020 } 1021 1022 this._triggerFocusOnHandle(); 1023 1024 this.offset = this._offset(this.sliderElem); 1025 this.size = this.sliderElem[this.sizePos]; 1026 1027 var percentage = this._getPercentage(ev); 1028 1029 if (this.options.range) { 1030 var diff1 = Math.abs(this.percentage[0] - percentage); 1031 var diff2 = Math.abs(this.percentage[1] - percentage); 1032 this.dragged = (diff1 < diff2) ? 0 : 1; 1033 } else { 1034 this.dragged = 0; 1035 } 1036 1037 this.percentage[this.dragged] = this.options.reversed ? 100 - percentage : percentage; 1038 this._layout(); 1039 1040 if (this.touchCapable) { 1041 document.removeEventListener("touchmove", this.mousemove, false); 1042 document.removeEventListener("touchend", this.mouseup, false); 1043 } 1044 1045 if(this.mousemove){ 1046 document.removeEventListener("mousemove", this.mousemove, false); 1047 } 1048 if(this.mouseup){ 1049 document.removeEventListener("mouseup", this.mouseup, false); 1050 } 1051 1052 this.mousemove = this._mousemove.bind(this); 1053 this.mouseup = this._mouseup.bind(this); 1054 1055 if (this.touchCapable) { 1056 // Touch: Bind touch events: 1057 document.addEventListener("touchmove", this.mousemove, false); 1058 document.addEventListener("touchend", this.mouseup, false); 1059 } 1060 // Bind mouse events: 1061 document.addEventListener("mousemove", this.mousemove, false); 1062 document.addEventListener("mouseup", this.mouseup, false); 1063 1064 this.inDrag = true; 1065 var newValue = this._calculateValue(); 1066 1067 this._trigger('slideStart', newValue); 1068 1069 this._setDataVal(newValue); 1070 this.setValue(newValue); 1071 1072 this._pauseEvent(ev); 1073 1074 return true; 1075 }, 1076 _triggerFocusOnHandle: function(handleIdx) { 1077 if(handleIdx === 0) { 1078 this.handle1.focus(); 1079 } 1080 if(handleIdx === 1) { 1081 this.handle2.focus(); 1082 } 1083 }, 1084 _keydown: function(handleIdx, ev) { 1085 if(!this.options.enabled) { 1086 return false; 1087 } 1088 1089 var dir; 1090 switch (ev.keyCode) { 1091 case 37: // left 1092 case 40: // down 1093 dir = -1; 1094 break; 1095 case 39: // right 1096 case 38: // up 1097 dir = 1; 1098 break; 1099 } 1100 if (!dir) { 1101 return; 1102 } 1103 1104 // use natural arrow keys instead of from min to max 1105 if (this.options.natural_arrow_keys) { 1106 var ifVerticalAndNotReversed = (this.options.orientation === 'vertical' && !this.options.reversed); 1107 var ifHorizontalAndReversed = (this.options.orientation === 'horizontal' && this.options.reversed); 1108 1109 if (ifVerticalAndNotReversed || ifHorizontalAndReversed) { 1110 dir = -dir; 1111 } 1112 } 1113 1114 var val = this.options.value[handleIdx] + dir * this.options.step; 1115 if (this.options.range) { 1116 val = [ (!handleIdx) ? val : this.options.value[0], 1117 ( handleIdx) ? val : this.options.value[1]]; 1118 } 1119 1120 this._trigger('slideStart', val); 1121 this._setDataVal(val); 1122 this.setValue(val, true); 1123 1124 this._trigger('slideStop', val); 1125 this._setDataVal(val); 1126 this._layout(); 1127 1128 this._pauseEvent(ev); 1129 1130 return false; 1131 }, 1132 _pauseEvent: function(ev) { 1133 if(ev.stopPropagation) { 1134 ev.stopPropagation(); 1135 } 1136 if(ev.preventDefault) { 1137 ev.preventDefault(); 1138 } 1139 ev.cancelBubble=true; 1140 ev.returnValue=false; 1141 }, 1142 _mousemove: function(ev) { 1143 if(!this.options.enabled) { 1144 return false; 1145 } 1146 1147 var percentage = this._getPercentage(ev); 1148 this._adjustPercentageForRangeSliders(percentage); 1149 this.percentage[this.dragged] = this.options.reversed ? 100 - percentage : percentage; 1150 this._layout(); 1151 1152 var val = this._calculateValue(true); 1153 this.setValue(val, true); 1154 1155 return false; 1156 }, 1157 _adjustPercentageForRangeSliders: function(percentage) { 1158 if (this.options.range) { 1159 if (this.dragged === 0 && this.percentage[1] < percentage) { 1160 this.percentage[0] = this.percentage[1]; 1161 this.dragged = 1; 1162 } else if (this.dragged === 1 && this.percentage[0] > percentage) { 1163 this.percentage[1] = this.percentage[0]; 1164 this.dragged = 0; 1165 } 1166 } 1167 }, 1168 _mouseup: function() { 1169 if(!this.options.enabled) { 1170 return false; 1171 } 1172 if (this.touchCapable) { 1173 // Touch: Unbind touch event handlers: 1174 document.removeEventListener("touchmove", this.mousemove, false); 1175 document.removeEventListener("touchend", this.mouseup, false); 1176 } 1177 // Unbind mouse event handlers: 1178 document.removeEventListener("mousemove", this.mousemove, false); 1179 document.removeEventListener("mouseup", this.mouseup, false); 1180 1181 this.inDrag = false;
1182 if (this.over === false) { 1183 this._hideTooltip(); 1184 } 1185 var val = this._calculateValue(true); 1186 1187 this._layout(); 1188 this._trigger('slideStop', val); 1189 this._setDataVal(val); 1190 1191 return false; 1192 }, 1193 _calculateValue: function(snapToClosestTick) { 1194 var val; 1195 if (this.options.range) { 1196 val = [this.options.min,this.options.max]; 1197 if (this.percentage[0] !== 0){ 1198 val[0] = this._toValue(this.percentage[0]); 1199 val[0] = this._applyPrecision(val[0]); 1200 } 1201 if (this.percentage[1] !== 100){ 1202 val[1] = this._toValue(this.percentage[1]); 1203 val[1] = this._applyPrecision(val[1]); 1204 } 1205 } else { 1206 val = this._toValue(this.percentage[0]); 1207 val = parseFloat(val); 1208 val = this._applyPrecision(val); 1209 } 1210 1211 if (snapToClosestTick) { 1212 var min = [val, Infinity]; 1213 for (var i = 0; i < this.options.ticks.length; i++) { 1214 var diff = Math.abs(this.options.ticks[i] - val); 1215 if (diff <= min[1]) { 1216 min = [this.options.ticks[i], diff]; 1217 } 1218 } 1219 if (min[1] <= this.options.ticks_snap_bounds) { 1220 return min[0]; 1221 } 1222 } 1223 1224 return val; 1225 }, 1226 _applyPrecision: function(val) { 1227 var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step); 1228 return this._applyToFixedAndParseFloat(val, precision); 1229 }, 1230 _getNumDigitsAfterDecimalPlace: function(num) { 1231 var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); 1232 if (!match) { return 0; } 1233 return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0)); 1234 }, 1235 _applyToFixedAndParseFloat: function(num, toFixedInput) { 1236 var truncatedNum = num.toFixed(toFixedInput); 1237 return parseFloat(truncatedNum); 1238 }, 1239 /* 1240 Credits to Mike Samuel for the following method! 1241 Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number 1242 */ 1243 _getPercentage: function(ev) { 1244 if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) { 1245 ev = ev.touches[0]; 1246 } 1247 var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size; 1248 percentage = Math.round(percentage/this.percentage[2])*this.percentage[2]; 1249 return Math.max(0, Math.min(100, percentage)); 1250 }, 1251 _validateInputValue: function(val) { 1252 if (typeof val === 'number') { 1253 return val; 1254 } else if (Array.isArray(val)) { 1255 this._validateArray(val); 1256 return val; 1257 } else { 1258 throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(val) ); 1259 } 1260 }, 1261 _validateArray: function(val) { 1262 for(var i = 0; i < val.length; i++) { 1263 var input = val[i]; 1264 if (typeof input !== 'number') { throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(input) ); } 1265 } 1266 }, 1267 _setDataVal: function(val) { 1268 var value = "value: '" + val + "'"; 1269 this.element.setAttribute('data', value); 1270 this.element.setAttribute('value', val); 1271 this.element.value = val; 1272 }, 1273 _trigger: function(evt, val) { 1274 val = (val || val === 0) ? val : undefined; 1275 1276 var callbackFnArray = this.eventToCallbackMap[evt]; 1277 if(callbackFnArray && callbackFnArray.length) { 1278 for(var i = 0; i < callbackFnArray.length; i++) { 1279 var callbackFn = callbackFnArray[i]; 1280 callbackFn(val); 1281 } 1282 } 1283 1284 /* If JQuery exists, trigger JQuery events */ 1285 if($) { 1286 this._triggerJQueryEvent(evt, val); 1287 } 1288 }, 1289 _triggerJQueryEvent: function(evt, val) { 1290 var eventData = { 1291 type: evt, 1292 value: val 1293 }; 1294 this.$element.trigger(eventData); 1295 this.$sliderElem.trigger(eventData); 1296 }, 1297 _unbindJQueryEventHandlers: function() { 1298 this.$element.off(); 1299 this.$sliderElem.off(); 1300 }, 1301 _setText: function(element, text) { 1302 if(typeof element.innerText !== "undefined") { 1303 element.innerText = text; 1304 } else if(typeof element.textContent !== "undefined") { 1305 element.textContent = text; 1306 } 1307 }, 1308 _removeClass: function(element, classString) { 1309 var classes = classString.split(" "); 1310 var newClasses = element.className; 1311
1312 for(var i = 0; i < classes.length; i++) { 1313 var classTag = classes[i]; 1314 var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)"); 1315 newClasses = newClasses.replace(regex, " "); 1316 } 1317 1318 element.className = newClasses.trim(); 1319 }, 1320 _addClass: function(element, classString) { 1321 var classes = classString.split(" "); 1322 var newClasses = element.className; 1323 1324 for(var i = 0; i < classes.length; i++) { 1325 var classTag = classes[i]; 1326 var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)"); 1327 var ifClassExists = regex.test(newClasses); 1328 1329 if(!ifClassExists) { 1330 newClasses += " " + classTag; 1331 } 1332 } 1333 1334 element.className = newClasses.trim(); 1335 }, 1336 _offset: function (obj) { 1337 var rect = obj.getBoundingClientRect(), 1338 ol = rect.left, 1339 ot = rect.top; 1340 1341 return { 1342 left: ol, 1343 top: ot 1344 }; 1345 }, 1346 _css: function(elementRef, styleName, value) { 1347 if ($) { 1348 $.style(elementRef, styleName, value); 1349 } else { 1350 var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) { 1351 return letter.toUpperCase(); 1352 }); 1353 elementRef.style[style] = value; 1354 } 1355 }, 1356 _toValue: function(percentage) { 1357 return this.options.scale.toValue.apply(this, [percentage]); 1358 }, 1359 _toPercentage: function(value) { 1360 return this.options.scale.toPercentage.apply(this, [value]); 1361 } 1362 1363 }; 1364 1365 /********************************* 1366 1367 Attach to global namespace 1368 1369 *********************************/ 1370 if($) { 1371 var namespace = $.fn.slider ? 'bootstrapSlider' : 'slider'; 1372 $.bridget(namespace, Slider); 1373 } 1374 1375 })( $ ); 1376 1377 return Slider; 1378}));
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.