Skip to content

Commit

Permalink
Store realm nodes in a temporary fragment.
Browse files Browse the repository at this point in the history
  • Loading branch information
edoardocavazza committed Jan 22, 2024
1 parent d13b66d commit 3ca21f6
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/honest-rabbits-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chialab/quantum": patch
---

Store realm nodes in a temporary fragment.
37 changes: 22 additions & 15 deletions src/Realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ export class Realm {
*/
_childNodes;

/**
* The fragment used to temporary store nodes.
* @type {DocumentFragment}
* @protected
*/
_fragment;

/**
* The callbacks to call when the realm changes.
* @type {Set<RealmChangeCallback>}
Expand All @@ -152,6 +159,7 @@ export class Realm {
constructor(node) {
this._node = node;
this._document = node.ownerDocument || document;
this._fragment = this._document.createDocumentFragment();

const store = new Map();
const proto = Object.getPrototypeOf(node);
Expand Down Expand Up @@ -234,7 +242,7 @@ export class Realm {
this._childNodes = [].slice.call(this.node.childNodes);

this._childNodes.forEach((node) => {
node.remove();
this._fragment.appendChild(node);
if (!getOwnerRealm(node)) {
setParentRealm(node, this);
}
Expand Down Expand Up @@ -339,6 +347,7 @@ export class Realm {
if (typeof node === 'string') {
node = this._document.createTextNode(node);
setParentRealm(node, this);
this._fragment.appendChild(node);
acc.push(/** @type {ChildNode} */ (node));
} else if (node.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
this._importNodes(Array.from(node.childNodes), acc);
Expand All @@ -348,9 +357,11 @@ export class Realm {
if (!ownerRealm.contains(this)) {
ownerRealm.remove(/** @type {ChildNode} */ (node));
setParentRealm(node, this);
this._fragment.appendChild(node);
}
} else {
setParentRealm(node, this);
this._fragment.appendChild(node);
}
acc.push(/** @type {ChildNode} */ (node));
}
Expand All @@ -365,13 +376,12 @@ export class Realm {
* @returns The nodes that were appended.
*/
_append(nodes) {
const changed = this._importNodes(nodes).map((child) => {
const changed = this._importNodes(nodes);
changed.forEach((child) => {
const previousIndex = this._childNodes.indexOf(child);
if (previousIndex !== -1) {
this._childNodes.splice(previousIndex, 1);
}

return child;
});
this._childNodes.push(...changed);

Expand All @@ -385,13 +395,12 @@ export class Realm {
* @returns The nodes that were prepended.
*/
_prepend(nodes) {
const changed = this._importNodes(nodes).map((child) => {
const changed = this._importNodes(nodes);
changed.forEach((child) => {
const previousIndex = this._childNodes.indexOf(child);
if (previousIndex !== -1) {
this._childNodes.splice(previousIndex, 1);
}

return child;
});
this._childNodes.unshift(...changed);

Expand All @@ -412,6 +421,9 @@ export class Realm {
setParentRealm(child, null);
}
this._childNodes.splice(io, 1);
if (this._fragment.contains(child)) {
this._fragment.removeChild(child);
}
} else {
throw new Error(
"Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node."
Expand All @@ -437,19 +449,14 @@ export class Realm {
);
}

const changed = this._importNodes(nodes).map((child) => {
const changed = this._importNodes(nodes);
changed.forEach((child) => {
const previousIndex = this._childNodes.indexOf(child);
if (previousIndex !== -1) {
this._childNodes.splice(previousIndex, 1);
}

return child;
});
if (io === 0) {
this._childNodes.unshift(...changed);
} else {
this._childNodes.splice(io, 0, ...changed);
}
this._childNodes.splice(io, 0, ...changed);

return changed;
}
Expand Down
9 changes: 9 additions & 0 deletions tests/realm.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,13 @@ describe('realm', () => {
expect(container.firstChild.textContent).toBe('test');
expect(child.parentNode).toBe(null);
});

test('Slotted elements are selectable', () => {
const container = document.createElement('div');
const child = document.createTextNode('test');
container.append(child);
attachRealm(container);
const range = document.createRange();
expect(() => range.selectNode(child)).not.toThrow();
});
});

0 comments on commit 3ca21f6

Please sign in to comment.