forked from DevExpress/testcafe
-
Notifications
You must be signed in to change notification settings - Fork 0
/
scroll.ts
107 lines (76 loc) · 4.09 KB
/
scroll.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import adapter from './adapter/index';
import AxisValues from '../../../../shared/utils/values/axis-values';
const SCROLLABLE_OVERFLOW_STYLE_RE = /auto|scroll|hidden/i;
const DEFAULT_IE_SCROLLABLE_OVERFLOW_STYLE_VALUE = 'visible';
function getScrollable (el: Element): AxisValues<boolean> {
const overflowX = adapter.style.get(el, 'overflowX') as string;
const overflowY = adapter.style.get(el, 'overflowY') as string;
let scrollableHorizontally = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowX);
let scrollableVertically = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowY);
// IE11 and MS Edge bug: There are two properties: overflow-x and overflow-y.
// If one property is set so that the browser may show scrollbars (`auto` or `scroll`) and the second one is set to 'visible',
// then the second one will work as if it had the 'auto' value.
if (adapter.browser.isIE) {
scrollableHorizontally = scrollableHorizontally || scrollableVertically && overflowX === DEFAULT_IE_SCROLLABLE_OVERFLOW_STYLE_VALUE;
scrollableVertically = scrollableVertically || scrollableHorizontally && overflowY === DEFAULT_IE_SCROLLABLE_OVERFLOW_STYLE_VALUE;
}
return new AxisValues(scrollableHorizontally, scrollableVertically);
}
function hasBodyScroll (el: HTMLBodyElement): boolean {
const overflowX = adapter.style.get(el, 'overflowX') as string;
const overflowY = adapter.style.get(el, 'overflowY') as string;
const scrollableHorizontally = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowX);
const scrollableVertically = SCROLLABLE_OVERFLOW_STYLE_RE.test(overflowY);
const documentElement = adapter.dom.findDocument(el).documentElement;
let bodyScrollHeight = el.scrollHeight;
if (adapter.browser.isChrome || adapter.browser.isFirefox || adapter.browser.isSafari) {
const { top: bodyTop } = el.getBoundingClientRect();
const { top: documentTop } = documentElement.getBoundingClientRect();
bodyScrollHeight = bodyScrollHeight - documentTop + bodyTop;
}
return (scrollableHorizontally || scrollableVertically) &&
bodyScrollHeight > documentElement.scrollHeight;
}
function hasHTMLElementScroll (el: HTMLHtmlElement): boolean {
const overflowX = adapter.style.get(el, 'overflowX') as string;
const overflowY = adapter.style.get(el, 'overflowY') as string;
//T303226
if (overflowX === 'hidden' && overflowY === 'hidden')
return false;
const hasHorizontalScroll = el.scrollHeight > el.clientHeight;
const hasVerticalScroll = el.scrollWidth > el.clientWidth;
if (hasHorizontalScroll || hasVerticalScroll)
return true;
//T174562 - wrong scrolling in iframes without src and others iframes
const body = el.getElementsByTagName('body')[0];
if (!body)
return false;
if (hasBodyScroll(body))
return false;
const clientWidth = Math.min(el.clientWidth, body.clientWidth);
const clientHeight = Math.min(el.clientHeight, body.clientHeight);
return body.scrollHeight > clientHeight || body.scrollWidth > clientWidth;
}
export function hasScroll (el: Element): boolean {
if (adapter.dom.isBodyElement(el))
return hasBodyScroll(el);
if (adapter.dom.isHtmlElement(el))
return hasHTMLElementScroll(el);
const scrollable = getScrollable(el);
if (!scrollable.x && !scrollable.y)
return false;
const hasVerticalScroll = scrollable.y && el.scrollHeight > el.clientHeight;
const hasHorizontalScroll = scrollable.x && el.scrollWidth > el.clientWidth;
return hasHorizontalScroll || hasVerticalScroll;
}
export function getScrollableParents (element: Element): Element[] {
const parentsArray = adapter.dom.getParents(element);
if (adapter.dom.isElementInIframe(element)) {
const iframe = adapter.dom.getIframeByElement(element);
if (iframe) {
const iFrameParents = adapter.dom.getParents(iframe);
parentsArray.concat(iFrameParents);
}
}
return adapter.nativeMethods.arrayFilter.call(parentsArray, hasScroll);
}