Skip to content

Commit 6c1f54d

Browse files
committed
Trim cloning down to deepCloneBasic
1 parent 97ea427 commit 6c1f54d

5 files changed

Lines changed: 24 additions & 759 deletions

File tree

src/snapdom/cache.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/snapdom/clone.js

Lines changed: 24 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
* @module clone
2828
*/
2929

30-
import { inlineAllStyles } from './styles.js';
3130

3231
/**
3332
* Freeze the responsive selection of an <img> that has srcset/sizes.
@@ -57,14 +56,11 @@ function freezeImgSrcset(original, cloned) {
5756
* Creates a deep clone of a DOM node, including styles, shadow DOM, and special handling for excluded/placeholder/canvas nodes.
5857
*
5958
* @param {Node} node - Node to clone
60-
* @param {boolean} compress - Whether to compress style keys
61-
* @param {Object} [options={}] - Capture options including exclude and filter
62-
* @param {Node} [originalRoot] - Original root element being captured
6359
* @returns {Node|null} Cloned node with styles and shadow DOM content, or null for empty text nodes or filtered elements
6460
*/
6561

6662

67-
export function deepClone(node, styleMap = new Map(), styleCache = new WeakMap(), nodeMap = new Map(), compress, options = {}, originalRoot) {
63+
export function deepCloneBasic(node) {
6864
if (!node) throw new Error('Invalid node');
6965

7066
// Local set to avoid duplicates in slot processing
@@ -81,81 +77,28 @@ export function deepClone(node, styleMap = new Map(), styleCache = new WeakMap()
8177
return node.cloneNode(true);
8278
}
8379

84-
// 3. Exclude by attribute
85-
if (node.getAttribute("data-capture") === "exclude") {
86-
const spacer = document.createElement("div");
87-
const rect = node.getBoundingClientRect();
88-
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
89-
return spacer;
90-
}
91-
92-
// 4. Exclude by selectors
93-
if (options.exclude && Array.isArray(options.exclude)) {
94-
for (const selector of options.exclude) {
95-
try {
96-
if (node.matches?.(selector)) {
97-
const spacer = document.createElement("div");
98-
const rect = node.getBoundingClientRect();
99-
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
100-
return spacer;
101-
}
102-
} catch (err) {
103-
console.warn(`Invalid selector in exclude option: ${selector}`, err);
104-
}
105-
}
106-
}
107-
108-
// 5. Custom filter function
109-
if (typeof options.filter === "function") {
110-
try {
111-
if (!options.filter(node, originalRoot || node)) {
112-
const spacer = document.createElement("div");
113-
const rect = node.getBoundingClientRect();
114-
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
115-
return spacer;
116-
}
117-
} catch (err) {
118-
console.warn("Error in filter function:", err);
119-
}
120-
}
121-
12280
// 6. Special case: iframe → fallback pattern
12381
if (node.tagName === "IFRAME") {
12482
const fallback = document.createElement("div");
12583
fallback.style.cssText = `width:${node.offsetWidth}px;height:${node.offsetHeight}px;background-image:repeating-linear-gradient(45deg,#ddd,#ddd 5px,#f9f9f9 5px,#f9f9f9 10px);display:flex;align-items:center;justify-content:center;font-size:12px;color:#555;border:1px solid #aaa;`;
12684
return fallback;
12785
}
12886

129-
// 7. Placeholder nodes
130-
if (node.getAttribute("data-capture") === "placeholder") {
131-
const clone2 = node.cloneNode(false);
132-
nodeMap.set(clone2, node);
133-
if (!options.skipInlineStyles) inlineAllStyles(node, clone2, styleMap, styleCache, compress);
134-
const placeholder = document.createElement("div");
135-
placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
136-
placeholder.style.cssText = `color:#666;font-size:12px;text-align:center;line-height:1.4;padding:0.5em;box-sizing:border-box;`;
137-
clone2.appendChild(placeholder);
138-
return clone2;
139-
}
140-
14187
// 8. Canvas → convert to image
14288
if (node.tagName === "CANVAS") {
14389
const dataURL = node.toDataURL();
14490
const img = document.createElement("img");
14591
img.src = dataURL;
14692
img.width = node.width;
14793
img.height = node.height;
148-
nodeMap.set(img, node);
149-
if (!options.skipInlineStyles) inlineAllStyles(node, img, styleMap, styleCache, compress);
15094
return img;
15195
}
15296

15397
// 9. Base clone (without children)
15498
let clone;
15599
try {
156100
clone = node.cloneNode(false);
157-
nodeMap.set(clone, node);
158-
101+
159102
if (node.tagName === 'IMG') {
160103
freezeImgSrcset(node, clone);
161104
}
@@ -191,37 +134,19 @@ export function deepClone(node, styleMap = new Map(), styleCache = new WeakMap()
191134
pendingSelectValue = node.value;
192135
}
193136

194-
// 11. Inline styles
195-
if (!options.skipInlineStyles) inlineAllStyles(node, clone, styleMap, styleCache, compress);
196-
197137
// 12. ShadowRoot logic
198138
if (node.shadowRoot) {
199139
const hasSlot = Array.from(node.shadowRoot.querySelectorAll("slot")).length > 0;
200140

201141
if (hasSlot) {
202-
// ShadowRoot with slots: only store styles
203-
for (const child of node.shadowRoot.childNodes) {
204-
if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "STYLE") {
205-
const cssText = child.textContent || "";
206-
if (cssText.trim() && compress) {
207-
//if (!cache.preStyle) cache.preStyle = new WeakMap();
208-
styleCache.set(child, cssText);
209-
}
210-
}
211-
}
212142
} else {
213143
// ShadowRoot without slots: clone full content
214144
const shadowFrag = document.createDocumentFragment();
215145
for (const child of node.shadowRoot.childNodes) {
216146
if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "STYLE") {
217-
const cssText = child.textContent || "";
218-
if (cssText.trim() && compress) {
219-
// if (!cache.preStyle) cache.preStyle = new WeakMap();
220-
styleCache.set(child, cssText);
221-
}
222147
continue;
223148
}
224-
const clonedChild = deepClone(child, styleMap, styleCache, nodeMap, compress, options, originalRoot || node);
149+
const clonedChild = deepCloneBasic(child);
225150
if (clonedChild) shadowFrag.appendChild(clonedChild);
226151
}
227152
clone.appendChild(shadowFrag);
@@ -235,7 +160,7 @@ export function deepClone(node, styleMap = new Map(), styleCache = new WeakMap()
235160
const fragment = document.createDocumentFragment();
236161

237162
for (const child of nodesToClone) {
238-
const clonedChild = deepClone(child, styleMap, styleCache, nodeMap, compress, options, originalRoot || node);
163+
const clonedChild = deepCloneBasic(child);
239164
if (clonedChild) fragment.appendChild(clonedChild);
240165
}
241166
return fragment;
@@ -245,7 +170,7 @@ export function deepClone(node, styleMap = new Map(), styleCache = new WeakMap()
245170
for (const child of node.childNodes) {
246171
if (clonedAssignedNodes.has(child)) continue;
247172

248-
const clonedChild = deepClone(child, styleMap, styleCache, nodeMap, compress, options, originalRoot || node);
173+
const clonedChild = deepCloneBasic(child);
249174
if (clonedChild) clone.appendChild(clonedChild);
250175
}
251176

@@ -261,5 +186,24 @@ export function deepClone(node, styleMap = new Map(), styleCache = new WeakMap()
261186
}
262187
}
263188

189+
// Fix scrolling (taken from prepareClone).
190+
const scrollX = node.scrollLeft;
191+
const scrollY = node.scrollTop;
192+
const hasScroll = scrollX || scrollY;
193+
if (hasScroll && clone instanceof HTMLElement) {
194+
clone.style.overflow = "hidden";
195+
clone.style.scrollbarWidth = "none";
196+
clone.style.msOverflowStyle = "none";
197+
const inner = document.createElement("div");
198+
inner.style.transform = `translate(${-scrollX}px, ${-scrollY}px)`;
199+
inner.style.willChange = "transform";
200+
inner.style.display = "inline-block";
201+
inner.style.width = "100%";
202+
while (clone.firstChild) {
203+
inner.appendChild(clone.firstChild);
204+
}
205+
clone.appendChild(inner);
206+
}
207+
264208
return clone;
265209
}

src/snapdom/cssTools.js

Lines changed: 0 additions & 169 deletions
This file was deleted.

0 commit comments

Comments
 (0)