UNPKG

shadow-selection-polyfill

Version:
93 lines (68 loc) 2.19 kB
export const eventName = '-shadow-selectionchange'; const validNodeTypes = [Node.ELEMENT_NODE, Node.TEXT_NODE, Node.DOCUMENT_FRAGMENT_NODE]; function isValidNode(node) { return validNodeTypes.includes(node.nodeType); } function findNode(s, parentNode, isLeft) { const nodes = parentNode.childNodes || parentNode.children; if (!nodes || !nodes.length) { return {node: parentNode, extent: true}; // found it, probably text or e.g. <img> } for (let i = 0; i < nodes.length; ++i) { const j = isLeft ? i : (nodes.length - 1 - i); const childNode = nodes[j]; if (!isValidNode(childNode)) { continue; } if (s.containsNode(childNode, true)) { if (childNode.nodeType === Node.TEXT_NODE) { return {node: childNode, extent: false}; // text nodes always report whole match, ignore } if (s.containsNode(childNode, false)) { return {node: childNode, extent: true}; // complete match, whole child } return findNode(s, childNode, isLeft); } } return {node: parentNode, extent: false}; } const addInternalListener = (() => { let withinInternals = false; const handlers = []; document.addEventListener('selectionchange', (ev) => { if (withinInternals) { return; } document.dispatchEvent(new CustomEvent(eventName)); withinInternals = true; window.setTimeout(() => { withinInternals = false; }, 0); handlers.forEach((fn) => fn(ev)); }); return (fn) => handlers.push(fn); })(); /** * @param {!ShadowRoot} root */ export function getRange(root) { const s = window.getSelection(); const left = findNode(s, root, true); if (left.node === root) { return null; } const right = findNode(s, root, false); if (right.node === root) { throw new TypeError('found left node but not right node'); } if (s.type !== 'Range') { return null; } const initialSize = s.toString().length; s.modify('extend', 'left', 'character'); const updatedSize = s.toString().length; console.info('initial size', initialSize, 'vs', updatedSize); s.modify('extend', 'right', 'character'); console.info(left, right); return null; }