diff --git a/package-lock.json b/package-lock.json index 1f78785..673ac1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "squire-rte", - "version": "2.2.6", + "version": "2.2.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "squire-rte", - "version": "2.2.6", + "version": "2.2.7", "license": "MIT", "devDependencies": { "@babel/core": "^7.22.20", diff --git a/source/Clipboard.ts b/source/Clipboard.ts index f42d5de..5e1ae5c 100644 --- a/source/Clipboard.ts +++ b/source/Clipboard.ts @@ -290,7 +290,7 @@ const _onPaste = function (this: Squire, event: ClipboardEvent): void { // No interface. Includes all versions of IE :( // -------------------------------------------- - const body = document.body; + const body = this._document.body; const range = this.getSelection(); const startContainer = range.startContainer; const startOffset = range.startOffset; diff --git a/source/Editor.ts b/source/Editor.ts index e0403bd..e7d83b2 100644 --- a/source/Editor.ts +++ b/source/Editor.ts @@ -97,6 +97,8 @@ interface SquireConfig { class Squire { _root: HTMLElement; + _document: Document; + _window: Window; _config: SquireConfig; _isFocused: boolean; @@ -124,6 +126,8 @@ class Squire { constructor(root: HTMLElement, config?: Partial) { this._root = root; + this._document = root.ownerDocument || document; + this._window = this._document.defaultView || window; this._config = this._makeConfig(config); @@ -235,9 +239,10 @@ class Squire { RETURN_DOM_FRAGMENT: true, FORCE_BODY: false, }); + const doc = this._document; return frag - ? document.importNode(frag, true) - : document.createDocumentFragment(); + ? doc.importNode(frag, true) + : doc.createDocumentFragment(); }, didError: (error: any): void => console.log(error), }; @@ -358,7 +363,8 @@ class Squire { // an infinite loop. So we detect whether we're actually // focused/blurred before firing. if (/^(?:focus|blur)/.test(type)) { - const isFocused = this._root === document.activeElement; + const shadow = this._root.getRootNode(); // either Document, ShadowRoot or orphan node itself + const isFocused = 'activeElement' in shadow && this._root === shadow.activeElement; if (type === 'focus') { if (!isFocused || this._isFocused) { return this; @@ -417,7 +423,7 @@ class Squire { this._events.set(type, handlers); if (!this.customEvents.has(type)) { if (type === 'selectionchange') { - target = document; + target = this._document; } target.addEventListener(type, this, true); } @@ -444,7 +450,7 @@ class Squire { this._events.delete(type); if (!this.customEvents.has(type)) { if (type === 'selectionchange') { - target = document; + target = this._document; } target.removeEventListener(type, this, true); } @@ -548,7 +554,7 @@ class Squire { end.remove(); if (!range) { - range = document.createRange(); + range = this._document.createRange(); } range.setStart(startContainer, startOffset); range.setEnd(endContainer, endOffset); @@ -580,7 +586,7 @@ class Squire { } getSelection(): Range { - const selection = window.getSelection(); + const selection = this._window.getSelection(); const root = this._root; let range: Range | null = null; // If not focused, always rely on cached selection; another function may @@ -603,7 +609,7 @@ class Squire { range = this._lastSelection; // Check the editor is in the live document; if not, the range has // probably been rewritten by the browser and is bogus - if (!document.contains(range.commonAncestorContainer)) { + if (!root.getRootNode().contains(range.commonAncestorContainer)) { range = null; } } @@ -621,7 +627,7 @@ class Squire { if (!this._isFocused) { this._enableRestoreSelection(); } else { - const selection = window.getSelection(); + const selection = this._window.getSelection(); if (selection) { if ('setBaseAndExtent' in Selection.prototype) { selection.setBaseAndExtent( @@ -1174,7 +1180,7 @@ class Squire { let offset = range.startOffset; let textNode: Text; if (!startContainer || !(startContainer instanceof Text)) { - const text = document.createTextNode(''); + const text = this._document.createTextNode(''); startContainer.insertBefore( text, startContainer.childNodes[offset], @@ -1521,11 +1527,9 @@ class Squire { // formatted text. let fixer: Node | Text | null | undefined; if (range.collapsed) { - if (cantFocusEmptyTextNodes) { - fixer = document.createTextNode(ZWS); - } else { - fixer = document.createTextNode(''); - } + fixer = this._document.createTextNode( + cantFocusEmptyTextNodes ? ZWS : '' + ); insertNodeInRange(range, fixer!); } @@ -1697,7 +1701,7 @@ class Squire { } insertNodeInRange( range, - document.createTextNode(url.slice(protocolEnd)), + this._document.createTextNode(url.slice(protocolEnd)), ); } attributes = Object.assign( @@ -1806,7 +1810,7 @@ class Squire { const endIndex = index + match[0].length; if (index) { parent.insertBefore( - document.createTextNode(data.slice(0, index)), + this._document.createTextNode(data.slice(0, index)), node, ); } @@ -1979,7 +1983,7 @@ class Squire { node = range.startContainer; const offset = range.startOffset; if (!(node instanceof Text)) { - node = document.createTextNode(''); + node = this._document.createTextNode(''); parent.insertBefore(node, parent.firstChild); } // If blank line: split and insert default block @@ -2111,7 +2115,7 @@ class Squire { (!nodeAfterSplit.textContent || nodeAfterSplit.textContent === ZWS) ) { - child = document.createTextNode('') as Text; + child = this._document.createTextNode('') as Text; replaceWith(nodeAfterSplit, child); nodeAfterSplit = child; break; @@ -2540,7 +2544,7 @@ class Squire { if (range.collapsed || isContainer(range.commonAncestorContainer)) { this.modifyBlocks((frag) => { const root = this._root; - const output = document.createDocumentFragment(); + const output = this._document.createDocumentFragment(); const blockWalker = getBlockWalker(frag, root); let node: Element | Text | null; // 1. Extract inline content; drop all blocks and contains. @@ -2563,7 +2567,7 @@ class Squire { if (!brBreaksLine[l]) { detach(br); } else { - replaceWith(br, document.createTextNode('\n')); + replaceWith(br, this._document.createTextNode('\n')); } } // 3. Remove ; its format clashes with
@@ -2573,7 +2577,7 @@ class Squire {
                         replaceWith(nodes[l], empty(nodes[l]));
                     }
                     if (output.childNodes.length) {
-                        output.appendChild(document.createTextNode('\n'));
+                        output.appendChild(this._document.createTextNode('\n'));
                     }
                     output.appendChild(empty(node));
                 }
@@ -2620,11 +2624,11 @@ class Squire {
                     while ((node = walker.nextNode())) {
                         let value = node.data;
                         value = value.replace(/ (?= )/g, ' '); // sp -> nbsp
-                        const contents = document.createDocumentFragment();
+                        const contents = this._document.createDocumentFragment();
                         let index: number;
                         while ((index = value.indexOf('\n')) > -1) {
                             contents.appendChild(
-                                document.createTextNode(value.slice(0, index)),
+                                this._document.createTextNode(value.slice(0, index)),
                             );
                             contents.appendChild(createElement('BR'));
                             value = value.slice(index + 1);
@@ -2679,7 +2683,7 @@ class Squire {
                     this.createDefaultBlock([
                         this._removeFormatting(
                             node as Element,
-                            document.createDocumentFragment(),
+                            this._document.createDocumentFragment(),
                         ),
                     ]),
                 );
@@ -2726,8 +2730,8 @@ class Squire {
 
         // Split end point first to avoid problems when end and start
         // in same container.
-        const formattedNodes = document.createDocumentFragment();
-        const cleanNodes = document.createDocumentFragment();
+        const formattedNodes = this._document.createDocumentFragment();
+        const cleanNodes = this._document.createDocumentFragment();
         const nodeAfterSplit = split(endContainer, endOffset, stopNode, root);
         let nodeInSplit = split(startContainer, startOffset, stopNode, root);
         let nextNode: ChildNode | null;
diff --git a/source/keyboard/KeyHandlers.ts b/source/keyboard/KeyHandlers.ts
index e829e83..b6df49c 100644
--- a/source/keyboard/KeyHandlers.ts
+++ b/source/keyboard/KeyHandlers.ts
@@ -92,7 +92,7 @@ const keyHandlers: Record = {
                 if (node.nodeName === 'CODE') {
                     let next = node.nextSibling;
                     if (!(next instanceof Text)) {
-                        const textNode = document.createTextNode(' '); // nbsp
+                        const textNode = self._document.createTextNode(' '); // nbsp
                         node.parentNode!.insertBefore(textNode, next);
                         next = textNode;
                     }
diff --git a/source/node/MergeSplit.ts b/source/node/MergeSplit.ts
index 4e8f5fe..702e994 100644
--- a/source/node/MergeSplit.ts
+++ b/source/node/MergeSplit.ts
@@ -31,11 +31,7 @@ const fixCursor = (node: Node): Node => {
             }
         }
         if (!child) {
-            if (cantFocusEmptyTextNodes) {
-                fixer = document.createTextNode(ZWS);
-            } else {
-                fixer = document.createTextNode('');
-            }
+            fixer = document.createTextNode(cantFocusEmptyTextNodes ? ZWS : '');
         }
     } else if (
         (node instanceof Element || node instanceof DocumentFragment) &&
diff --git a/source/range/Boundaries.ts b/source/range/Boundaries.ts
index 2908bc2..9c4d496 100644
--- a/source/range/Boundaries.ts
+++ b/source/range/Boundaries.ts
@@ -15,7 +15,7 @@ const isNodeContainedInRange = (
     node: Node,
     partial: boolean,
 ): boolean => {
-    const nodeRange = document.createRange();
+    const nodeRange = (node.ownerDocument || document).createRange();
     nodeRange.selectNode(node);
     if (partial) {
         // Node must not finish before range starts or start after range
diff --git a/source/range/InsertDelete.ts b/source/range/InsertDelete.ts
index c31c069..c69572f 100644
--- a/source/range/InsertDelete.ts
+++ b/source/range/InsertDelete.ts
@@ -36,7 +36,7 @@ function createRange(
     endContainer?: Node,
     endOffset?: number,
 ): Range {
-    const range = document.createRange();
+    const range = (startContainer.ownerDocument || document).createRange();
     range.setStart(startContainer, startOffset);
     if (endContainer && typeof endOffset === 'number') {
         range.setEnd(endContainer, endOffset);
@@ -108,7 +108,7 @@ const extractContentsOfRange = (
     common: Node | null,
     root: Element,
 ): DocumentFragment => {
-    const frag = document.createDocumentFragment();
+    const frag = (root.ownerDocument || document).createDocumentFragment();
     if (range.collapsed) {
         return frag;
     }
@@ -363,7 +363,7 @@ const insertTreeFragmentIntoRange = (
         }
         if (/*isBlock( container ) && */ offset !== getLength(container)) {
             // Collect any inline contents of the block after the range point
-            blockContentsAfterSplit = document.createDocumentFragment();
+            blockContentsAfterSplit = (root.ownerDocument || document).createDocumentFragment();
             while ((node = container.childNodes[offset])) {
                 blockContentsAfterSplit.appendChild(node);
             }