balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

perfect-scrollbar.js (35321B)


      1 /*!
      2  * perfect-scrollbar v1.4.0
      3  * (c) 2018 Hyunje Jun
      4  * @license MIT
      5  */
      6 (function (global, factory) {
      7 	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
      8 	typeof define === 'function' && define.amd ? define(factory) :
      9 	(global.PerfectScrollbar = factory());
     10 }(this, (function () { 'use strict';
     11 
     12 function get(element) {
     13   return getComputedStyle(element);
     14 }
     15 
     16 function set(element, obj) {
     17   for (var key in obj) {
     18     var val = obj[key];
     19     if (typeof val === 'number') {
     20       val = val + "px";
     21     }
     22     element.style[key] = val;
     23   }
     24   return element;
     25 }
     26 
     27 function div(className) {
     28   var div = document.createElement('div');
     29   div.className = className;
     30   return div;
     31 }
     32 
     33 var elMatches =
     34   typeof Element !== 'undefined' &&
     35   (Element.prototype.matches ||
     36     Element.prototype.webkitMatchesSelector ||
     37     Element.prototype.mozMatchesSelector ||
     38     Element.prototype.msMatchesSelector);
     39 
     40 function matches(element, query) {
     41   if (!elMatches) {
     42     throw new Error('No element matching method supported');
     43   }
     44 
     45   return elMatches.call(element, query);
     46 }
     47 
     48 function remove(element) {
     49   if (element.remove) {
     50     element.remove();
     51   } else {
     52     if (element.parentNode) {
     53       element.parentNode.removeChild(element);
     54     }
     55   }
     56 }
     57 
     58 function queryChildren(element, selector) {
     59   return Array.prototype.filter.call(element.children, function (child) { return matches(child, selector); }
     60   );
     61 }
     62 
     63 var cls = {
     64   main: 'ps',
     65   element: {
     66     thumb: function (x) { return ("ps__thumb-" + x); },
     67     rail: function (x) { return ("ps__rail-" + x); },
     68     consuming: 'ps__child--consume',
     69   },
     70   state: {
     71     focus: 'ps--focus',
     72     clicking: 'ps--clicking',
     73     active: function (x) { return ("ps--active-" + x); },
     74     scrolling: function (x) { return ("ps--scrolling-" + x); },
     75   },
     76 };
     77 
     78 /*
     79  * Helper methods
     80  */
     81 var scrollingClassTimeout = { x: null, y: null };
     82 
     83 function addScrollingClass(i, x) {
     84   var classList = i.element.classList;
     85   var className = cls.state.scrolling(x);
     86 
     87   if (classList.contains(className)) {
     88     clearTimeout(scrollingClassTimeout[x]);
     89   } else {
     90     classList.add(className);
     91   }
     92 }
     93 
     94 function removeScrollingClass(i, x) {
     95   scrollingClassTimeout[x] = setTimeout(
     96     function () { return i.isAlive && i.element.classList.remove(cls.state.scrolling(x)); },
     97     i.settings.scrollingThreshold
     98   );
     99 }
    100 
    101 function setScrollingClassInstantly(i, x) {
    102   addScrollingClass(i, x);
    103   removeScrollingClass(i, x);
    104 }
    105 
    106 var EventElement = function EventElement(element) {
    107   this.element = element;
    108   this.handlers = {};
    109 };
    110 
    111 var prototypeAccessors = { isEmpty: { configurable: true } };
    112 
    113 EventElement.prototype.bind = function bind (eventName, handler) {
    114   if (typeof this.handlers[eventName] === 'undefined') {
    115     this.handlers[eventName] = [];
    116   }
    117   this.handlers[eventName].push(handler);
    118   this.element.addEventListener(eventName, handler, false);
    119 };
    120 
    121 EventElement.prototype.unbind = function unbind (eventName, target) {
    122     var this$1 = this;
    123 
    124   this.handlers[eventName] = this.handlers[eventName].filter(function (handler) {
    125     if (target && handler !== target) {
    126       return true;
    127     }
    128     this$1.element.removeEventListener(eventName, handler, false);
    129     return false;
    130   });
    131 };
    132 
    133 EventElement.prototype.unbindAll = function unbindAll () {
    134     var this$1 = this;
    135 
    136   for (var name in this$1.handlers) {
    137     this$1.unbind(name);
    138   }
    139 };
    140 
    141 prototypeAccessors.isEmpty.get = function () {
    142     var this$1 = this;
    143 
    144   return Object.keys(this.handlers).every(
    145     function (key) { return this$1.handlers[key].length === 0; }
    146   );
    147 };
    148 
    149 Object.defineProperties( EventElement.prototype, prototypeAccessors );
    150 
    151 var EventManager = function EventManager() {
    152   this.eventElements = [];
    153 };
    154 
    155 EventManager.prototype.eventElement = function eventElement (element) {
    156   var ee = this.eventElements.filter(function (ee) { return ee.element === element; })[0];
    157   if (!ee) {
    158     ee = new EventElement(element);
    159     this.eventElements.push(ee);
    160   }
    161   return ee;
    162 };
    163 
    164 EventManager.prototype.bind = function bind (element, eventName, handler) {
    165   this.eventElement(element).bind(eventName, handler);
    166 };
    167 
    168 EventManager.prototype.unbind = function unbind (element, eventName, handler) {
    169   var ee = this.eventElement(element);
    170   ee.unbind(eventName, handler);
    171 
    172   if (ee.isEmpty) {
    173     // remove
    174     this.eventElements.splice(this.eventElements.indexOf(ee), 1);
    175   }
    176 };
    177 
    178 EventManager.prototype.unbindAll = function unbindAll () {
    179   this.eventElements.forEach(function (e) { return e.unbindAll(); });
    180   this.eventElements = [];
    181 };
    182 
    183 EventManager.prototype.once = function once (element, eventName, handler) {
    184   var ee = this.eventElement(element);
    185   var onceHandler = function (evt) {
    186     ee.unbind(eventName, onceHandler);
    187     handler(evt);
    188   };
    189   ee.bind(eventName, onceHandler);
    190 };
    191 
    192 function createEvent(name) {
    193   if (typeof window.CustomEvent === 'function') {
    194     return new CustomEvent(name);
    195   } else {
    196     var evt = document.createEvent('CustomEvent');
    197     evt.initCustomEvent(name, false, false, undefined);
    198     return evt;
    199   }
    200 }
    201 
    202 var processScrollDiff = function(
    203   i,
    204   axis,
    205   diff,
    206   useScrollingClass,
    207   forceFireReachEvent
    208 ) {
    209   if ( useScrollingClass === void 0 ) useScrollingClass = true;
    210   if ( forceFireReachEvent === void 0 ) forceFireReachEvent = false;
    211 
    212   var fields;
    213   if (axis === 'top') {
    214     fields = [
    215       'contentHeight',
    216       'containerHeight',
    217       'scrollTop',
    218       'y',
    219       'up',
    220       'down' ];
    221   } else if (axis === 'left') {
    222     fields = [
    223       'contentWidth',
    224       'containerWidth',
    225       'scrollLeft',
    226       'x',
    227       'left',
    228       'right' ];
    229   } else {
    230     throw new Error('A proper axis should be provided');
    231   }
    232 
    233   processScrollDiff$1(i, diff, fields, useScrollingClass, forceFireReachEvent);
    234 };
    235 
    236 function processScrollDiff$1(
    237   i,
    238   diff,
    239   ref,
    240   useScrollingClass,
    241   forceFireReachEvent
    242 ) {
    243   var contentHeight = ref[0];
    244   var containerHeight = ref[1];
    245   var scrollTop = ref[2];
    246   var y = ref[3];
    247   var up = ref[4];
    248   var down = ref[5];
    249   if ( useScrollingClass === void 0 ) useScrollingClass = true;
    250   if ( forceFireReachEvent === void 0 ) forceFireReachEvent = false;
    251 
    252   var element = i.element;
    253 
    254   // reset reach
    255   i.reach[y] = null;
    256 
    257   // 1 for subpixel rounding
    258   if (element[scrollTop] < 1) {
    259     i.reach[y] = 'start';
    260   }
    261 
    262   // 1 for subpixel rounding
    263   if (element[scrollTop] > i[contentHeight] - i[containerHeight] - 1) {
    264     i.reach[y] = 'end';
    265   }
    266 
    267   if (diff) {
    268     element.dispatchEvent(createEvent(("ps-scroll-" + y)));
    269 
    270     if (diff < 0) {
    271       element.dispatchEvent(createEvent(("ps-scroll-" + up)));
    272     } else if (diff > 0) {
    273       element.dispatchEvent(createEvent(("ps-scroll-" + down)));
    274     }
    275 
    276     if (useScrollingClass) {
    277       setScrollingClassInstantly(i, y);
    278     }
    279   }
    280 
    281   if (i.reach[y] && (diff || forceFireReachEvent)) {
    282     element.dispatchEvent(createEvent(("ps-" + y + "-reach-" + (i.reach[y]))));
    283   }
    284 }
    285 
    286 function toInt(x) {
    287   return parseInt(x, 10) || 0;
    288 }
    289 
    290 function isEditable(el) {
    291   return (
    292     matches(el, 'input,[contenteditable]') ||
    293     matches(el, 'select,[contenteditable]') ||
    294     matches(el, 'textarea,[contenteditable]') ||
    295     matches(el, 'button,[contenteditable]')
    296   );
    297 }
    298 
    299 function outerWidth(element) {
    300   var styles = get(element);
    301   return (
    302     toInt(styles.width) +
    303     toInt(styles.paddingLeft) +
    304     toInt(styles.paddingRight) +
    305     toInt(styles.borderLeftWidth) +
    306     toInt(styles.borderRightWidth)
    307   );
    308 }
    309 
    310 var env = {
    311   isWebKit:
    312     typeof document !== 'undefined' &&
    313     'WebkitAppearance' in document.documentElement.style,
    314   supportsTouch:
    315     typeof window !== 'undefined' &&
    316     ('ontouchstart' in window ||
    317       (window.DocumentTouch && document instanceof window.DocumentTouch)),
    318   supportsIePointer:
    319     typeof navigator !== 'undefined' && navigator.msMaxTouchPoints,
    320   isChrome:
    321     typeof navigator !== 'undefined' &&
    322     /Chrome/i.test(navigator && navigator.userAgent),
    323 };
    324 
    325 var updateGeometry = function(i) {
    326   var element = i.element;
    327   var roundedScrollTop = Math.floor(element.scrollTop);
    328 
    329   i.containerWidth = element.clientWidth;
    330   i.containerHeight = element.clientHeight;
    331   i.contentWidth = element.scrollWidth;
    332   i.contentHeight = element.scrollHeight;
    333 
    334   if (!element.contains(i.scrollbarXRail)) {
    335     // clean up and append
    336     queryChildren(element, cls.element.rail('x')).forEach(function (el) { return remove(el); }
    337     );
    338     element.appendChild(i.scrollbarXRail);
    339   }
    340   if (!element.contains(i.scrollbarYRail)) {
    341     // clean up and append
    342     queryChildren(element, cls.element.rail('y')).forEach(function (el) { return remove(el); }
    343     );
    344     element.appendChild(i.scrollbarYRail);
    345   }
    346 
    347   if (
    348     !i.settings.suppressScrollX &&
    349     i.containerWidth + i.settings.scrollXMarginOffset < i.contentWidth
    350   ) {
    351     i.scrollbarXActive = true;
    352     i.railXWidth = i.containerWidth - i.railXMarginWidth;
    353     i.railXRatio = i.containerWidth / i.railXWidth;
    354     i.scrollbarXWidth = getThumbSize(
    355       i,
    356       toInt(i.railXWidth * i.containerWidth / i.contentWidth)
    357     );
    358     i.scrollbarXLeft = toInt(
    359       (i.negativeScrollAdjustment + element.scrollLeft) *
    360         (i.railXWidth - i.scrollbarXWidth) /
    361         (i.contentWidth - i.containerWidth)
    362     );
    363   } else {
    364     i.scrollbarXActive = false;
    365   }
    366 
    367   if (
    368     !i.settings.suppressScrollY &&
    369     i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight
    370   ) {
    371     i.scrollbarYActive = true;
    372     i.railYHeight = i.containerHeight - i.railYMarginHeight;
    373     i.railYRatio = i.containerHeight / i.railYHeight;
    374     i.scrollbarYHeight = getThumbSize(
    375       i,
    376       toInt(i.railYHeight * i.containerHeight / i.contentHeight)
    377     );
    378     i.scrollbarYTop = toInt(
    379       roundedScrollTop *
    380         (i.railYHeight - i.scrollbarYHeight) /
    381         (i.contentHeight - i.containerHeight)
    382     );
    383   } else {
    384     i.scrollbarYActive = false;
    385   }
    386 
    387   if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
    388     i.scrollbarXLeft = i.railXWidth - i.scrollbarXWidth;
    389   }
    390   if (i.scrollbarYTop >= i.railYHeight - i.scrollbarYHeight) {
    391     i.scrollbarYTop = i.railYHeight - i.scrollbarYHeight;
    392   }
    393 
    394   updateCss(element, i);
    395 
    396   if (i.scrollbarXActive) {
    397     element.classList.add(cls.state.active('x'));
    398   } else {
    399     element.classList.remove(cls.state.active('x'));
    400     i.scrollbarXWidth = 0;
    401     i.scrollbarXLeft = 0;
    402     element.scrollLeft = 0;
    403   }
    404   if (i.scrollbarYActive) {
    405     element.classList.add(cls.state.active('y'));
    406   } else {
    407     element.classList.remove(cls.state.active('y'));
    408     i.scrollbarYHeight = 0;
    409     i.scrollbarYTop = 0;
    410     element.scrollTop = 0;
    411   }
    412 };
    413 
    414 function getThumbSize(i, thumbSize) {
    415   if (i.settings.minScrollbarLength) {
    416     thumbSize = Math.max(thumbSize, i.settings.minScrollbarLength);
    417   }
    418   if (i.settings.maxScrollbarLength) {
    419     thumbSize = Math.min(thumbSize, i.settings.maxScrollbarLength);
    420   }
    421   return thumbSize;
    422 }
    423 
    424 function updateCss(element, i) {
    425   var xRailOffset = { width: i.railXWidth };
    426   var roundedScrollTop = Math.floor(element.scrollTop);
    427 
    428   if (i.isRtl) {
    429     xRailOffset.left =
    430       i.negativeScrollAdjustment +
    431       element.scrollLeft +
    432       i.containerWidth -
    433       i.contentWidth;
    434   } else {
    435     xRailOffset.left = element.scrollLeft;
    436   }
    437   if (i.isScrollbarXUsingBottom) {
    438     xRailOffset.bottom = i.scrollbarXBottom - roundedScrollTop;
    439   } else {
    440     xRailOffset.top = i.scrollbarXTop + roundedScrollTop;
    441   }
    442   set(i.scrollbarXRail, xRailOffset);
    443 
    444   var yRailOffset = { top: roundedScrollTop, height: i.railYHeight };
    445   if (i.isScrollbarYUsingRight) {
    446     if (i.isRtl) {
    447       yRailOffset.right =
    448         i.contentWidth -
    449         (i.negativeScrollAdjustment + element.scrollLeft) -
    450         i.scrollbarYRight -
    451         i.scrollbarYOuterWidth;
    452     } else {
    453       yRailOffset.right = i.scrollbarYRight - element.scrollLeft;
    454     }
    455   } else {
    456     if (i.isRtl) {
    457       yRailOffset.left =
    458         i.negativeScrollAdjustment +
    459         element.scrollLeft +
    460         i.containerWidth * 2 -
    461         i.contentWidth -
    462         i.scrollbarYLeft -
    463         i.scrollbarYOuterWidth;
    464     } else {
    465       yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;
    466     }
    467   }
    468   set(i.scrollbarYRail, yRailOffset);
    469 
    470   set(i.scrollbarX, {
    471     left: i.scrollbarXLeft,
    472     width: i.scrollbarXWidth - i.railBorderXWidth,
    473   });
    474   set(i.scrollbarY, {
    475     top: i.scrollbarYTop,
    476     height: i.scrollbarYHeight - i.railBorderYWidth,
    477   });
    478 }
    479 
    480 var clickRail = function(i) {
    481   i.event.bind(i.scrollbarY, 'mousedown', function (e) { return e.stopPropagation(); });
    482   i.event.bind(i.scrollbarYRail, 'mousedown', function (e) {
    483     var positionTop =
    484       e.pageY -
    485       window.pageYOffset -
    486       i.scrollbarYRail.getBoundingClientRect().top;
    487     var direction = positionTop > i.scrollbarYTop ? 1 : -1;
    488 
    489     i.element.scrollTop += direction * i.containerHeight;
    490     updateGeometry(i);
    491 
    492     e.stopPropagation();
    493   });
    494 
    495   i.event.bind(i.scrollbarX, 'mousedown', function (e) { return e.stopPropagation(); });
    496   i.event.bind(i.scrollbarXRail, 'mousedown', function (e) {
    497     var positionLeft =
    498       e.pageX -
    499       window.pageXOffset -
    500       i.scrollbarXRail.getBoundingClientRect().left;
    501     var direction = positionLeft > i.scrollbarXLeft ? 1 : -1;
    502 
    503     i.element.scrollLeft += direction * i.containerWidth;
    504     updateGeometry(i);
    505 
    506     e.stopPropagation();
    507   });
    508 };
    509 
    510 var dragThumb = function(i) {
    511   bindMouseScrollHandler(i, [
    512     'containerWidth',
    513     'contentWidth',
    514     'pageX',
    515     'railXWidth',
    516     'scrollbarX',
    517     'scrollbarXWidth',
    518     'scrollLeft',
    519     'x',
    520     'scrollbarXRail' ]);
    521   bindMouseScrollHandler(i, [
    522     'containerHeight',
    523     'contentHeight',
    524     'pageY',
    525     'railYHeight',
    526     'scrollbarY',
    527     'scrollbarYHeight',
    528     'scrollTop',
    529     'y',
    530     'scrollbarYRail' ]);
    531 };
    532 
    533 function bindMouseScrollHandler(
    534   i,
    535   ref
    536 ) {
    537   var containerHeight = ref[0];
    538   var contentHeight = ref[1];
    539   var pageY = ref[2];
    540   var railYHeight = ref[3];
    541   var scrollbarY = ref[4];
    542   var scrollbarYHeight = ref[5];
    543   var scrollTop = ref[6];
    544   var y = ref[7];
    545   var scrollbarYRail = ref[8];
    546 
    547   var element = i.element;
    548 
    549   var startingScrollTop = null;
    550   var startingMousePageY = null;
    551   var scrollBy = null;
    552 
    553   function mouseMoveHandler(e) {
    554     element[scrollTop] =
    555       startingScrollTop + scrollBy * (e[pageY] - startingMousePageY);
    556     addScrollingClass(i, y);
    557     updateGeometry(i);
    558 
    559     e.stopPropagation();
    560     e.preventDefault();
    561   }
    562 
    563   function mouseUpHandler() {
    564     removeScrollingClass(i, y);
    565     i[scrollbarYRail].classList.remove(cls.state.clicking);
    566     i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
    567   }
    568 
    569   i.event.bind(i[scrollbarY], 'mousedown', function (e) {
    570     startingScrollTop = element[scrollTop];
    571     startingMousePageY = e[pageY];
    572     scrollBy =
    573       (i[contentHeight] - i[containerHeight]) /
    574       (i[railYHeight] - i[scrollbarYHeight]);
    575 
    576     i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
    577     i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
    578 
    579     i[scrollbarYRail].classList.add(cls.state.clicking);
    580 
    581     e.stopPropagation();
    582     e.preventDefault();
    583   });
    584 }
    585 
    586 var keyboard = function(i) {
    587   var element = i.element;
    588 
    589   var elementHovered = function () { return matches(element, ':hover'); };
    590   var scrollbarFocused = function () { return matches(i.scrollbarX, ':focus') || matches(i.scrollbarY, ':focus'); };
    591 
    592   function shouldPreventDefault(deltaX, deltaY) {
    593     var scrollTop = Math.floor(element.scrollTop);
    594     if (deltaX === 0) {
    595       if (!i.scrollbarYActive) {
    596         return false;
    597       }
    598       if (
    599         (scrollTop === 0 && deltaY > 0) ||
    600         (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)
    601       ) {
    602         return !i.settings.wheelPropagation;
    603       }
    604     }
    605 
    606     var scrollLeft = element.scrollLeft;
    607     if (deltaY === 0) {
    608       if (!i.scrollbarXActive) {
    609         return false;
    610       }
    611       if (
    612         (scrollLeft === 0 && deltaX < 0) ||
    613         (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)
    614       ) {
    615         return !i.settings.wheelPropagation;
    616       }
    617     }
    618     return true;
    619   }
    620 
    621   i.event.bind(i.ownerDocument, 'keydown', function (e) {
    622     if (
    623       (e.isDefaultPrevented && e.isDefaultPrevented()) ||
    624       e.defaultPrevented
    625     ) {
    626       return;
    627     }
    628 
    629     if (!elementHovered() && !scrollbarFocused()) {
    630       return;
    631     }
    632 
    633     var activeElement = document.activeElement
    634       ? document.activeElement
    635       : i.ownerDocument.activeElement;
    636     if (activeElement) {
    637       if (activeElement.tagName === 'IFRAME') {
    638         activeElement = activeElement.contentDocument.activeElement;
    639       } else {
    640         // go deeper if element is a webcomponent
    641         while (activeElement.shadowRoot) {
    642           activeElement = activeElement.shadowRoot.activeElement;
    643         }
    644       }
    645       if (isEditable(activeElement)) {
    646         return;
    647       }
    648     }
    649 
    650     var deltaX = 0;
    651     var deltaY = 0;
    652 
    653     switch (e.which) {
    654       case 37: // left
    655         if (e.metaKey) {
    656           deltaX = -i.contentWidth;
    657         } else if (e.altKey) {
    658           deltaX = -i.containerWidth;
    659         } else {
    660           deltaX = -30;
    661         }
    662         break;
    663       case 38: // up
    664         if (e.metaKey) {
    665           deltaY = i.contentHeight;
    666         } else if (e.altKey) {
    667           deltaY = i.containerHeight;
    668         } else {
    669           deltaY = 30;
    670         }
    671         break;
    672       case 39: // right
    673         if (e.metaKey) {
    674           deltaX = i.contentWidth;
    675         } else if (e.altKey) {
    676           deltaX = i.containerWidth;
    677         } else {
    678           deltaX = 30;
    679         }
    680         break;
    681       case 40: // down
    682         if (e.metaKey) {
    683           deltaY = -i.contentHeight;
    684         } else if (e.altKey) {
    685           deltaY = -i.containerHeight;
    686         } else {
    687           deltaY = -30;
    688         }
    689         break;
    690       case 32: // space bar
    691         if (e.shiftKey) {
    692           deltaY = i.containerHeight;
    693         } else {
    694           deltaY = -i.containerHeight;
    695         }
    696         break;
    697       case 33: // page up
    698         deltaY = i.containerHeight;
    699         break;
    700       case 34: // page down
    701         deltaY = -i.containerHeight;
    702         break;
    703       case 36: // home
    704         deltaY = i.contentHeight;
    705         break;
    706       case 35: // end
    707         deltaY = -i.contentHeight;
    708         break;
    709       default:
    710         return;
    711     }
    712 
    713     if (i.settings.suppressScrollX && deltaX !== 0) {
    714       return;
    715     }
    716     if (i.settings.suppressScrollY && deltaY !== 0) {
    717       return;
    718     }
    719 
    720     element.scrollTop -= deltaY;
    721     element.scrollLeft += deltaX;
    722     updateGeometry(i);
    723 
    724     if (shouldPreventDefault(deltaX, deltaY)) {
    725       e.preventDefault();
    726     }
    727   });
    728 };
    729 
    730 var wheel = function(i) {
    731   var element = i.element;
    732 
    733   function shouldPreventDefault(deltaX, deltaY) {
    734     var roundedScrollTop = Math.floor(element.scrollTop);
    735     var isTop = element.scrollTop === 0;
    736     var isBottom =
    737       roundedScrollTop + element.offsetHeight === element.scrollHeight;
    738     var isLeft = element.scrollLeft === 0;
    739     var isRight =
    740       element.scrollLeft + element.offsetWidth === element.scrollWidth;
    741 
    742     var hitsBound;
    743 
    744     // pick axis with primary direction
    745     if (Math.abs(deltaY) > Math.abs(deltaX)) {
    746       hitsBound = isTop || isBottom;
    747     } else {
    748       hitsBound = isLeft || isRight;
    749     }
    750 
    751     return hitsBound ? !i.settings.wheelPropagation : true;
    752   }
    753 
    754   function getDeltaFromEvent(e) {
    755     var deltaX = e.deltaX;
    756     var deltaY = -1 * e.deltaY;
    757 
    758     if (typeof deltaX === 'undefined' || typeof deltaY === 'undefined') {
    759       // OS X Safari
    760       deltaX = -1 * e.wheelDeltaX / 6;
    761       deltaY = e.wheelDeltaY / 6;
    762     }
    763 
    764     if (e.deltaMode && e.deltaMode === 1) {
    765       // Firefox in deltaMode 1: Line scrolling
    766       deltaX *= 10;
    767       deltaY *= 10;
    768     }
    769 
    770     if (deltaX !== deltaX && deltaY !== deltaY /* NaN checks */) {
    771       // IE in some mouse drivers
    772       deltaX = 0;
    773       deltaY = e.wheelDelta;
    774     }
    775 
    776     if (e.shiftKey) {
    777       // reverse axis with shift key
    778       return [-deltaY, -deltaX];
    779     }
    780     return [deltaX, deltaY];
    781   }
    782 
    783   function shouldBeConsumedByChild(target, deltaX, deltaY) {
    784     // FIXME: this is a workaround for <select> issue in FF and IE #571
    785     if (!env.isWebKit && element.querySelector('select:focus')) {
    786       return true;
    787     }
    788 
    789     if (!element.contains(target)) {
    790       return false;
    791     }
    792 
    793     var cursor = target;
    794 
    795     while (cursor && cursor !== element) {
    796       if (cursor.classList.contains(cls.element.consuming)) {
    797         return true;
    798       }
    799 
    800       var style = get(cursor);
    801       var overflow = [style.overflow, style.overflowX, style.overflowY].join(
    802         ''
    803       );
    804 
    805       // if scrollable
    806       if (overflow.match(/(scroll|auto)/)) {
    807         var maxScrollTop = cursor.scrollHeight - cursor.clientHeight;
    808         if (maxScrollTop > 0) {
    809           if (
    810             !(cursor.scrollTop === 0 && deltaY > 0) &&
    811             !(cursor.scrollTop === maxScrollTop && deltaY < 0)
    812           ) {
    813             return true;
    814           }
    815         }
    816         var maxScrollLeft = cursor.scrollWidth - cursor.clientWidth;
    817         if (maxScrollLeft > 0) {
    818           if (
    819             !(cursor.scrollLeft === 0 && deltaX < 0) &&
    820             !(cursor.scrollLeft === maxScrollLeft && deltaX > 0)
    821           ) {
    822             return true;
    823           }
    824         }
    825       }
    826 
    827       cursor = cursor.parentNode;
    828     }
    829 
    830     return false;
    831   }
    832 
    833   function mousewheelHandler(e) {
    834     var ref = getDeltaFromEvent(e);
    835     var deltaX = ref[0];
    836     var deltaY = ref[1];
    837 
    838     if (shouldBeConsumedByChild(e.target, deltaX, deltaY)) {
    839       return;
    840     }
    841 
    842     var shouldPrevent = false;
    843     if (!i.settings.useBothWheelAxes) {
    844       // deltaX will only be used for horizontal scrolling and deltaY will
    845       // only be used for vertical scrolling - this is the default
    846       element.scrollTop -= deltaY * i.settings.wheelSpeed;
    847       element.scrollLeft += deltaX * i.settings.wheelSpeed;
    848     } else if (i.scrollbarYActive && !i.scrollbarXActive) {
    849       // only vertical scrollbar is active and useBothWheelAxes option is
    850       // active, so let's scroll vertical bar using both mouse wheel axes
    851       if (deltaY) {
    852         element.scrollTop -= deltaY * i.settings.wheelSpeed;
    853       } else {
    854         element.scrollTop += deltaX * i.settings.wheelSpeed;
    855       }
    856       shouldPrevent = true;
    857     } else if (i.scrollbarXActive && !i.scrollbarYActive) {
    858       // useBothWheelAxes and only horizontal bar is active, so use both
    859       // wheel axes for horizontal bar
    860       if (deltaX) {
    861         element.scrollLeft += deltaX * i.settings.wheelSpeed;
    862       } else {
    863         element.scrollLeft -= deltaY * i.settings.wheelSpeed;
    864       }
    865       shouldPrevent = true;
    866     }
    867 
    868     updateGeometry(i);
    869 
    870     shouldPrevent = shouldPrevent || shouldPreventDefault(deltaX, deltaY);
    871     if (shouldPrevent && !e.ctrlKey) {
    872       e.stopPropagation();
    873       e.preventDefault();
    874     }
    875   }
    876 
    877   if (typeof window.onwheel !== 'undefined') {
    878     i.event.bind(element, 'wheel', mousewheelHandler);
    879   } else if (typeof window.onmousewheel !== 'undefined') {
    880     i.event.bind(element, 'mousewheel', mousewheelHandler);
    881   }
    882 };
    883 
    884 var touch = function(i) {
    885   if (!env.supportsTouch && !env.supportsIePointer) {
    886     return;
    887   }
    888 
    889   var element = i.element;
    890 
    891   function shouldPrevent(deltaX, deltaY) {
    892     var scrollTop = Math.floor(element.scrollTop);
    893     var scrollLeft = element.scrollLeft;
    894     var magnitudeX = Math.abs(deltaX);
    895     var magnitudeY = Math.abs(deltaY);
    896 
    897     if (magnitudeY > magnitudeX) {
    898       // user is perhaps trying to swipe up/down the page
    899 
    900       if (
    901         (deltaY < 0 && scrollTop === i.contentHeight - i.containerHeight) ||
    902         (deltaY > 0 && scrollTop === 0)
    903       ) {
    904         // set prevent for mobile Chrome refresh
    905         return window.scrollY === 0 && deltaY > 0 && env.isChrome;
    906       }
    907     } else if (magnitudeX > magnitudeY) {
    908       // user is perhaps trying to swipe left/right across the page
    909 
    910       if (
    911         (deltaX < 0 && scrollLeft === i.contentWidth - i.containerWidth) ||
    912         (deltaX > 0 && scrollLeft === 0)
    913       ) {
    914         return true;
    915       }
    916     }
    917 
    918     return true;
    919   }
    920 
    921   function applyTouchMove(differenceX, differenceY) {
    922     element.scrollTop -= differenceY;
    923     element.scrollLeft -= differenceX;
    924 
    925     updateGeometry(i);
    926   }
    927 
    928   var startOffset = {};
    929   var startTime = 0;
    930   var speed = {};
    931   var easingLoop = null;
    932 
    933   function getTouch(e) {
    934     if (e.targetTouches) {
    935       return e.targetTouches[0];
    936     } else {
    937       // Maybe IE pointer
    938       return e;
    939     }
    940   }
    941 
    942   function shouldHandle(e) {
    943     if (e.pointerType && e.pointerType === 'pen' && e.buttons === 0) {
    944       return false;
    945     }
    946     if (e.targetTouches && e.targetTouches.length === 1) {
    947       return true;
    948     }
    949     if (
    950       e.pointerType &&
    951       e.pointerType !== 'mouse' &&
    952       e.pointerType !== e.MSPOINTER_TYPE_MOUSE
    953     ) {
    954       return true;
    955     }
    956     return false;
    957   }
    958 
    959   function touchStart(e) {
    960     if (!shouldHandle(e)) {
    961       return;
    962     }
    963 
    964     var touch = getTouch(e);
    965 
    966     startOffset.pageX = touch.pageX;
    967     startOffset.pageY = touch.pageY;
    968 
    969     startTime = new Date().getTime();
    970 
    971     if (easingLoop !== null) {
    972       clearInterval(easingLoop);
    973     }
    974   }
    975 
    976   function shouldBeConsumedByChild(target, deltaX, deltaY) {
    977     if (!element.contains(target)) {
    978       return false;
    979     }
    980 
    981     var cursor = target;
    982 
    983     while (cursor && cursor !== element) {
    984       if (cursor.classList.contains(cls.element.consuming)) {
    985         return true;
    986       }
    987 
    988       var style = get(cursor);
    989       var overflow = [style.overflow, style.overflowX, style.overflowY].join(
    990         ''
    991       );
    992 
    993       // if scrollable
    994       if (overflow.match(/(scroll|auto)/)) {
    995         var maxScrollTop = cursor.scrollHeight - cursor.clientHeight;
    996         if (maxScrollTop > 0) {
    997           if (
    998             !(cursor.scrollTop === 0 && deltaY > 0) &&
    999             !(cursor.scrollTop === maxScrollTop && deltaY < 0)
   1000           ) {
   1001             return true;
   1002           }
   1003         }
   1004         var maxScrollLeft = cursor.scrollLeft - cursor.clientWidth;
   1005         if (maxScrollLeft > 0) {
   1006           if (
   1007             !(cursor.scrollLeft === 0 && deltaX < 0) &&
   1008             !(cursor.scrollLeft === maxScrollLeft && deltaX > 0)
   1009           ) {
   1010             return true;
   1011           }
   1012         }
   1013       }
   1014 
   1015       cursor = cursor.parentNode;
   1016     }
   1017 
   1018     return false;
   1019   }
   1020 
   1021   function touchMove(e) {
   1022     if (shouldHandle(e)) {
   1023       var touch = getTouch(e);
   1024 
   1025       var currentOffset = { pageX: touch.pageX, pageY: touch.pageY };
   1026 
   1027       var differenceX = currentOffset.pageX - startOffset.pageX;
   1028       var differenceY = currentOffset.pageY - startOffset.pageY;
   1029 
   1030       if (shouldBeConsumedByChild(e.target, differenceX, differenceY)) {
   1031         return;
   1032       }
   1033 
   1034       applyTouchMove(differenceX, differenceY);
   1035       startOffset = currentOffset;
   1036 
   1037       var currentTime = new Date().getTime();
   1038 
   1039       var timeGap = currentTime - startTime;
   1040       if (timeGap > 0) {
   1041         speed.x = differenceX / timeGap;
   1042         speed.y = differenceY / timeGap;
   1043         startTime = currentTime;
   1044       }
   1045 
   1046       if (shouldPrevent(differenceX, differenceY)) {
   1047         e.preventDefault();
   1048       }
   1049     }
   1050   }
   1051   function touchEnd() {
   1052     if (i.settings.swipeEasing) {
   1053       clearInterval(easingLoop);
   1054       easingLoop = setInterval(function() {
   1055         if (i.isInitialized) {
   1056           clearInterval(easingLoop);
   1057           return;
   1058         }
   1059 
   1060         if (!speed.x && !speed.y) {
   1061           clearInterval(easingLoop);
   1062           return;
   1063         }
   1064 
   1065         if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
   1066           clearInterval(easingLoop);
   1067           return;
   1068         }
   1069 
   1070         applyTouchMove(speed.x * 30, speed.y * 30);
   1071 
   1072         speed.x *= 0.8;
   1073         speed.y *= 0.8;
   1074       }, 10);
   1075     }
   1076   }
   1077 
   1078   if (env.supportsTouch) {
   1079     i.event.bind(element, 'touchstart', touchStart);
   1080     i.event.bind(element, 'touchmove', touchMove);
   1081     i.event.bind(element, 'touchend', touchEnd);
   1082   } else if (env.supportsIePointer) {
   1083     if (window.PointerEvent) {
   1084       i.event.bind(element, 'pointerdown', touchStart);
   1085       i.event.bind(element, 'pointermove', touchMove);
   1086       i.event.bind(element, 'pointerup', touchEnd);
   1087     } else if (window.MSPointerEvent) {
   1088       i.event.bind(element, 'MSPointerDown', touchStart);
   1089       i.event.bind(element, 'MSPointerMove', touchMove);
   1090       i.event.bind(element, 'MSPointerUp', touchEnd);
   1091     }
   1092   }
   1093 };
   1094 
   1095 var defaultSettings = function () { return ({
   1096   handlers: ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'],
   1097   maxScrollbarLength: null,
   1098   minScrollbarLength: null,
   1099   scrollingThreshold: 1000,
   1100   scrollXMarginOffset: 0,
   1101   scrollYMarginOffset: 0,
   1102   suppressScrollX: false,
   1103   suppressScrollY: false,
   1104   swipeEasing: true,
   1105   useBothWheelAxes: false,
   1106   wheelPropagation: true,
   1107   wheelSpeed: 1,
   1108 }); };
   1109 
   1110 var handlers = {
   1111   'click-rail': clickRail,
   1112   'drag-thumb': dragThumb,
   1113   keyboard: keyboard,
   1114   wheel: wheel,
   1115   touch: touch,
   1116 };
   1117 
   1118 var PerfectScrollbar = function PerfectScrollbar(element, userSettings) {
   1119   var this$1 = this;
   1120   if ( userSettings === void 0 ) userSettings = {};
   1121 
   1122   if (typeof element === 'string') {
   1123     element = document.querySelector(element);
   1124   }
   1125 
   1126   if (!element || !element.nodeName) {
   1127     throw new Error('no element is specified to initialize PerfectScrollbar');
   1128   }
   1129 
   1130   this.element = element;
   1131 
   1132   element.classList.add(cls.main);
   1133 
   1134   this.settings = defaultSettings();
   1135   for (var key in userSettings) {
   1136     this$1.settings[key] = userSettings[key];
   1137   }
   1138 
   1139   this.containerWidth = null;
   1140   this.containerHeight = null;
   1141   this.contentWidth = null;
   1142   this.contentHeight = null;
   1143 
   1144   var focus = function () { return element.classList.add(cls.state.focus); };
   1145   var blur = function () { return element.classList.remove(cls.state.focus); };
   1146 
   1147   this.isRtl = get(element).direction === 'rtl';
   1148   this.isNegativeScroll = (function () {
   1149     var originalScrollLeft = element.scrollLeft;
   1150     var result = null;
   1151     element.scrollLeft = -1;
   1152     result = element.scrollLeft < 0;
   1153     element.scrollLeft = originalScrollLeft;
   1154     return result;
   1155   })();
   1156   this.negativeScrollAdjustment = this.isNegativeScroll
   1157     ? element.scrollWidth - element.clientWidth
   1158     : 0;
   1159   this.event = new EventManager();
   1160   this.ownerDocument = element.ownerDocument || document;
   1161 
   1162   this.scrollbarXRail = div(cls.element.rail('x'));
   1163   element.appendChild(this.scrollbarXRail);
   1164   this.scrollbarX = div(cls.element.thumb('x'));
   1165   this.scrollbarXRail.appendChild(this.scrollbarX);
   1166   this.scrollbarX.setAttribute('tabindex', 0);
   1167   this.event.bind(this.scrollbarX, 'focus', focus);
   1168   this.event.bind(this.scrollbarX, 'blur', blur);
   1169   this.scrollbarXActive = null;
   1170   this.scrollbarXWidth = null;
   1171   this.scrollbarXLeft = null;
   1172   var railXStyle = get(this.scrollbarXRail);
   1173   this.scrollbarXBottom = parseInt(railXStyle.bottom, 10);
   1174   if (isNaN(this.scrollbarXBottom)) {
   1175     this.isScrollbarXUsingBottom = false;
   1176     this.scrollbarXTop = toInt(railXStyle.top);
   1177   } else {
   1178     this.isScrollbarXUsingBottom = true;
   1179   }
   1180   this.railBorderXWidth =
   1181     toInt(railXStyle.borderLeftWidth) + toInt(railXStyle.borderRightWidth);
   1182   // Set rail to display:block to calculate margins
   1183   set(this.scrollbarXRail, { display: 'block' });
   1184   this.railXMarginWidth =
   1185     toInt(railXStyle.marginLeft) + toInt(railXStyle.marginRight);
   1186   set(this.scrollbarXRail, { display: '' });
   1187   this.railXWidth = null;
   1188   this.railXRatio = null;
   1189 
   1190   this.scrollbarYRail = div(cls.element.rail('y'));
   1191   element.appendChild(this.scrollbarYRail);
   1192   this.scrollbarY = div(cls.element.thumb('y'));
   1193   this.scrollbarYRail.appendChild(this.scrollbarY);
   1194   this.scrollbarY.setAttribute('tabindex', 0);
   1195   this.event.bind(this.scrollbarY, 'focus', focus);
   1196   this.event.bind(this.scrollbarY, 'blur', blur);
   1197   this.scrollbarYActive = null;
   1198   this.scrollbarYHeight = null;
   1199   this.scrollbarYTop = null;
   1200   var railYStyle = get(this.scrollbarYRail);
   1201   this.scrollbarYRight = parseInt(railYStyle.right, 10);
   1202   if (isNaN(this.scrollbarYRight)) {
   1203     this.isScrollbarYUsingRight = false;
   1204     this.scrollbarYLeft = toInt(railYStyle.left);
   1205   } else {
   1206     this.isScrollbarYUsingRight = true;
   1207   }
   1208   this.scrollbarYOuterWidth = this.isRtl ? outerWidth(this.scrollbarY) : null;
   1209   this.railBorderYWidth =
   1210     toInt(railYStyle.borderTopWidth) + toInt(railYStyle.borderBottomWidth);
   1211   set(this.scrollbarYRail, { display: 'block' });
   1212   this.railYMarginHeight =
   1213     toInt(railYStyle.marginTop) + toInt(railYStyle.marginBottom);
   1214   set(this.scrollbarYRail, { display: '' });
   1215   this.railYHeight = null;
   1216   this.railYRatio = null;
   1217 
   1218   this.reach = {
   1219     x:
   1220       element.scrollLeft <= 0
   1221         ? 'start'
   1222         : element.scrollLeft >= this.contentWidth - this.containerWidth
   1223           ? 'end'
   1224           : null,
   1225     y:
   1226       element.scrollTop <= 0
   1227         ? 'start'
   1228         : element.scrollTop >= this.contentHeight - this.containerHeight
   1229           ? 'end'
   1230           : null,
   1231   };
   1232 
   1233   this.isAlive = true;
   1234 
   1235   this.settings.handlers.forEach(function (handlerName) { return handlers[handlerName](this$1); });
   1236 
   1237   this.lastScrollTop = Math.floor(element.scrollTop); // for onScroll only
   1238   this.lastScrollLeft = element.scrollLeft; // for onScroll only
   1239   this.event.bind(this.element, 'scroll', function (e) { return this$1.onScroll(e); });
   1240   updateGeometry(this);
   1241 };
   1242 
   1243 PerfectScrollbar.prototype.update = function update () {
   1244   if (!this.isAlive) {
   1245     return;
   1246   }
   1247 
   1248   // Recalcuate negative scrollLeft adjustment
   1249   this.negativeScrollAdjustment = this.isNegativeScroll
   1250     ? this.element.scrollWidth - this.element.clientWidth
   1251     : 0;
   1252 
   1253   // Recalculate rail margins
   1254   set(this.scrollbarXRail, { display: 'block' });
   1255   set(this.scrollbarYRail, { display: 'block' });
   1256   this.railXMarginWidth =
   1257     toInt(get(this.scrollbarXRail).marginLeft) +
   1258     toInt(get(this.scrollbarXRail).marginRight);
   1259   this.railYMarginHeight =
   1260     toInt(get(this.scrollbarYRail).marginTop) +
   1261     toInt(get(this.scrollbarYRail).marginBottom);
   1262 
   1263   // Hide scrollbars not to affect scrollWidth and scrollHeight
   1264   set(this.scrollbarXRail, { display: 'none' });
   1265   set(this.scrollbarYRail, { display: 'none' });
   1266 
   1267   updateGeometry(this);
   1268 
   1269   processScrollDiff(this, 'top', 0, false, true);
   1270   processScrollDiff(this, 'left', 0, false, true);
   1271 
   1272   set(this.scrollbarXRail, { display: '' });
   1273   set(this.scrollbarYRail, { display: '' });
   1274 };
   1275 
   1276 PerfectScrollbar.prototype.onScroll = function onScroll (e) {
   1277   if (!this.isAlive) {
   1278     return;
   1279   }
   1280 
   1281   updateGeometry(this);
   1282   processScrollDiff(this, 'top', this.element.scrollTop - this.lastScrollTop);
   1283   processScrollDiff(
   1284     this,
   1285     'left',
   1286     this.element.scrollLeft - this.lastScrollLeft
   1287   );
   1288 
   1289   this.lastScrollTop = Math.floor(this.element.scrollTop);
   1290   this.lastScrollLeft = this.element.scrollLeft;
   1291 };
   1292 
   1293 PerfectScrollbar.prototype.destroy = function destroy () {
   1294   if (!this.isAlive) {
   1295     return;
   1296   }
   1297 
   1298   this.event.unbindAll();
   1299   remove(this.scrollbarX);
   1300   remove(this.scrollbarY);
   1301   remove(this.scrollbarXRail);
   1302   remove(this.scrollbarYRail);
   1303   this.removePsClasses();
   1304 
   1305   // unset elements
   1306   this.element = null;
   1307   this.scrollbarX = null;
   1308   this.scrollbarY = null;
   1309   this.scrollbarXRail = null;
   1310   this.scrollbarYRail = null;
   1311 
   1312   this.isAlive = false;
   1313 };
   1314 
   1315 PerfectScrollbar.prototype.removePsClasses = function removePsClasses () {
   1316   this.element.className = this.element.className
   1317     .split(' ')
   1318     .filter(function (name) { return !name.match(/^ps([-_].+|)$/); })
   1319     .join(' ');
   1320 };
   1321 
   1322 return PerfectScrollbar;
   1323 
   1324 })));