(html, opts = {})
| 81 | } |
| 82 | |
| 83 | function removeNonInteractiveElements(html, opts = {}) { |
| 84 | opts = { ...defaultHtmlOpts, ...opts } |
| 85 | const { interactiveElements, textElements, allowedAttrs, allowedRoles } = opts |
| 86 | |
| 87 | // Parse the HTML into a document tree |
| 88 | const document = parse(html) |
| 89 | |
| 90 | // Array to store interactive elements |
| 91 | const removeElements = ['path', 'script'] |
| 92 | |
| 93 | function isFilteredOut(node) { |
| 94 | if (removeElements.includes(node.nodeName)) return true |
| 95 | if (node.attrs) { |
| 96 | if (node.attrs.find(attr => attr.name === 'role' && attr.value === 'tooltip')) return true |
| 97 | } |
| 98 | return false |
| 99 | } |
| 100 | |
| 101 | // Function to check if an element is interactive |
| 102 | function isInteractive(element) { |
| 103 | if (element.nodeName === 'input' && element.attrs.find(attr => attr.name === 'type' && attr.value === 'hidden')) return false |
| 104 | if (interactiveElements.includes(element.nodeName)) return true |
| 105 | if (element.attrs) { |
| 106 | if (element.attrs.find(attr => attr.name === 'contenteditable')) return true |
| 107 | if (element.attrs.find(attr => attr.name === 'tabindex')) return true |
| 108 | const role = element.attrs.find(attr => attr.name === 'role') |
| 109 | if (role && allowedRoles.includes(role.value)) return true |
| 110 | } |
| 111 | return false |
| 112 | } |
| 113 | |
| 114 | function hasMeaningfulText(node) { |
| 115 | if (textElements.includes(node.nodeName)) return true |
| 116 | return false |
| 117 | } |
| 118 | |
| 119 | function hasInteractiveDescendant(node) { |
| 120 | if (!node.childNodes) return false |
| 121 | let result = false |
| 122 | |
| 123 | for (const childNode of node.childNodes) { |
| 124 | if (isInteractive(childNode) || hasMeaningfulText(childNode)) return true |
| 125 | result = result || hasInteractiveDescendant(childNode) |
| 126 | } |
| 127 | |
| 128 | return result |
| 129 | } |
| 130 | |
| 131 | // Function to remove non-interactive elements recursively |
| 132 | function removeNonInteractive(node) { |
| 133 | if (node.nodeName !== '#document') { |
| 134 | const parent = node.parentNode |
| 135 | const index = parent.childNodes.indexOf(node) |
| 136 | |
| 137 | if (isFilteredOut(node)) { |
| 138 | parent.childNodes.splice(index, 1) |
| 139 | return true |
| 140 | } |
no test coverage detected