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