@asamuzakjp/dom-selector
Advanced tools
Comparing version 0.11.1 to 0.12.0
@@ -45,3 +45,3 @@ { | ||
}, | ||
"version": "0.11.1" | ||
"version": "0.12.0" | ||
} |
@@ -16,2 +16,3 @@ /** | ||
} = require('./constant.js'); | ||
const DOCUMENT_POSITION_CONTAINS = 8; | ||
const ELEMENT_NODE = 1; | ||
@@ -34,2 +35,32 @@ const FILTER_ACCEPT = 1; | ||
/** | ||
* is content editable | ||
* NOTE: not implemented in jsdom https://github.com/jsdom/jsdom/issues/1670 | ||
* @param {object} node - Element | ||
* @returns {boolean} - result | ||
*/ | ||
const isContentEditable = (node = {}) => { | ||
let bool; | ||
if (node.nodeType === ELEMENT_NODE) { | ||
if (node.ownerDocument.designMode === 'on') { | ||
bool = true; | ||
} else if (node.hasAttribute('contenteditable')) { | ||
const attr = node.getAttribute('contenteditable'); | ||
if (/^(?:plaintext-only|true)$/.test(attr) || attr === '') { | ||
bool = true; | ||
} else if (attr === 'inherit') { | ||
let parent = node.parentNode; | ||
while (parent) { | ||
if (isContentEditable(parent)) { | ||
bool = true; | ||
break; | ||
} | ||
parent = parent.parentNode; | ||
} | ||
} | ||
} | ||
} | ||
return !!bool; | ||
}; | ||
/** | ||
* unescape selector | ||
@@ -93,5 +124,5 @@ * @param {string} selector - CSS selector | ||
if (selector) { | ||
const a = new Matcher(selector, ownerDocument).querySelectorAll(); | ||
if (a.length) { | ||
items.push(...a); | ||
const ar = new Matcher(selector, ownerDocument).querySelectorAll(); | ||
if (ar.length) { | ||
items.push(...ar); | ||
} | ||
@@ -670,4 +701,3 @@ } | ||
case 'link': | ||
// TBD: what about namespaced href? e.g. xlink:href | ||
if (node.hasAttribute('href')) { | ||
if (/^a(?:rea)?$/.test(localName) && node.hasAttribute('href')) { | ||
matched.push(node); | ||
@@ -677,4 +707,3 @@ } | ||
case 'local-link': | ||
// TBD: what about namespaced href? e.g. xlink:href | ||
if (node.hasAttribute('href')) { | ||
if (/^a(?:rea)?$/.test(localName) && node.hasAttribute('href')) { | ||
const attrURL = new URL(node.getAttribute('href'), docURL.href); | ||
@@ -744,7 +773,20 @@ if (attrURL.origin === docURL.origin && | ||
case 'disabled': | ||
if ((HTML_FORM_INPUT.test(localName) || | ||
HTML_FORM_PARTS.test(localName) || | ||
isCustomElementName(localName)) && | ||
node.hasAttribute('disabled')) { | ||
matched.push(node); | ||
if (HTML_FORM_INPUT.test(localName) || | ||
HTML_FORM_PARTS.test(localName) || | ||
isCustomElementName(localName)) { | ||
if (node.hasAttribute('disabled')) { | ||
matched.push(node); | ||
} else { | ||
let parent = node.parentNode; | ||
while (parent) { | ||
if (parent.localName === 'fieldset') { | ||
break; | ||
} | ||
parent = parent.parentNode; | ||
} | ||
if (parent && parent.hasAttribute('disabled') && | ||
node.parentNode.localName !== 'legend') { | ||
matched.push(node); | ||
} | ||
} | ||
} | ||
@@ -760,4 +802,32 @@ break; | ||
break; | ||
case 'read-only': | ||
if (/^(?:input|textarea)$/.test(localName)) { | ||
if (node.hasAttribute('readonly') || | ||
node.hasAttribute('disabled')) { | ||
matched.push(node); | ||
} | ||
} else if (!isContentEditable(node)) { | ||
matched.push(node); | ||
} | ||
break; | ||
case 'read-write': | ||
if (/^(?:input|textarea)$/.test(localName)) { | ||
if (!(node.hasAttribute('readonly') || | ||
node.hasAttribute('disabled'))) { | ||
matched.push(node); | ||
} | ||
} else if (isContentEditable(node)) { | ||
matched.push(node); | ||
} | ||
break; | ||
case 'placeholder-shown': | ||
if (/^(?:input|textarea)$/.test(localName) && | ||
node.hasAttribute('placeholder') && | ||
node.getAttribute('placeholder').trim().length && | ||
node.value === '') { | ||
matched.push(node); | ||
} | ||
break; | ||
case 'checked': | ||
if ((/^input$/.test(localName) && node.hasAttribute('type') && | ||
if ((localName === 'input' && node.hasAttribute('type') && | ||
/^(?:checkbox|radio)$/.test(node.getAttribute('type')) && | ||
@@ -769,5 +839,35 @@ node.checked) || | ||
break; | ||
case 'indeterminate': | ||
if ((localName === 'input' && node.type === 'checkbox' && | ||
node.indeterminate) || | ||
(localName === 'progress' && !node.hasAttribute('value'))) { | ||
matched.push(node); | ||
} else if (localName === 'input' && node.type === 'radio') { | ||
const radioName = node.name; | ||
let form = node; | ||
while (form) { | ||
if (form.localName === 'form') { | ||
break; | ||
} | ||
form = form.parentNode; | ||
} | ||
if (form && radioName) { | ||
const sel = `input[type="radio"][name="${radioName}"]`; | ||
const arr = new Matcher(sel, form).querySelectorAll(); | ||
let checked; | ||
for (const i of arr) { | ||
checked = !!i.checked; | ||
if (checked) { | ||
break; | ||
} | ||
} | ||
if (!checked) { | ||
matched.push(node); | ||
} | ||
} | ||
} | ||
break; | ||
case 'default': | ||
// input[type="checkbox"], input[type="radio"] | ||
if (/^input$/.test(localName) && node.hasAttribute('type') && | ||
if (localName === 'input' && node.hasAttribute('type') && | ||
/^(?:checkbox|radio)$/.test(node.getAttribute('type'))) { | ||
@@ -817,3 +917,3 @@ if (node.hasAttribute('checked')) { | ||
node.getAttribute('type') === 'submit')) || | ||
(/^input$/.test(localName) && node.hasAttribute('type') && | ||
(localName === 'input' && node.hasAttribute('type') && | ||
/^(?:image|submit)$/.test(node.getAttribute('type')))) { | ||
@@ -824,2 +924,35 @@ throw new DOMException(`Unsupported pseudo-class ${astName}`, | ||
break; | ||
case 'valid': | ||
if (HTML_FORM_INPUT.test(localName) || | ||
/^(?:f(?:ieldset|orm)|button|output)$/.test(localName)) { | ||
if (node.checkValidity()) { | ||
matched.push(node); | ||
} | ||
} | ||
break; | ||
case 'invalid': | ||
if (HTML_FORM_INPUT.test(localName) || | ||
/^(?:f(?:ieldset|orm)|button|output)$/.test(localName)) { | ||
if (!node.checkValidity()) { | ||
matched.push(node); | ||
} | ||
} | ||
break; | ||
case 'in-range': | ||
if (localName === 'input' && | ||
node.hasAttribute('min') && node.hasAttribute('max')) { | ||
if (!(node.validity.rangeUnderflow || | ||
node.validity.rangeOverflow)) { | ||
matched.push(node); | ||
} | ||
} | ||
break; | ||
case 'out-of-range': | ||
if (localName === 'input' && | ||
node.hasAttribute('min') && node.hasAttribute('max')) { | ||
if (node.validity.rangeUnderflow || node.validity.rangeOverflow) { | ||
matched.push(node); | ||
} | ||
} | ||
break; | ||
case 'required': | ||
@@ -918,15 +1051,8 @@ if (HTML_FORM_INPUT.test(localName) && node.required) { | ||
case 'hover': | ||
case 'indeterminate': | ||
case 'invalid': | ||
case 'in-range': | ||
case 'modal': | ||
case 'muted': | ||
case 'out-of-range': | ||
case 'past': | ||
case 'paused': | ||
case 'picture-in-picture': | ||
case 'placeholder-shown': | ||
case 'playing': | ||
case 'read-only': | ||
case 'read-write': | ||
case 'seeking': | ||
@@ -936,3 +1062,2 @@ case 'stalled': | ||
case 'user-valid': | ||
case 'valid': | ||
case 'volume-locked': | ||
@@ -1018,15 +1143,6 @@ throw new DOMException(`Unsupported pseudo-class ${astName}`, | ||
_isAttached() { | ||
const root = this.#document?.documentElement; | ||
let bool; | ||
if (root) { | ||
let node = this.#node; | ||
while (node) { | ||
if (node === root) { | ||
bool = true; | ||
break; | ||
} | ||
node = node.parentNode; | ||
} | ||
} | ||
return !!bool; | ||
const root = this.#document.documentElement; | ||
const posBit = | ||
this.#node.compareDocumentPosition(root) & DOCUMENT_POSITION_CONTAINS; | ||
return !!posBit; | ||
}; | ||
@@ -1603,2 +1719,3 @@ | ||
collectNthOfType, | ||
isContentEditable, | ||
matchAnPlusB, | ||
@@ -1605,0 +1722,0 @@ matchAttributeSelector, |
@@ -31,2 +31,3 @@ export class Matcher { | ||
}, node?: object): Array<object | undefined>; | ||
export function isContentEditable(node?: object): boolean; | ||
export function matchAnPlusB(nthName: string, ast?: object, node?: object): Array<object | undefined>; | ||
@@ -33,0 +34,0 @@ export function matchAttributeSelector(ast?: object, node?: object): object | null; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
67140
1976