UNPKG

5.97 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var getDocument_1 = require("./dom/getDocument");
4var merge_styles_1 = require("@uifabric/merge-styles");
5var getWindow_1 = require("./dom/getWindow");
6var _scrollbarWidth;
7var _bodyScrollDisabledCount = 0;
8var DisabledScrollClassName = merge_styles_1.mergeStyles({
9 overflow: 'hidden !important',
10});
11/**
12 * Placing this attribute on scrollable divs optimizes detection to know
13 * if the div is scrollable or not (given we can avoid expensive operations
14 * like getComputedStyle.)
15 *
16 * @public
17 */
18exports.DATA_IS_SCROLLABLE_ATTRIBUTE = 'data-is-scrollable';
19/**
20 * Allows the user to scroll within a element,
21 * while preventing the user from scrolling the body
22 */
23exports.allowScrollOnElement = function (element, events) {
24 if (!element) {
25 return;
26 }
27 var _previousClientY = 0;
28 var _element = null;
29 // remember the clientY for future calls of _preventOverscrolling
30 var _saveClientY = function (event) {
31 if (event.targetTouches.length === 1) {
32 _previousClientY = event.targetTouches[0].clientY;
33 }
34 };
35 // prevent the body from scrolling when the user attempts
36 // to scroll past the top or bottom of the element
37 var _preventOverscrolling = function (event) {
38 // only respond to a single-finger touch
39 if (event.targetTouches.length !== 1) {
40 return;
41 }
42 // prevent the body touchmove handler from firing
43 // so that scrolling is allowed within the element
44 event.stopPropagation();
45 if (!_element) {
46 return;
47 }
48 var clientY = event.targetTouches[0].clientY - _previousClientY;
49 var scrollableParent = findScrollableParent(event.target);
50 if (scrollableParent) {
51 _element = scrollableParent;
52 }
53 // if the element is scrolled to the top,
54 // prevent the user from scrolling up
55 if (_element.scrollTop === 0 && clientY > 0) {
56 event.preventDefault();
57 }
58 // if the element is scrolled to the bottom,
59 // prevent the user from scrolling down
60 if (_element.scrollHeight - Math.ceil(_element.scrollTop) <= _element.clientHeight && clientY < 0) {
61 event.preventDefault();
62 }
63 };
64 events.on(element, 'touchstart', _saveClientY, { passive: false });
65 events.on(element, 'touchmove', _preventOverscrolling, { passive: false });
66 _element = element;
67};
68/**
69 * Same as allowScrollOnElement but does not prevent overscrolling.
70 */
71exports.allowOverscrollOnElement = function (element, events) {
72 if (!element) {
73 return;
74 }
75 var _allowElementScroll = function (event) {
76 event.stopPropagation();
77 };
78 events.on(element, 'touchmove', _allowElementScroll, { passive: false });
79};
80var _disableIosBodyScroll = function (event) {
81 event.preventDefault();
82};
83/**
84 * Disables the body scrolling.
85 *
86 * @public
87 */
88function disableBodyScroll() {
89 var doc = getDocument_1.getDocument();
90 if (doc && doc.body && !_bodyScrollDisabledCount) {
91 doc.body.classList.add(DisabledScrollClassName);
92 doc.body.addEventListener('touchmove', _disableIosBodyScroll, { passive: false, capture: false });
93 }
94 _bodyScrollDisabledCount++;
95}
96exports.disableBodyScroll = disableBodyScroll;
97/**
98 * Enables the body scrolling.
99 *
100 * @public
101 */
102function enableBodyScroll() {
103 if (_bodyScrollDisabledCount > 0) {
104 var doc = getDocument_1.getDocument();
105 if (doc && doc.body && _bodyScrollDisabledCount === 1) {
106 doc.body.classList.remove(DisabledScrollClassName);
107 doc.body.removeEventListener('touchmove', _disableIosBodyScroll);
108 }
109 _bodyScrollDisabledCount--;
110 }
111}
112exports.enableBodyScroll = enableBodyScroll;
113/**
114 * Calculates the width of a scrollbar for the browser/os.
115 *
116 * @public
117 */
118function getScrollbarWidth() {
119 if (_scrollbarWidth === undefined) {
120 var scrollDiv = document.createElement('div');
121 scrollDiv.style.setProperty('width', '100px');
122 scrollDiv.style.setProperty('height', '100px');
123 scrollDiv.style.setProperty('overflow', 'scroll');
124 scrollDiv.style.setProperty('position', 'absolute');
125 scrollDiv.style.setProperty('top', '-9999px');
126 document.body.appendChild(scrollDiv);
127 // Get the scrollbar width
128 _scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
129 // Delete the DIV
130 document.body.removeChild(scrollDiv);
131 }
132 return _scrollbarWidth;
133}
134exports.getScrollbarWidth = getScrollbarWidth;
135/**
136 * Traverses up the DOM for the element with the data-is-scrollable=true attribute, or returns
137 * document.body.
138 *
139 * @public
140 */
141function findScrollableParent(startingElement) {
142 var el = startingElement;
143 var doc = getDocument_1.getDocument(startingElement);
144 // First do a quick scan for the scrollable attribute.
145 while (el && el !== doc.body) {
146 if (el.getAttribute(exports.DATA_IS_SCROLLABLE_ATTRIBUTE) === 'true') {
147 return el;
148 }
149 el = el.parentElement;
150 }
151 // If we haven't found it, the use the slower method: compute styles to evaluate if overflow is set.
152 el = startingElement;
153 while (el && el !== doc.body) {
154 if (el.getAttribute(exports.DATA_IS_SCROLLABLE_ATTRIBUTE) !== 'false') {
155 var computedStyles = getComputedStyle(el);
156 var overflowY = computedStyles ? computedStyles.getPropertyValue('overflow-y') : '';
157 if (overflowY && (overflowY === 'scroll' || overflowY === 'auto')) {
158 return el;
159 }
160 }
161 el = el.parentElement;
162 }
163 // Fall back to window scroll.
164 if (!el || el === doc.body) {
165 el = getWindow_1.getWindow(startingElement);
166 }
167 return el;
168}
169exports.findScrollableParent = findScrollableParent;
170//# sourceMappingURL=scroll.js.map
\No newline at end of file