Skip to content

Commit bcffd09

Browse files
authored
chore(text-block): suggest changes to PR #5000 (#5009)
While reviewing #5000 I found the approach wasn't working as I was expecting. Playing around with examples I found a simpler way to do this. IDK if this is everything we should do, but I think this gets us close. I decided to put this in its own PR since this was too much code to put into comments.
1 parent 256d1c1 commit bcffd09

File tree

2 files changed

+85
-91
lines changed

2 files changed

+85
-91
lines changed

lib/commons/dom/is-in-text-block.js

Lines changed: 34 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,11 @@ import getComposedParent from './get-composed-parent';
22
import sanitize from '../text/sanitize';
33
import { getNodeFromTree, nodeLookup } from '../../core/utils';
44
import getRoleType from '../aria/get-role-type';
5-
import isFocusable from './is-focusable';
6-
7-
function walkDomNode(node, functor) {
8-
if (functor(node.actualNode) !== false) {
9-
node.children.forEach(child => walkDomNode(child, functor));
10-
}
11-
}
125

136
const blockLike = ['block', 'list-item', 'table', 'flex', 'grid'];
147

158
const inlineBlockLike = ['inline-block', 'inline-flex', 'inline-grid'];
169

17-
function isBlock(node) {
18-
const { vNode } = nodeLookup(node);
19-
const display = vNode.getComputedStylePropertyValue('display');
20-
return blockLike.includes(display) || display.substr(0, 6) === 'table-';
21-
}
22-
23-
function isInlineBlockLike(vNode) {
24-
const display = vNode.getComputedStylePropertyValue('display');
25-
return inlineBlockLike.includes(display);
26-
}
27-
28-
function getBlockParent(node) {
29-
// Find the closest parent
30-
let parentBlock = getComposedParent(node);
31-
while (parentBlock && !isBlock(parentBlock)) {
32-
parentBlock = getComposedParent(parentBlock);
33-
}
34-
35-
return getNodeFromTree(parentBlock);
36-
}
37-
3810
/**
3911
* Determines if an element is within a text block
4012
* With `noLengthCompare` true, will return if there is any non-space text outside
@@ -43,62 +15,21 @@ function getBlockParent(node) {
4315
* @param {Element} node [description]
4416
* @param {Object} options Optional
4517
* @property {Bool} noLengthCompare
46-
* @property {Bool} permissive
18+
* @property {Bool} includeInlineBlock
4719
* @return {Boolean} [description]
4820
*/
49-
function isInTextBlock(node, { noLengthCompare, permissive = false } = {}) {
21+
function isInTextBlock(
22+
node,
23+
{ noLengthCompare, includeInlineBlock = false } = {}
24+
) {
5025
const { vNode, domNode } = nodeLookup(node);
51-
52-
if (isBlock(domNode)) {
53-
// Ignore if the link is a block
26+
if (isBlock(domNode) || (!includeInlineBlock && isInlineBlockLike(vNode))) {
27+
// Ignore if the element is a block
5428
return false;
5529
}
5630

5731
// Find all the text part of the parent block not in a link, and all the text in a link
5832
const virtualParent = getBlockParent(domNode);
59-
60-
// if the element is a block-like element, look at the siblings of the node and if any
61-
// are inline or text nodes then return the desired permissive option value so the
62-
// caller determine what to do with them.
63-
// @see https://github.com/dequelabs/axe-core/issues/4392
64-
if (isInlineBlockLike(vNode)) {
65-
// widget parents should be ignored
66-
if (getRoleType(virtualParent) === 'widget' || isFocusable(virtualParent)) {
67-
return false;
68-
}
69-
70-
for (const siblingVNode of virtualParent.children) {
71-
if (
72-
siblingVNode.actualNode === node ||
73-
// BR and HR elements break the line
74-
['br', 'hr'].includes(siblingVNode.props.nodeName)
75-
) {
76-
continue;
77-
}
78-
79-
// if there is a widget as a sibling we break out of the loop as we won't count two
80-
// widgets as being inline
81-
if (getRoleType(siblingVNode) === 'widget') {
82-
break;
83-
}
84-
85-
if (siblingVNode.props.nodeType === window.Node.TEXT_NODE) {
86-
if (sanitize(siblingVNode.props.nodeValue)) {
87-
return permissive;
88-
}
89-
90-
continue;
91-
}
92-
93-
const display = siblingVNode.getComputedStylePropertyValue('display');
94-
if (display === 'inline') {
95-
return permissive;
96-
}
97-
}
98-
99-
return false;
100-
}
101-
10233
let parentText = '';
10334
let widgetText = '';
10435
let inBrBlock = 0;
@@ -160,3 +91,30 @@ function isInTextBlock(node, { noLengthCompare, permissive = false } = {}) {
16091
}
16192

16293
export default isInTextBlock;
94+
95+
function isBlock(node) {
96+
const { vNode } = nodeLookup(node);
97+
const display = vNode.getComputedStylePropertyValue('display');
98+
return blockLike.includes(display) || display.substr(0, 6) === 'table-';
99+
}
100+
101+
function isInlineBlockLike(vNode) {
102+
const display = vNode.getComputedStylePropertyValue('display');
103+
return inlineBlockLike.includes(display);
104+
}
105+
106+
function walkDomNode(node, functor) {
107+
if (functor(node.actualNode) !== false) {
108+
node.children.forEach(child => walkDomNode(child, functor));
109+
}
110+
}
111+
112+
function getBlockParent(node) {
113+
// Find the closest parent
114+
let parentBlock = getComposedParent(node);
115+
while (parentBlock && !isBlock(parentBlock)) {
116+
parentBlock = getComposedParent(parentBlock);
117+
}
118+
119+
return getNodeFromTree(parentBlock);
120+
}

test/commons/dom/is-in-text-block.js

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,7 @@ describe('dom.isInTextBlock', () => {
315315
it('returns true if there is any text outside the link', () => {
316316
fixtureSetup('<p>amy <a href="" id="link">link text is longer</a></p>');
317317
const link = document.getElementById('link');
318-
assert.isTrue(
319-
isInTextBlock(link, {
320-
noLengthCompare: true
321-
})
322-
);
318+
assert.isTrue(isInTextBlock(link, { noLengthCompare: true }));
323319
});
324320

325321
it('returns false if the non-widget text is only whitespace', () => {
@@ -332,33 +328,73 @@ describe('dom.isInTextBlock', () => {
332328
'</p>'
333329
);
334330
const link = document.getElementById('link');
335-
assert.isFalse(
336-
isInTextBlock(link, {
337-
noLengthCompare: true
338-
})
339-
);
331+
assert.isFalse(isInTextBlock(link, { noLengthCompare: true }));
340332
});
341333
});
342334

343-
describe('options.permissive', () => {
344-
it('returns options.permissive if inline-block element has text sibling', () => {
335+
describe('with options.permissive: true', () => {
336+
it('returns true if inline-block element has text sibling', () => {
345337
const target = queryFixture(`
346338
<div>
347339
Hello world
348340
<button id="target">button</button>
349341
</div>
350342
`);
351-
assert.isTrue(isInTextBlock(target, { permissive: true }));
343+
assert.isTrue(isInTextBlock(target, { includeInlineBlock: true }));
352344
});
353345

354-
it('returns options.permissive if inline-block element has inline element sibling', () => {
346+
it('returns true if inline-block element has inline element sibling', () => {
355347
const target = queryFixture(`
356348
<div>
357349
<span>Hello world</span>
358350
<button id="target">button</button>
359351
</div>
360352
`);
361-
assert.isTrue(isInTextBlock(target, { permissive: true }));
353+
assert.isTrue(isInTextBlock(target, { includeInlineBlock: true }));
354+
});
355+
356+
it('returns true if inline-block element has text sibling after it', () => {
357+
const target = queryFixture(`
358+
<div>
359+
<button id="target">button</button> hello world
360+
</div>
361+
`);
362+
assert.isTrue(isInTextBlock(target, { includeInlineBlock: true }));
363+
});
364+
365+
it('returns true if inline-block element has both inline text and a widget sibling', () => {
366+
const target = queryFixture(`
367+
<div>
368+
<button>button 1</button>
369+
<span>Hello world, goodbye mars</span>
370+
<button id="target">button 2</button>
371+
</div>
372+
`);
373+
assert.isTrue(isInTextBlock(target, { includeInlineBlock: true }));
374+
});
375+
376+
it('returns false the inline text sibling is on a different line', () => {
377+
const target = queryFixture(`
378+
<div>
379+
Hello
380+
<br>
381+
<button id="target">button</button>
382+
<hr>
383+
world
384+
</div>
385+
`);
386+
assert.isFalse(isInTextBlock(target, { includeInlineBlock: true }));
387+
});
388+
389+
it('returns true if inline-block element has a sibling on the same line', () => {
390+
const target = queryFixture(`
391+
<div>
392+
Hello
393+
<br>
394+
world <button id="target">button 2</button>
395+
</div>
396+
`);
397+
assert.isFalse(isInTextBlock(target, { includeInlineBlock: true }));
362398
});
363399
});
364400
});

0 commit comments

Comments
 (0)