UNPKG

3.75 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = isElementClickable;
7
8function isElementClickable(elem) {
9 if (!elem.getBoundingClientRect || !elem.scrollIntoView || !elem.contains || !elem.getClientRects || !document.elementFromPoint) {
10 return false;
11 }
12
13 const isOldEdge = !!window.StyleMedia;
14 const scrollIntoViewFullSupport = !(window.safari || isOldEdge);
15
16 function getOverlappingElement(elem, context) {
17 context = context || document;
18 const elemDimension = elem.getBoundingClientRect();
19 const x = elemDimension.left + elem.clientWidth / 2;
20 const y = elemDimension.top + elem.clientHeight / 2;
21 return context.elementFromPoint(x, y);
22 }
23
24 function getOverlappingRects(elem, context) {
25 context = context || document;
26 const elems = [];
27 const rects = elem.getClientRects();
28 const rect = rects[0];
29 const x = rect.left + rect.width / 2;
30 const y = rect.top + rect.height / 2;
31 elems.push(context.elementFromPoint(x, y));
32 return elems;
33 }
34
35 function getOverlappingElements(elem, context) {
36 return [getOverlappingElement(elem, context)].concat(getOverlappingRects(elem, context));
37 }
38
39 function nodeContains(elem, otherNode) {
40 if (isOldEdge) {
41 let tmpElement = otherNode;
42
43 while (tmpElement) {
44 if (tmpElement === elem) {
45 return true;
46 }
47
48 tmpElement = tmpElement.parentNode;
49
50 if (tmpElement && tmpElement.nodeType === 11 && tmpElement.host) {
51 tmpElement = tmpElement.host;
52 }
53 }
54
55 return false;
56 }
57
58 return elem.contains(otherNode);
59 }
60
61 function isOverlappingElementMatch(elementsFromPoint, elem) {
62 if (elementsFromPoint.some(function (elementFromPoint) {
63 return elementFromPoint === elem || nodeContains(elem, elementFromPoint);
64 })) {
65 return true;
66 }
67
68 let elemsWithShadowRoot = [].concat(elementsFromPoint);
69 elemsWithShadowRoot = elemsWithShadowRoot.filter(function (x) {
70 return x && x.shadowRoot && x.shadowRoot.elementFromPoint;
71 });
72 let shadowElementsFromPoint = [];
73
74 for (let i = 0; i < elemsWithShadowRoot.length; ++i) {
75 let shadowElement = elemsWithShadowRoot[i];
76 shadowElementsFromPoint = shadowElementsFromPoint.concat(getOverlappingElements(elem, shadowElement.shadowRoot));
77 }
78
79 shadowElementsFromPoint = [].concat(shadowElementsFromPoint);
80 shadowElementsFromPoint = shadowElementsFromPoint.filter(function (x) {
81 return !elementsFromPoint.includes(x);
82 });
83
84 if (shadowElementsFromPoint.length === 0) {
85 return false;
86 }
87
88 return isOverlappingElementMatch(shadowElementsFromPoint, elem);
89 }
90
91 function isElementInViewport(elem) {
92 if (!elem.getBoundingClientRect) {
93 return false;
94 }
95
96 const rect = elem.getBoundingClientRect();
97 const windowHeight = window.innerHeight || document.documentElement.clientHeight;
98 const windowWidth = window.innerWidth || document.documentElement.clientWidth;
99 const vertInView = rect.top <= windowHeight && rect.top + rect.height > 0;
100 const horInView = rect.left <= windowWidth && rect.left + rect.width > 0;
101 return vertInView && horInView;
102 }
103
104 function isClickable(elem) {
105 return isElementInViewport(elem) && elem.disabled !== true && isOverlappingElementMatch(getOverlappingElements(elem), elem);
106 }
107
108 if (!isClickable(elem)) {
109 elem.scrollIntoView(scrollIntoViewFullSupport ? {
110 block: 'nearest',
111 inline: 'nearest'
112 } : false);
113
114 if (!isClickable(elem)) {
115 elem.scrollIntoView(scrollIntoViewFullSupport ? {
116 block: 'center',
117 inline: 'center'
118 } : true);
119 return isClickable(elem);
120 }
121 }
122
123 return true;
124}
\No newline at end of file