-
Notifications
You must be signed in to change notification settings - Fork 878
Expand file tree
/
Copy pathis-in-text-block.js
More file actions
127 lines (109 loc) · 3.78 KB
/
is-in-text-block.js
File metadata and controls
127 lines (109 loc) · 3.78 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import getComposedParent from './get-composed-parent';
import sanitize from '../text/sanitize';
import { getNodeFromTree, nodeLookup } from '../../core/utils';
import getRoleType from '../aria/get-role-type';
const blockLike = ['block', 'list-item', 'table', 'flex', 'grid'];
const inlineBlockLike = ['inline-block', 'inline-flex', 'inline-grid'];
/**
* Determines if an element is within a text block
* With `noLengthCompare` true, will return if there is any non-space text outside
* widgets. When false, compares the length of non-widget text to widget text
*
* @param {Element} node [description]
* @param {Object} options Optional
* @property {Bool} noLengthCompare
* @property {Bool} includeInlineBlock
* @return {Boolean} [description]
*/
function isInTextBlock(
node,
{ noLengthCompare, includeInlineBlock = false } = {}
) {
const { vNode, domNode } = nodeLookup(node);
if (isBlock(domNode) || (!includeInlineBlock && isInlineBlockLike(vNode))) {
// Ignore if the element is a block
return false;
}
// Find all the text part of the parent block not in a link, and all the text in a link
const virtualParent = getBlockParent(domNode);
let parentText = '';
let widgetText = '';
let inBrBlock = 0;
// We want to ignore hidden text, and if br / hr is used, only use the section of the parent
// that has the link we're looking at
walkDomNode(virtualParent, currNode => {
if (currNode === virtualParent.actualNode) {
return true; // Skip the element itself
}
// We're already passed it, skip everything else
if (inBrBlock === 2) {
return false;
}
if (currNode.nodeType === 3) {
// Add the text to the parent
parentText += currNode.nodeValue;
}
// Ignore any node that's not an element (or text as above)
if (currNode.nodeType !== 1) {
return;
}
const nodeName = (currNode.nodeName || '').toUpperCase();
if (currNode === domNode) {
inBrBlock = 1;
}
const nodeIsBlock = isBlock(currNode);
// BR and HR elements break the line
if (nodeIsBlock || ['BR', 'HR'].includes(nodeName)) {
if (inBrBlock === 0) {
parentText = '';
widgetText = '';
} else {
inBrBlock = 2;
}
// Don't walk nodes with content not displayed on screen.
}
if (
nodeIsBlock ||
currNode.style.display === 'none' ||
currNode.style.overflow === 'hidden' ||
!['', null, 'none'].includes(currNode.style.float) ||
!['', null, 'relative'].includes(currNode.style.position)
) {
return false;
// Don't walk widgets, we're only interested in what's not in them.
} else if (getRoleType(currNode) === 'widget') {
// Grab all the text from this element, but don't walk down it's children
widgetText += currNode.textContent;
return false;
}
});
parentText = sanitize(parentText);
if (noLengthCompare) {
return parentText.length !== 0;
}
widgetText = sanitize(widgetText);
return parentText.length > widgetText.length;
}
export default isInTextBlock;
function isBlock(node) {
const { vNode } = nodeLookup(node);
const display = vNode.getComputedStylePropertyValue('display');
return blockLike.includes(display) || display.substr(0, 6) === 'table-';
}
function isInlineBlockLike(vNode) {
const display = vNode.getComputedStylePropertyValue('display');
return inlineBlockLike.includes(display);
}
function walkDomNode(node, functor) {
if (functor(node.actualNode) !== false) {
node.children.forEach(child => walkDomNode(child, functor));
}
}
function getBlockParent(node) {
// Find the closest parent
let parentBlock = getComposedParent(node);
while (parentBlock && !isBlock(parentBlock)) {
parentBlock = getComposedParent(parentBlock);
}
return getNodeFromTree(parentBlock);
}