1/*! perfect-scrollbar - v0.4.11 2* http://noraesae.github.com/perfect-scrollbar/ 3* Copyright (c) 2014 Hyeonje Alex Jun; Licensed MIT 4* 5* Edited by Rik de Vos (www.rikdevos.com) 6* 7*/ 8(function (factory) { 9 'use strict'; 10 11 if (typeof define === 'function' && define.amd) { 12 // AMD. Register as an anonymous module. 13 define(['jquery'], factory); 14 } else if (typeof exports === 'object') { 15 // Node/CommonJS 16 factory(require('jquery')); 17 } else { 18 // Browser globals 19 factory(jQuery); 20 } 21}(function ($) { 22 'use strict'; 23 24 // The default settings for the plugin 25 var defaultSettings = { 26 wheelSpeed: 10, 27 wheelPropagation: false, 28 minScrollbarLength: null, 29 maxScrollbarLength: null, 30 useBothWheelAxes: false, 31 useKeyboard: true, 32 suppressScrollX: false, 33 suppressScrollY: false, 34 scrollXMarginOffset: 0, 35 scrollYMarginOffset: 0, 36 includePadding: false 37 }; 38 39 var getEventClassName = (function () { 40 var incrementingId = 0; 41 return function () { 42 var id = incrementingId; 43 incrementingId += 1; 44 return '.perfect-scrollbar-' + id; 45 }; 46 }()); 47 48 $.fn.perfectScrollbar = function (suppliedSettings, option) { 49 50 return this.each(function () { 51 // Use the default settings 52 var settings = $.extend(true, {}, defaultSettings), 53 $this = $(this); 54 55 if (typeof suppliedSettings === "object") { 56 // But over-ride any supplied 57 $.extend(true, settings, suppliedSettings); 58 } else { 59 // If no settings were supplied, then the first param must be the option 60 option = suppliedSettings; 61 } 62 63 // Catch options 64 65 if (option === 'update') { 66 if ($this.data('perfect-scrollbar-update')) { 67 $this.data('perfect-scrollbar-update')(); 68 } 69 return $this; 70 } 71 else if (option === 'destroy') { 72 if ($this.data('perfect-scrollbar-destroy')) { 73 $this.data('perfect-scrollbar-destroy')(); 74 } 75 return $this; 76 } 77 78 if ($this.data('perfect-scrollbar')) { 79 // if there's already perfect-scrollbar 80 return $this.data('perfect-scrollbar'); 81 } 82 83 84 // Or generate new perfectScrollbar 85 86 // Set class to the container 87 $this.addClass('ps-container'); 88 89 var $scrollbarXRail = $("<div class='ps-scrollbar-x-rail'></div>").appendTo($this), 90 $scrollbarYRail = $("<div class='ps-scrollbar-y-rail'></div>").appendTo($this), 91 $scrollbarX = $("<div class='ps-scrollbar-x'></div>").appendTo($scrollbarXRail), 92 $scrollbarY = $("<div class='ps-scrollbar-y'></div>").appendTo($scrollbarYRail), 93 scrollbarXActive, 94 scrollbarYActive, 95 containerWidth, 96 containerHeight, 97 contentWidth, 98 contentHeight, 99 scrollbarXWidth, 100 scrollbarXLeft, 101 scrollbarXBottom = parseInt($scrollbarXRail.css('bottom'), 10), 102 isScrollbarXUsingBottom = scrollbarXBottom === scrollbarXBottom, // !isNaN 103 scrollbarXTop = isScrollbarXUsingBottom ? null : parseInt($scrollbarXRail.css('top'), 10), 104 scrollbarYHeight, 105 scrollbarYTop, 106 scrollbarYRight = parseInt($scrollbarYRail.css('right'), 10), 107 isScrollbarYUsingRight = scrollbarYRight === scrollbarYRight, // !isNaN 108 scrollbarYLeft = isScrollbarYUsingRight ? null: parseInt($scrollbarYRail.css('left'), 10), 109 isRtl = $this.css('direction') === "rtl", 110 eventClassName = getEventClassName(), 111 railBorderXWidth = parseInt($scrollbarXRail.css('borderLeftWidth'), 10) + parseInt($scrollbarXRail.css('borderRightWidth'), 10), 112 railBorderYWidth = parseInt($scrollbarXRail.css('borderTopWidth'), 10) + parseInt($scrollbarXRail.css('borderBottomWidth'), 10); 113 114 var updateContentScrollTop = function (currentTop, deltaY) { 115 var newTop = currentTop + deltaY, 116 maxTop = containerHeight - scrollbarYHeight; 117 118 if (newTop < 0) { 119 scrollbarYTop = 0; 120 } 121 else if (newTop > maxTop) { 122 scrollbarYTop = maxTop; 123 } 124 else { 125 scrollbarYTop = newTop; 126 } 127 128 var scrollTop = parseInt(scrollbarYTop * (contentHeight - containerHeight) / (containerHeight - scrollbarYHeight), 10); 129 $this.scrollTop(scrollTop); 130 }; 131 132 var updateContentScrollLeft = function (currentLeft, deltaX) { 133 var newLeft = currentLeft + deltaX, 134 maxLeft = containerWidth - scrollbarXWidth; 135 136 if (newLeft < 0) { 137 scrollbarXLeft = 0; 138 } 139 else if (newLeft > maxLeft) { 140 scrollbarXLeft = maxLeft; 141 } 142 else { 143 scrollbarXLeft = newLeft; 144 } 145 146 var scrollLeft = parseInt(scrollbarXLeft * (contentWidth - containerWidth) / (containerWidth - scrollbarXWidth), 10); 147 $this.scrollLeft(scrollLeft); 148 }; 149 150 var getSettingsAdjustedThumbSize = function (thumbSize) { 151 if (settings.minScrollbarLength) { 152 thumbSize = Math.max(thumbSize, settings.minScrollbarLength); 153 } 154 if (settings.maxScrollbarLength) { 155 thumbSize = Math.min(thumbSize, settings.maxScrollbarLength); 156 } 157 return thumbSize; 158 }; 159 160 var updateScrollbarCss = function () { 161 var scrollbarXStyles = {width: containerWidth, display: scrollbarXActive ? "inherit": "none"}; 162 if (isRtl) { 163 scrollbarXStyles.left = $this.scrollLeft() + containerWidth - contentWidth; 164 } else { 165 scrollbarXStyles.left = $this.scrollLeft(); 166 } 167 if (isScrollbarXUsingBottom) { 168 scrollbarXStyles.bottom = scrollbarXBottom - $this.scrollTop(); 169 } else { 170 scrollbarXStyles.top = scrollbarXTop + $this.scrollTop(); 171 } 172 $scrollbarXRail.css(scrollbarXStyles); 173 174 var scrollbarYStyles = {top: $this.scrollTop(), height: containerHeight, display: scrollbarYActive ? "inherit": "none"}; 175 176 if (isScrollbarYUsingRight) { 177 if (isRtl) { 178 scrollbarYStyles.right = contentWidth - $this.scrollLeft() - scrollbarYRight - $scrollbarY.outerWidth(); 179 } else { 180 scrollbarYStyles.right = scrollbarYRight - $this.scrollLeft(); 181 } 182 } else { 183 if (isRtl) { 184 scrollbarYStyles.left = $this.scrollLeft() + containerWidth * 2 - contentWidth - scrollbarYLeft - $scrollbarY.outerWidth(); 185 } else { 186 scrollbarYStyles.left = scrollbarYLeft + $this.scrollLeft(); 187 } 188 } 189 $scrollbarYRail.css(scrollbarYStyles); 190 191 $scrollbarX.css({left: scrollbarXLeft, width: scrollbarXWidth - railBorderXWidth}); 192 $scrollbarY.css({top: scrollbarYTop, height: scrollbarYHeight - railBorderYWidth}); 193 194 if (scrollbarXActive) { 195 $this.addClass('ps-active-x'); 196 } else { 197 $this.removeClass('ps-active-x'); 198 } 199 200 if (scrollbarYActive) { 201 $this.addClass('ps-active-y'); 202 } else { 203 $this.removeClass('ps-active-y'); 204 } 205 }; 206 207 var updateBarSizeAndPosition = function () { 208 containerWidth = settings.includePadding ? $this.innerWidth() : $this.width(); 209 containerHeight = settings.includePadding ? $this.innerHeight() : $this.height(); 210 contentWidth = $this.prop('scrollWidth'); 211 contentHeight = $this.prop('scrollHeight'); 212 213 if (!settings.suppressScrollX && containerWidth + settings.scrollXMarginOffset < contentWidth) { 214 scrollbarXActive = true; 215 scrollbarXWidth = getSettingsAdjustedThumbSize(parseInt(containerWidth * containerWidth / contentWidth, 10)); 216 scrollbarXLeft = parseInt($this.scrollLeft() * (containerWidth - scrollbarXWidth) / (contentWidth - containerWidth), 10); 217 } 218 else { 219 scrollbarXActive = false;
220 scrollbarXWidth = 0; 221 scrollbarXLeft = 0; 222 $this.scrollLeft(0); 223 } 224 225 if (!settings.suppressScrollY && containerHeight + settings.scrollYMarginOffset < contentHeight) { 226 scrollbarYActive = true; 227 scrollbarYHeight = getSettingsAdjustedThumbSize(parseInt(containerHeight * containerHeight / contentHeight, 10)); 228 scrollbarYTop = parseInt($this.scrollTop() * (containerHeight - scrollbarYHeight) / (contentHeight - containerHeight), 10); 229 } 230 else { 231 scrollbarYActive = false; 232 scrollbarYHeight = 0; 233 scrollbarYTop = 0; 234 $this.scrollTop(0); 235 } 236 237 if (scrollbarYTop >= containerHeight - scrollbarYHeight) { 238 scrollbarYTop = containerHeight - scrollbarYHeight; 239 } 240 if (scrollbarXLeft >= containerWidth - scrollbarXWidth) { 241 scrollbarXLeft = containerWidth - scrollbarXWidth; 242 } 243 244 updateScrollbarCss(); 245 }; 246 247 var bindMouseScrollXHandler = function () { 248 var currentLeft, 249 currentPageX; 250 251 $scrollbarX.bind('mousedown' + eventClassName, function (e) { 252 currentPageX = e.pageX; 253 currentLeft = $scrollbarX.position().left; 254 $scrollbarXRail.addClass('in-scrolling'); 255 e.stopPropagation(); 256 e.preventDefault(); 257 }); 258 259 $(document).bind('mousemove' + eventClassName, function (e) { 260 if ($scrollbarXRail.hasClass('in-scrolling')) { 261 updateContentScrollLeft(currentLeft, e.pageX - currentPageX); 262 updateBarSizeAndPosition(); 263 e.stopPropagation(); 264 e.preventDefault(); 265 } 266 }); 267 268 $(document).bind('mouseup' + eventClassName, function (e) { 269 if ($scrollbarXRail.hasClass('in-scrolling')) { 270 $scrollbarXRail.removeClass('in-scrolling'); 271 } 272 }); 273 274 currentLeft = 275 currentPageX = null; 276 }; 277 278 var bindMouseScrollYHandler = function () { 279 var currentTop, 280 currentPageY; 281 282 $scrollbarY.bind('mousedown' + eventClassName, function (e) { 283 currentPageY = e.pageY; 284 currentTop = $scrollbarY.position().top; 285 $scrollbarYRail.addClass('in-scrolling'); 286 e.stopPropagation(); 287 e.preventDefault(); 288 }); 289 290 $(document).bind('mousemove' + eventClassName, function (e) { 291 if ($scrollbarYRail.hasClass('in-scrolling')) { 292 updateContentScrollTop(currentTop, e.pageY - currentPageY); 293 updateBarSizeAndPosition(); 294 e.stopPropagation(); 295 e.preventDefault(); 296 } 297 }); 298 299 $(document).bind('mouseup' + eventClassName, function (e) { 300 if ($scrollbarYRail.hasClass('in-scrolling')) { 301 $scrollbarYRail.removeClass('in-scrolling'); 302 } 303 }); 304 305 currentTop = 306 currentPageY = null; 307 }; 308 309 // check if the default scrolling should be prevented. 310 var shouldPreventDefault = function (deltaX, deltaY) { 311 var scrollTop = $this.scrollTop(); 312 if (deltaX === 0) { 313 if (!scrollbarYActive) { 314 return false; 315 } 316 if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= contentHeight - containerHeight && deltaY < 0)) { 317 return !settings.wheelPropagation; 318 } 319 } 320 321 var scrollLeft = $this.scrollLeft(); 322 if (deltaY === 0) { 323 if (!scrollbarXActive) { 324 return false; 325 } 326 if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= contentWidth - containerWidth && deltaX > 0)) { 327 return !settings.wheelPropagation; 328 } 329 } 330 return true; 331 }; 332 333 // bind handlers 334 var bindMouseWheelHandler = function () { 335 // FIXME: Backward compatibility. 336 // After e.deltaFactor applied, wheelSpeed should have smaller value. 337 // Currently, there's no way to change the settings after the scrollbar initialized. 338 // But if the way is implemented in the future, wheelSpeed should be reset. 339 settings.wheelSpeed /= 10; 340 341 var shouldPrevent = false;
342 $this.bind('mousewheel' + eventClassName, function (e, deprecatedDelta, deprecatedDeltaX, deprecatedDeltaY) { 343 var deltaX = e.deltaX * e.deltaFactor || deprecatedDeltaX, 344 deltaY = e.deltaY * e.deltaFactor || deprecatedDeltaY; 345 346 shouldPrevent = false; 347 if (!settings.useBothWheelAxes) { 348 // deltaX will only be used for horizontal scrolling and deltaY will 349 // only be used for vertical scrolling - this is the default 350 $this.scrollTop($this.scrollTop() - (deltaY * settings.wheelSpeed)); 351 $this.scrollLeft($this.scrollLeft() + (deltaX * settings.wheelSpeed)); 352 } else if (scrollbarYActive && !scrollbarXActive) { 353 // only vertical scrollbar is active and useBothWheelAxes option is 354 // active, so let's scroll vertical bar using both mouse wheel axes 355 if (deltaY) { 356 $this.scrollTop($this.scrollTop() - (deltaY * settings.wheelSpeed)); 357 } else { 358 $this.scrollTop($this.scrollTop() + (deltaX * settings.wheelSpeed)); 359 } 360 shouldPrevent = true; 361 } else if (scrollbarXActive && !scrollbarYActive) { 362 // useBothWheelAxes and only horizontal bar is active, so use both 363 // wheel axes for horizontal bar 364 if (deltaX) { 365 $this.scrollLeft($this.scrollLeft() + (deltaX * settings.wheelSpeed)); 366 } else { 367 $this.scrollLeft($this.scrollLeft() - (deltaY * settings.wheelSpeed)); 368 } 369 shouldPrevent = true; 370 } 371 372 // update bar position 373 updateBarSizeAndPosition(); 374 375 shouldPrevent = (shouldPrevent || shouldPreventDefault(deltaX, deltaY)); 376 if (shouldPrevent) { 377 e.stopPropagation(); 378 e.preventDefault(); 379 } 380 }); 381 382 // fix Firefox scroll problem 383 $this.bind('MozMousePixelScroll' + eventClassName, function (e) { 384 if (shouldPrevent) { 385 e.preventDefault(); 386 } 387 }); 388 }; 389 390 var bindKeyboardHandler = function () { 391 var hovered = false; 392 $this.bind('mouseenter' + eventClassName, function (e) { 393 hovered = true; 394 }); 395 $this.bind('mouseleave' + eventClassName, function (e) { 396 hovered = false; 397 }); 398 399 var shouldPrevent = false; 400 $(document).bind('keydown' + eventClassName, function (e) { 401 if (e.isDefaultPrevented && e.isDefaultPrevented()) { 402 return; 403 } 404 405 if (!hovered || $(document.activeElement).is(":input,[contenteditable]")) { 406 return; 407 } 408 409 var deltaX = 0, 410 deltaY = 0; 411 412 switch (e.which) { 413 case 37: // left 414 deltaX = -30; 415 break; 416 case 38: // up 417 deltaY = 30; 418 break; 419 case 39: // right 420 deltaX = 30; 421 break; 422 case 40: // down 423 deltaY = -30; 424 break; 425 case 33: // page up 426 deltaY = 90; 427 break; 428 case 32: // space bar 429 case 34: // page down 430 deltaY = -90; 431 break; 432 case 35: // end 433 deltaY = -containerHeight; 434 break; 435 case 36: // home 436 deltaY = containerHeight; 437 break; 438 default: 439 return; 440 } 441 442 $this.scrollTop($this.scrollTop() - deltaY); 443 $this.scrollLeft($this.scrollLeft() + deltaX); 444 445 shouldPrevent = shouldPreventDefault(deltaX, deltaY); 446 if (shouldPrevent) { 447 e.preventDefault(); 448 } 449 }); 450 }; 451 452 var bindRailClickHandler = function () { 453 var stopPropagation = function (e) { e.stopPropagation(); }; 454 455 $scrollbarY.bind('click' + eventClassName, stopPropagation); 456 $scrollbarYRail.bind('click' + eventClassName, function (e) { 457 var halfOfScrollbarLength = parseInt(scrollbarYHeight / 2, 10), 458 positionTop = e.pageY - $scrollbarYRail.offset().top - halfOfScrollbarLength, 459 maxPositionTop = containerHeight - scrollbarYHeight, 460 positionRatio = positionTop / maxPositionTop; 461 462 if (positionRatio < 0) { 463 positionRatio = 0; 464 } else if (positionRatio > 1) { 465 positionRatio = 1; 466 } 467 468 $this.scrollTop((contentHeight - containerHeight) * positionRatio); 469 }); 470
471 $scrollbarX.bind('click' + eventClassName, stopPropagation); 472 $scrollbarXRail.bind('click' + eventClassName, function (e) { 473 var halfOfScrollbarLength = parseInt(scrollbarXWidth / 2, 10), 474 positionLeft = e.pageX - $scrollbarXRail.offset().left - halfOfScrollbarLength, 475 maxPositionLeft = containerWidth - scrollbarXWidth, 476 positionRatio = positionLeft / maxPositionLeft; 477 478 if (positionRatio < 0) { 479 positionRatio = 0; 480 } else if (positionRatio > 1) { 481 positionRatio = 1; 482 } 483 484 $this.scrollLeft((contentWidth - containerWidth) * positionRatio); 485 }); 486 }; 487 488 // bind mobile touch handler 489 var bindMobileTouchHandler = function () { 490 var applyTouchMove = function (differenceX, differenceY) { 491 if(isNaN(differenceY) || differenceY == NaN || !differenceY) { 492 return; 493 } 494 $this.scrollTop($this.scrollTop() - differenceY); 495 $this.scrollLeft($this.scrollLeft() - differenceX); 496 497 // update bar position 498 updateBarSizeAndPosition(); 499 }; 500 501 var startCoords = {}, 502 startTime = 0, 503 speed = {}, 504 breakingProcess = null, 505 inGlobalTouch = false; 506 507 $(window).bind("touchstart" + eventClassName, function (e) { 508 inGlobalTouch = true; 509 }); 510 $(window).bind("touchend" + eventClassName, function (e) { 511 inGlobalTouch = false; 512 }); 513 514 $this.bind("touchstart" + eventClassName, function (e) { 515 var touch = e.originalEvent.targetTouches[0]; 516 517 startCoords.pageX = touch.pageX; 518 startCoords.pageY = touch.pageY; 519 520 startTime = (new Date()).getTime(); 521 522 if (breakingProcess !== null) { 523 clearInterval(breakingProcess); 524 } 525 526 e.stopPropagation(); 527 }); 528 $this.bind("touchmove" + eventClassName, function (e) { 529 if (!inGlobalTouch && e.originalEvent.targetTouches.length === 1) { 530 var touch = e.originalEvent.targetTouches[0]; 531 532 var currentCoords = {}; 533 currentCoords.pageX = touch.pageX; 534 currentCoords.pageY = touch.pageY; 535
536 var differenceX = currentCoords.pageX - startCoords.pageX, 537 differenceY = currentCoords.pageY - startCoords.pageY; 538 539 applyTouchMove(differenceX, differenceY); 540 startCoords = currentCoords; 541 542 var currentTime = (new Date()).getTime(); 543 544 var timeGap = currentTime - startTime; 545 if (timeGap > 0) { 546 speed.x = differenceX / timeGap; 547 speed.y = differenceY / timeGap; 548 startTime = currentTime; 549 } 550 551 e.preventDefault(); 552 } 553 }); 554 $this.bind("touchend" + eventClassName, function (e) { 555 clearInterval(breakingProcess); 556 breakingProcess = setInterval(function () { 557 if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) { 558 clearInterval(breakingProcess); 559 return; 560 } 561 562 applyTouchMove(speed.x * 30, speed.y * 30); 563 564 speed.x *= 0.8; 565 speed.y *= 0.8; 566 }, 10); 567 }); 568 }; 569 570 var bindScrollHandler = function () { 571 $this.bind('scroll' + eventClassName, function (e) { 572 updateBarSizeAndPosition(); 573 }); 574 }; 575 576 var destroy = function () { 577 $this.unbind(eventClassName); 578 $(window).unbind(eventClassName); 579 $(document).unbind(eventClassName); 580 $this.data('perfect-scrollbar', null); 581 $this.data('perfect-scrollbar-update', null); 582 $this.data('perfect-scrollbar-destroy', null); 583 $scrollbarX.remove(); 584 $scrollbarY.remove(); 585 $scrollbarXRail.remove(); 586 $scrollbarYRail.remove(); 587 588 // clean all variables 589 $scrollbarXRail = 590 $scrollbarYRail = 591 $scrollbarX = 592 $scrollbarY = 593 scrollbarXActive = 594 scrollbarYActive = 595 containerWidth = 596 containerHeight = 597 contentWidth = 598 contentHeight = 599 scrollbarXWidth = 600 scrollbarXLeft = 601 scrollbarXBottom = 602 isScrollbarXUsingBottom = 603 scrollbarXTop = 604 scrollbarYHeight = 605 scrollbarYTop = 606 scrollbarYRight = 607 isScrollbarYUsingRight = 608 scrollbarYLeft = 609 isRtl = 610 eventClassName = null; 611 }; 612 613 var ieSupport = function (version) { 614 $this.addClass('ie').addClass('ie' + version); 615 616 var bindHoverHandlers = function () { 617 var mouseenter = function () { 618 $(this).addClass('hover'); 619 }; 620 var mouseleave = function () { 621 $(this).removeClass('hover'); 622 }; 623 $this.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave); 624 $scrollbarXRail.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave); 625 $scrollbarYRail.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave); 626 $scrollbarX.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave); 627 $scrollbarY.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave); 628 }; 629 630 var fixIe6ScrollbarPosition = function () { 631 updateScrollbarCss = function () { 632 var scrollbarXStyles = {left: scrollbarXLeft + $this.scrollLeft(), width: scrollbarXWidth}; 633 if (isScrollbarXUsingBottom) { 634 scrollbarXStyles.bottom = scrollbarXBottom; 635 } else { 636 scrollbarXStyles.top = scrollbarXTop; 637 } 638 $scrollbarX.css(scrollbarXStyles); 639 640 var scrollbarYStyles = {top: scrollbarYTop + $this.scrollTop(), height: scrollbarYHeight}; 641 if (isScrollbarYUsingRight) { 642 scrollbarYStyles.right = scrollbarYRight; 643 } else { 644 scrollbarYStyles.left = scrollbarYLeft; 645 } 646 647 $scrollbarY.css(scrollbarYStyles); 648 $scrollbarX.hide().show(); 649 $scrollbarY.hide().show(); 650 }; 651 }; 652 653 if (version === 6) { 654 bindHoverHandlers(); 655 fixIe6ScrollbarPosition(); 656 } 657 }; 658 659 var supportsTouch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch); 660 661 var initialize = function () { 662 var ieMatch = navigator.userAgent.toLowerCase().match(/(msie) ([\w.]+)/); 663 if (ieMatch && ieMatch[1] === 'msie') { 664 // must be executed at first, because 'ieSupport' may addClass to the container 665 ieSupport(parseInt(ieMatch[2], 10)); 666 } 667 668 updateBarSizeAndPosition(); 669 bindScrollHandler(); 670 bindMouseScrollXHandler(); 671 bindMouseScrollYHandler(); 672 bindRailClickHandler(); 673 if (supportsTouch) { 674 bindMobileTouchHandler(); 675 } 676 if ($this.mousewheel) { 677 bindMouseWheelHandler(); 678 } 679 if (settings.useKeyboard) { 680 bindKeyboardHandler(); 681 } 682 $this.data('perfect-scrollbar', $this); 683 $this.data('perfect-scrollbar-update', updateBarSizeAndPosition); 684 $this.data('perfect-scrollbar-destroy', destroy); 685 }; 686 687 // initialize 688 initialize(); 689 690 return $this; 691 }); 692 }; 693}));
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.