scrollbar.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /**
  2. * @fileoverview added by tsickle
  3. * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  4. */
  5. import { Injectable, Inject } from '@angular/core';
  6. import { DOCUMENT } from '@angular/common';
  7. import * as i0 from "@angular/core";
  8. import * as i1 from "@angular/common";
  9. /** @type {?} */
  10. const noop = (/**
  11. * @return {?}
  12. */
  13. () => { });
  14. const ɵ0 = noop;
  15. /**
  16. * Utility to handle the scrollbar.
  17. *
  18. * It allows to compensate the lack of a vertical scrollbar by adding an
  19. * equivalent padding on the right of the body, and to remove this compensation.
  20. */
  21. export class ScrollBar {
  22. /**
  23. * @param {?} _document
  24. */
  25. constructor(_document) {
  26. this._document = _document;
  27. }
  28. /**
  29. * To be called right before a potential vertical scrollbar would be removed:
  30. *
  31. * - if there was a scrollbar, adds some compensation padding to the body
  32. * to keep the same layout as when the scrollbar is there
  33. * - if there was none, there is nothing to do
  34. *
  35. * @return {?} a callback used to revert the compensation (noop if there was none,
  36. * otherwise a function removing the padding)
  37. */
  38. compensate() {
  39. /** @type {?} */
  40. const width = this._getWidth();
  41. return !this._isPresent(width) ? noop : this._adjustBody(width);
  42. }
  43. /**
  44. * Adds a padding of the given width on the right of the body.
  45. *
  46. * @private
  47. * @param {?} scrollbarWidth
  48. * @return {?} a callback used to revert the padding to its previous value
  49. */
  50. _adjustBody(scrollbarWidth) {
  51. /** @type {?} */
  52. const body = this._document.body;
  53. /** @type {?} */
  54. const userSetPaddingStyle = body.style.paddingRight;
  55. /** @type {?} */
  56. const actualPadding = parseFloat(window.getComputedStyle(body)['padding-right']);
  57. body.style['padding-right'] = `${actualPadding + scrollbarWidth}px`;
  58. return (/**
  59. * @return {?}
  60. */
  61. () => body.style['padding-right'] = userSetPaddingStyle);
  62. }
  63. /**
  64. * Tells whether a scrollbar is currently present on the body.
  65. *
  66. * @private
  67. * @param {?} scrollbarWidth
  68. * @return {?} true if scrollbar is present, false otherwise
  69. */
  70. _isPresent(scrollbarWidth) {
  71. /** @type {?} */
  72. const rect = this._document.body.getBoundingClientRect();
  73. /** @type {?} */
  74. const bodyToViewportGap = window.innerWidth - (rect.left + rect.right);
  75. /** @type {?} */
  76. const uncertainty = 0.1 * scrollbarWidth;
  77. return bodyToViewportGap >= scrollbarWidth - uncertainty;
  78. }
  79. /**
  80. * Calculates and returns the width of a scrollbar.
  81. *
  82. * @private
  83. * @return {?} the width of a scrollbar on this page
  84. */
  85. _getWidth() {
  86. /** @type {?} */
  87. const measurer = this._document.createElement('div');
  88. measurer.className = 'modal-scrollbar-measure';
  89. /** @type {?} */
  90. const body = this._document.body;
  91. body.appendChild(measurer);
  92. /** @type {?} */
  93. const width = measurer.getBoundingClientRect().width - measurer.clientWidth;
  94. body.removeChild(measurer);
  95. return width;
  96. }
  97. }
  98. ScrollBar.decorators = [
  99. { type: Injectable, args: [{ providedIn: 'root' },] }
  100. ];
  101. /** @nocollapse */
  102. ScrollBar.ctorParameters = () => [
  103. { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
  104. ];
  105. /** @nocollapse */ ScrollBar.ngInjectableDef = i0.ɵɵdefineInjectable({ factory: function ScrollBar_Factory() { return new ScrollBar(i0.ɵɵinject(i1.DOCUMENT)); }, token: ScrollBar, providedIn: "root" });
  106. if (false) {
  107. /**
  108. * @type {?}
  109. * @private
  110. */
  111. ScrollBar.prototype._document;
  112. }
  113. export { ɵ0 };
  114. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nyb2xsYmFyLmpzIiwic291cmNlUm9vdCI6Im5nOi8vQG5nLWJvb3RzdHJhcC9uZy1ib290c3RyYXAvIiwic291cmNlcyI6WyJ1dGlsL3Njcm9sbGJhci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDakQsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGlCQUFpQixDQUFDOzs7O01BR25DLElBQUk7OztBQUFHLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQTs7Ozs7Ozs7QUFnQnJCLE1BQU0sT0FBTyxTQUFTOzs7O0lBQ3BCLFlBQXNDLFNBQWM7UUFBZCxjQUFTLEdBQVQsU0FBUyxDQUFLO0lBQUcsQ0FBQzs7Ozs7Ozs7Ozs7SUFZeEQsVUFBVTs7Y0FDRixLQUFLLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRTtRQUM5QixPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2xFLENBQUM7Ozs7Ozs7O0lBT08sV0FBVyxDQUFDLGNBQXNCOztjQUNsQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJOztjQUMxQixtQkFBbUIsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVk7O2NBQzdDLGFBQWEsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ2hGLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLEdBQUcsR0FBRyxhQUFhLEdBQUcsY0FBYyxJQUFJLENBQUM7UUFDcEU7OztRQUFPLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLEdBQUcsbUJBQW1CLEVBQUM7SUFDakUsQ0FBQzs7Ozs7Ozs7SUFPTyxVQUFVLENBQUMsY0FBc0I7O2NBQ2pDLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxxQkFBcUIsRUFBRTs7Y0FDbEQsaUJBQWlCLEdBQUcsTUFBTSxDQUFDLFVBQVUsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQzs7Y0FDaEUsV0FBVyxHQUFHLEdBQUcsR0FBRyxjQUFjO1FBQ3hDLE9BQU8saUJBQWlCLElBQUksY0FBYyxHQUFHLFdBQVcsQ0FBQztJQUMzRCxDQUFDOzs7Ozs7O0lBT08sU0FBUzs7Y0FDVCxRQUFRLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDO1FBQ3BELFFBQVEsQ0FBQyxTQUFTLEdBQUcseUJBQXlCLENBQUM7O2NBRXpDLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUk7UUFDaEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsQ0FBQzs7Y0FDckIsS0FBSyxHQUFHLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsV0FBVztRQUMzRSxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRTNCLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQzs7O1lBM0RGLFVBQVUsU0FBQyxFQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUM7Ozs7NENBRWpCLE1BQU0sU0FBQyxRQUFROzs7Ozs7OztJQUFoQiw4QkFBd0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0luamVjdGFibGUsIEluamVjdH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge0RPQ1VNRU5UfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuXG5cbmNvbnN0IG5vb3AgPSAoKSA9PiB7fTtcblxuXG5cbi8qKiBUeXBlIGZvciB0aGUgY2FsbGJhY2sgdXNlZCB0byByZXZlcnQgdGhlIHNjcm9sbGJhciBjb21wZW5zYXRpb24uICovXG5leHBvcnQgdHlwZSBDb21wZW5zYXRpb25SZXZlcnRlciA9ICgpID0+IHZvaWQ7XG5cblxuXG4vKipcbiAqIFV0aWxpdHkgdG8gaGFuZGxlIHRoZSBzY3JvbGxiYXIuXG4gKlxuICogSXQgYWxsb3dzIHRvIGNvbXBlbnNhdGUgdGhlIGxhY2sgb2YgYSB2ZXJ0aWNhbCBzY3JvbGxiYXIgYnkgYWRkaW5nIGFuXG4gKiBlcXVpdmFsZW50IHBhZGRpbmcgb24gdGhlIHJpZ2h0IG9mIHRoZSBib2R5LCBhbmQgdG8gcmVtb3ZlIHRoaXMgY29tcGVuc2F0aW9uLlxuICovXG5ASW5qZWN0YWJsZSh7cHJvdmlkZWRJbjogJ3Jvb3QnfSlcbmV4cG9ydCBjbGFzcyBTY3JvbGxCYXIge1xuICBjb25zdHJ1Y3RvcihASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIF9kb2N1bWVudDogYW55KSB7fVxuXG4gIC8qKlxuICAgKiBUbyBiZSBjYWxsZWQgcmlnaHQgYmVmb3JlIGEgcG90ZW50aWFsIHZlcnRpY2FsIHNjcm9sbGJhciB3b3VsZCBiZSByZW1vdmVkOlxuICAgKlxuICAgKiAtIGlmIHRoZXJlIHdhcyBhIHNjcm9sbGJhciwgYWRkcyBzb21lIGNvbXBlbnNhdGlvbiBwYWRkaW5nIHRvIHRoZSBib2R5XG4gICAqIHRvIGtlZXAgdGhlIHNhbWUgbGF5b3V0IGFzIHdoZW4gdGhlIHNjcm9sbGJhciBpcyB0aGVyZVxuICAgKiAtIGlmIHRoZXJlIHdhcyBub25lLCB0aGVyZSBpcyBub3RoaW5nIHRvIGRvXG4gICAqXG4gICAqIEByZXR1cm4gYSBjYWxsYmFjayB1c2VkIHRvIHJldmVydCB0aGUgY29tcGVuc2F0aW9uIChub29wIGlmIHRoZXJlIHdhcyBub25lLFxuICAgKiBvdGhlcndpc2UgYSBmdW5jdGlvbiByZW1vdmluZyB0aGUgcGFkZGluZylcbiAgICovXG4gIGNvbXBlbnNhdGUoKTogQ29tcGVuc2F0aW9uUmV2ZXJ0ZXIge1xuICAgIGNvbnN0IHdpZHRoID0gdGhpcy5fZ2V0V2lkdGgoKTtcbiAgICByZXR1cm4gIXRoaXMuX2lzUHJlc2VudCh3aWR0aCkgPyBub29wIDogdGhpcy5fYWRqdXN0Qm9keSh3aWR0aCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHBhZGRpbmcgb2YgdGhlIGdpdmVuIHdpZHRoIG9uIHRoZSByaWdodCBvZiB0aGUgYm9keS5cbiAgICpcbiAgICogQHJldHVybiBhIGNhbGxiYWNrIHVzZWQgdG8gcmV2ZXJ0IHRoZSBwYWRkaW5nIHRvIGl0cyBwcmV2aW91cyB2YWx1ZVxuICAgKi9cbiAgcHJpdmF0ZSBfYWRqdXN0Qm9keShzY3JvbGxiYXJXaWR0aDogbnVtYmVyKTogQ29tcGVuc2F0aW9uUmV2ZXJ0ZXIge1xuICAgIGNvbnN0IGJvZHkgPSB0aGlzLl9kb2N1bWVudC5ib2R5O1xuICAgIGNvbnN0IHVzZXJTZXRQYWRkaW5nU3R5bGUgPSBib2R5LnN0eWxlLnBhZGRpbmdSaWdodDtcbiAgICBjb25zdCBhY3R1YWxQYWRkaW5nID0gcGFyc2VGbG9hdCh3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShib2R5KVsncGFkZGluZy1yaWdodCddKTtcbiAgICBib2R5LnN0eWxlWydwYWRkaW5nLXJpZ2h0J10gPSBgJHthY3R1YWxQYWRkaW5nICsgc2Nyb2xsYmFyV2lkdGh9cHhgO1xuICAgIHJldHVybiAoKSA9PiBib2R5LnN0eWxlWydwYWRkaW5nLXJpZ2h0J10gPSB1c2VyU2V0UGFkZGluZ1N0eWxlO1xuICB9XG5cbiAgLyoqXG4gICAqIFRlbGxzIHdoZXRoZXIgYSBzY3JvbGxiYXIgaXMgY3VycmVudGx5IHByZXNlbnQgb24gdGhlIGJvZHkuXG4gICAqXG4gICAqIEByZXR1cm4gdHJ1ZSBpZiBzY3JvbGxiYXIgaXMgcHJlc2VudCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBwcml2YXRlIF9pc1ByZXNlbnQoc2Nyb2xsYmFyV2lkdGg6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHJlY3QgPSB0aGlzLl9kb2N1bWVudC5ib2R5LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGNvbnN0IGJvZHlUb1ZpZXdwb3J0R2FwID0gd2luZG93LmlubmVyV2lkdGggLSAocmVjdC5sZWZ0ICsgcmVjdC5yaWdodCk7XG4gICAgY29uc3QgdW5jZXJ0YWludHkgPSAwLjEgKiBzY3JvbGxiYXJXaWR0aDtcbiAgICByZXR1cm4gYm9keVRvVmlld3BvcnRHYXAgPj0gc2Nyb2xsYmFyV2lkdGggLSB1bmNlcnRhaW50eTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIGFuZCByZXR1cm5zIHRoZSB3aWR0aCBvZiBhIHNjcm9sbGJhci5cbiAgICpcbiAgICogQHJldHVybiB0aGUgd2lkdGggb2YgYSBzY3JvbGxiYXIgb24gdGhpcyBwYWdlXG4gICAqL1xuICBwcml2YXRlIF9nZXRXaWR0aCgpOiBudW1iZXIge1xuICAgIGNvbnN0IG1lYXN1cmVyID0gdGhpcy5fZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgbWVhc3VyZXIuY2xhc3NOYW1lID0gJ21vZGFsLXNjcm9sbGJhci1tZWFzdXJlJztcblxuICAgIGNvbnN0IGJvZHkgPSB0aGlzLl9kb2N1bWVudC5ib2R5O1xuICAgIGJvZHkuYXBwZW5kQ2hpbGQobWVhc3VyZXIpO1xuICAgIGNvbnN0IHdpZHRoID0gbWVhc3VyZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGggLSBtZWFzdXJlci5jbGllbnRXaWR0aDtcbiAgICBib2R5LnJlbW92ZUNoaWxkKG1lYXN1cmVyKTtcblxuICAgIHJldHVybiB3aWR0aDtcbiAgfVxufVxuIl19