PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
2.0.14 2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / assets / js / ai-capture.js

ai-capture.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at assets/js/ai-capture.js

79 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /** Private static section previews. Never changes the editor's viewport or saved blocks. */
2 (function () {
3 'use strict';
4 window.bkbgCaptureSection = async function (source, viewport, signal, rendered) {
5 if (!source || !source.isConnected) { throw new Error('The editor canvas is unavailable. Wait for the section to render or open the editor in a supported browser.'); }
6 if (!window.htmlToImage) { throw new Error('Screenshot renderer is unavailable. Reload the editor.'); }
7 var width = viewport === 'mobile' ? 390 : 1280;
8 var frame = document.createElement('iframe');
9 frame.setAttribute('sandbox', 'allow-same-origin');
10 frame.setAttribute('aria-hidden', 'true'); frame.tabIndex = -1;
11 frame.style.cssText = 'position:fixed;left:-100000px;top:0;width:' + width + 'px;height:2000px;border:0;pointer-events:none;';
12 var timer, rejectStop;
13 var stopped = new Promise(function (_, reject) { rejectStop = reject; });
14 function abort() { rejectStop(new Error('Section capture cancelled.')); }
15 function check() { if ((signal && signal.aborted) || !source.isConnected || !frame.isConnected) { throw new Error('Section changed or capture cancelled.'); } }
16 if (signal) { signal.addEventListener('abort', abort, { once: true }); }
17 timer = setTimeout(function () { rejectStop(new Error('Section capture timed out. Check image and font loading, then retry.')); }, 30000);
18 async function capture() {
19 document.body.appendChild(frame);
20 var doc = frame.contentDocument, original = source.ownerDocument;
21 if (!doc || !doc.head || !doc.body) { throw new Error('Capture canvas is not ready. Retry.'); }
22 doc.documentElement.className = original.documentElement.className;
23 doc.documentElement.style.cssText = original.documentElement.style.cssText;
24 doc.body.style.cssText = original.body.style.cssText;
25 doc.documentElement.lang = original.documentElement.lang;
26 doc.documentElement.dir = original.documentElement.dir;
27 var loads = [];
28 original.querySelectorAll('style,link[rel="stylesheet"]').forEach(function (item) {
29 var clone = item.cloneNode(true);
30 Array.from(clone.attributes).forEach(function (attr) { if (/^on/i.test(attr.name)) { clone.removeAttribute(attr.name); } });
31 if (clone.tagName === 'LINK') {
32 clone.href = item.href;
33 loads.push(new Promise(function (resolve, reject) { clone.onload = resolve; clone.onerror = function () { reject(new Error('A stylesheet could not load in the preview.')); }; }));
34 }
35 doc.head.appendChild(clone);
36 });
37 doc.body.className = original.body.className;
38 var host = doc.createElement('div');
39 host.className = 'editor-styles-wrapper';
40 host.style.cssText = 'width:100%;max-width:none;margin:0;padding:0;';
41 doc.body.appendChild(host);
42 if (!rendered || !rendered.html) { throw new Error('WordPress did not render this section.'); }
43 host.innerHTML = rendered.html;
44 var theme = doc.createElement('style'); theme.textContent = rendered.themeCss || ''; doc.head.appendChild(theme);
45 host.querySelectorAll('style').forEach(function (style) { doc.head.appendChild(style); });
46 var target = host.firstElementChild;
47 if (!target) { throw new Error('The rendered section is empty.'); }
48 var warnings = [];
49 if (target.querySelector('video,canvas,iframe')) { warnings.push('Video, canvas, embedded frames and interactive states may not be represented. Inspect them with browser tools separately.'); }
50 target.querySelectorAll('script,iframe,video,canvas').forEach(function (node) { node.remove(); });
51 [target].concat(Array.from(doc.body.querySelectorAll('*'))).forEach(function (node) {
52 Array.from(node.attributes).forEach(function (attr) { if (/^on/i.test(attr.name) || attr.name === 'autofocus') { node.removeAttribute(attr.name); } });
53 node.removeAttribute('contenteditable');
54 });
55 var css = doc.createElement('style');
56 css.textContent = 'html,body{margin:0!important;padding:0!important;min-width:0!important;}body{width:100%!important;}*,*::before,*::after{animation:none!important;transition:none!important;caret-color:transparent!important;} .block-editor-block-list__block::before,.block-editor-block-list__block::after{display:none!important;} .block-editor-block-list__block{outline:none!important;} .block-editor-block-list__layout{max-width:none!important;margin:0!important;}';
57 css.textContent += '.editor-styles-wrapper{padding:0!important;margin:0!important;max-width:none!important;width:100%!important;min-height:0!important;height:auto!important;display:flow-root!important;}';
58 doc.head.appendChild(css);
59 await Promise.all(loads); check();
60 // Two layout frames let styles/media queries settle in the isolated viewport.
61 await new Promise(function (resolve) { requestAnimationFrame(function () { requestAnimationFrame(resolve); }); });
62 if (doc.fonts) { await doc.fonts.ready; } check();
63 await Promise.all(Array.from(target.querySelectorAll('img')).map(async function (img) {
64 img.loading = 'eager';
65 if (img.decode) { try { await img.decode(); } catch (e) { warnings.push('An image could not be loaded: ' + (img.alt || 'unnamed image')); } }
66 }));
67 check();
68 var rect = target.getBoundingClientRect(), height = Math.ceil(rect.height);
69 if (height < 1 || height > 6000 || rect.width < 1) { throw new Error('Section is empty or too tall to capture. Capture a smaller nested block (maximum height 6000px).'); }
70 var png = await window.htmlToImage.toPng(target, { pixelRatio: 1, width: Math.ceil(rect.width), height: height, backgroundColor: '#ffffff', preferredFontFormat: 'woff2' });
71 check();
72 if (png.length > 4200000) { throw new Error('Section screenshot is too large. Capture a smaller nested block.'); }
73 return { data: png, viewport: viewport, width: Math.ceil(rect.width), height: height, warnings: warnings, kind: 'wordpress-static-render' };
74 }
75 try { return await Promise.race([capture(), stopped]); }
76 finally { clearTimeout(timer); if (signal) { signal.removeEventListener('abort', abort); } frame.remove(); }
77 };
78 })();
79