Skip to content

Commit

Permalink
Add pseudo-classes that nwsapi can handle (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
asamuzaK authored Nov 2, 2024
1 parent 39ce132 commit 96200eb
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"types": "types/index.d.ts",
"dependencies": {
"@asamuzakjp/nwsapi": "^2.2.17",
"@asamuzakjp/nwsapi": "^2.2.23",
"bidi-js": "^1.0.3",
"css-tree": "^3.0.1",
"is-potential-custom-element-name": "^1.0.1"
Expand Down
3 changes: 1 addition & 2 deletions src/js/constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ export const ALPHA_NUM = '[A-Z\\d]+';
export const CHILD_IDX = '(?:first|last|only)-(?:child|of-type)';
export const DIGIT = '(?:0|[1-9]\\d*)';
export const LANG_PART = `(?:-${ALPHA_NUM})*`;
export const PSEUDO_CLASS =
`(?:any-)?link|${CHILD_IDX}|checked|empty|indeterminate|root|target|visited`;
export const PSEUDO_CLASS = `(?:any-)?link|${CHILD_IDX}|(?:en|dis)abled|checked|empty|indeterminate|read-(?:only|write)|root|target`;
export const ANB =
`[+-]?(?:${DIGIT}n?|n)|(?:[+-]?${DIGIT})?n\\s*[+-]\\s*${DIGIT}`;
// N_TH: excludes An+B with selector list, e.g. :nth-child(2n+1 of .foo)
Expand Down
22 changes: 10 additions & 12 deletions src/js/utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,13 @@ export const isContentEditable = node => {
return node.isContentEditable;
} else if (node.ownerDocument.designMode === 'on') {
return true;
} else if (node.hasAttribute('contenteditable')) {
const attr = node.getAttribute('contenteditable');
} else {
let attr;
if (node.hasAttribute('contenteditable')) {
attr = node.getAttribute('contenteditable');
} else {
attr = 'inherit';
}
switch (attr) {
case '':
case 'true': {
Expand All @@ -345,20 +350,13 @@ export const isContentEditable = node => {
return false;
}
default: {
let parent = node.parentNode;
let bool = false;
while (parent) {
if (isContentEditable(parent)) {
bool = true;
break;
}
parent = parent.parentNode;
if (node?.parentNode?.nodeType === ELEMENT_NODE) {
return isContentEditable(node.parentNode);
}
return bool;
return false;
}
}
}
return false;
};

/**
Expand Down
50 changes: 48 additions & 2 deletions test/utility.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,17 @@ describe('utility functions', () => {
assert.throws(() => func('foo'), TypeError, 'Unexpected type String');
});

it('should get result', () => {
const res = func(document);
assert.isFalse(res, 'result');
});

it('should get result', () => {
const node = document.createElement('div');
const res = func(node);
assert.isFalse(res, 'result');
});

it('should get result', () => {
const node = document.createElement('div');
const parent = document.getElementById('div0');
Expand Down Expand Up @@ -1063,6 +1074,15 @@ describe('utility functions', () => {
assert.isTrue(res, 'result');
});

it('should get result', () => {
const node = document.createElement('div');
node.setAttribute('contenteditable', 'foo');
const parent = document.getElementById('div0');
parent.appendChild(node);
const res = func(node);
assert.isFalse(res, 'result');
});

it('should get result', () => {
const node = document.createElement('div');
node.setAttribute('contenteditable', 'inherit');
Expand All @@ -1083,6 +1103,17 @@ describe('utility functions', () => {
const res = func(node1);
assert.isTrue(res, 'result');
});

it('should get result', () => {
const node1 = document.createElement('div');
const node2 = document.createElement('div');
node2.setAttribute('contenteditable', 'true');
node2.appendChild(node1);
const parent = document.getElementById('div0');
parent.appendChild(node2);
const res = func(node1);
assert.isTrue(res, 'result');
});
});

describe('is node visible', () => {
Expand Down Expand Up @@ -2011,12 +2042,22 @@ describe('utility functions', () => {

it('should get false', () => {
const res = func(':enabled');
assert.isFalse(res, 'result');
assert.isTrue(res, 'result');
});

it('should get false', () => {
const res = func(':disabled');
assert.isFalse(res, 'result');
assert.isTrue(res, 'result');
});

it('should get false', () => {
const res = func(':read-only');
assert.isTrue(res, 'result');
});

it('should get false', () => {
const res = func(':read-write');
assert.isTrue(res, 'result');
});

it('should get false', () => {
Expand All @@ -2039,6 +2080,11 @@ describe('utility functions', () => {
assert.isTrue(res, 'result');
});

it('should get false', () => {
const res = func(':visited');
assert.isFalse(res, 'result');
});

it('should get false', () => {
const res = func(':after');
assert.isFalse(res, 'result');
Expand Down
69 changes: 64 additions & 5 deletions test/wpt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4729,7 +4729,7 @@ describe('local wpt test cases', () => {
const ancestor = document.getElementById('ancestor');
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
ancestor.classList.add("some-hidden");
ancestor.classList.add('some-hidden');
root.classList.remove('reftest-wait');
assert.isTrue(div1.matches('.some-hidden > :not(.always-matches:not(:first-of-type))'));
assert.isFalse(div2.matches('.some-hidden > :not(.always-matches:not(:first-of-type))'));
Expand Down Expand Up @@ -4759,7 +4759,7 @@ describe('local wpt test cases', () => {
const ancestor = document.getElementById('ancestor');
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
ancestor.classList.add("some-hidden");
ancestor.classList.add('some-hidden');
root.classList.remove('reftest-wait');
assert.isFalse(div1.matches('.some-hidden > :not(:is(.always-matches, :not(:first-of-type)))'));
assert.isFalse(div2.matches('.some-hidden > :not(:is(.always-matches, :not(:first-of-type)))'));
Expand Down Expand Up @@ -4792,7 +4792,7 @@ describe('local wpt test cases', () => {
const ancestor = document.getElementById('ancestor');
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
ancestor.classList.add("some-hidden");
ancestor.classList.add('some-hidden');
root.classList.remove('reftest-wait');
assert.isTrue(div1.matches('.some-hidden > :not(:is(.never-matches, :not(:first-of-type)))'));
assert.isFalse(div2.matches('.some-hidden > :not(:is(.never-matches, :not(:first-of-type)))'));
Expand Down Expand Up @@ -4825,7 +4825,7 @@ describe('local wpt test cases', () => {
const ancestor = document.getElementById('ancestor');
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
ancestor.classList.add("some-hidden");
ancestor.classList.add('some-hidden');
root.classList.remove('reftest-wait');
assert.isTrue(div1.matches('.some-hidden > :not(:not(:first-of-type))'));
assert.isFalse(div2.matches('.some-hidden > :not(:not(:first-of-type))'));
Expand Down Expand Up @@ -4858,7 +4858,7 @@ describe('local wpt test cases', () => {
const ancestor = document.getElementById('ancestor');
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
ancestor.classList.add("some-hidden");
ancestor.classList.add('some-hidden');
root.classList.remove('reftest-wait');
assert.isTrue(div1.matches('.some-hidden > :not(.never-matches:not(:first-of-type))'));
assert.isTrue(div2.matches('.some-hidden > :not(.never-matches:not(:first-of-type))'));
Expand Down Expand Up @@ -5563,6 +5563,44 @@ describe('local wpt test cases', () => {
});
});

describe('css/selectors/pseudo-enabled-disabled.html', () => {
it('should get matched node(s)', () => {
const html = `
<div id="container">
<button id="button_enabled"></button>
<button id="button_disabled" disabled></button>
<input id="input_enabled">
<input id="input_disabled" disabled>
<select id="select_enabled"></select>
<select id="select_disabled" disabled></select>
<textarea id="textarea_enabled"></textarea>
<textarea id="textarea_disabled" disabled></textarea>
<span id="incapable"></span>
</div>
`;
document.body.innerHTML = html;
const container = document.getElementById('container');
const matchEnabled = container.querySelectorAll(':enabled');
for (const element of matchEnabled) {
assert.isTrue(element.id.endsWith('_enabled'), element.id);
}
const matchDisabled = container.querySelectorAll(':disabled');
for (const element of matchDisabled) {
assert.isTrue(element.id.endsWith('_disabled'), element.id);
}
const matchNotDisabled = container.querySelectorAll(':not(:disabled)');
for (const element of matchNotDisabled) {
assert.isTrue(element.id.endsWith('_enabled') ||
element.id === 'incapable', element.id);
}
const matchNotEnabled = container.querySelectorAll(':not(:enabled)');
for (const element of matchNotEnabled) {
assert.isTrue(element.id.endsWith('_disabled') ||
element.id === 'incapable', element.id);
}
});
});

describe('css/selectors/scope-selector.html', () => {
it('querySelector() with ":scope" should return the document element, if present in the subtree', () => {
const html = '<div id=\'shadowHost\'></div>';
Expand Down Expand Up @@ -5621,6 +5659,27 @@ describe('local wpt test cases', () => {
});
});

describe('css/selectors/selector-read-write-type-change-001.html', () => {
it('should get matched node(s)', async () => {
const html = `
<style>
span { color: green; }
:read-write + span { color: red }
</style>
<input id="input" required><span id="span">This should be green</span>
`;
document.body.innerHTML = html;
const input = document.getElementById('input');
const span = document.getElementById('span');
await sleep();
input.type = 'button';
assert.isFalse(span.matches(':read-write + span'));
await sleep();
input.type = '';
assert.isTrue(span.matches(':read-write + span'));
});
});

describe('dom/nodes/Element-matches.html', () => {
it('should match', () => {
const html = `<div id="universal">
Expand Down

0 comments on commit 96200eb

Please sign in to comment.