@accelerated-agency/visual-editor 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +11 -54
- package/dist/vite.cjs +181 -21
- package/dist/vite.js +181 -21
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -4960,7 +4960,7 @@ function PlatformVisualEditorV2({
|
|
|
4960
4960
|
window.addEventListener("message", listener);
|
|
4961
4961
|
return () => window.removeEventListener("message", listener);
|
|
4962
4962
|
}, [handleMessage]);
|
|
4963
|
-
|
|
4963
|
+
useCallback(
|
|
4964
4964
|
(tab) => onTabChange?.(tab),
|
|
4965
4965
|
[onTabChange]
|
|
4966
4966
|
);
|
|
@@ -4972,59 +4972,16 @@ function PlatformVisualEditorV2({
|
|
|
4972
4972
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-red-400", children: error })
|
|
4973
4973
|
] }) });
|
|
4974
4974
|
}
|
|
4975
|
-
return /* @__PURE__ */
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
}
|
|
4984
|
-
|
|
4985
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 min-w-0", children: [
|
|
4986
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold tracking-wide px-1.5 py-0.5 rounded bg-indigo-50 text-indigo-600 border border-indigo-100 shrink-0", children: "V2" }),
|
|
4987
|
-
/* @__PURE__ */ jsx("span", { className: "font-semibold text-sm text-slate-800 truncate", children: title ?? experiment?.name ?? "Visual Editor" }),
|
|
4988
|
-
status ? /* @__PURE__ */ jsx("span", { className: "hidden sm:inline-flex text-[10px] px-2 py-0.5 rounded-full border border-slate-200 text-slate-500 font-medium bg-slate-50 capitalize", children: status }) : null,
|
|
4989
|
-
dirty ? /* @__PURE__ */ jsx(
|
|
4990
|
-
"span",
|
|
4991
|
-
{
|
|
4992
|
-
className: "w-1.5 h-1.5 rounded-full bg-amber-400 shrink-0",
|
|
4993
|
-
title: "Unsaved changes"
|
|
4994
|
-
}
|
|
4995
|
-
) : null
|
|
4996
|
-
] }),
|
|
4997
|
-
tabs.length > 0 ? /* @__PURE__ */ jsx("div", { className: "hidden md:flex items-center gap-1 absolute left-1/2 -translate-x-1/2", children: tabs.map((tab) => /* @__PURE__ */ jsx(
|
|
4998
|
-
"button",
|
|
4999
|
-
{
|
|
5000
|
-
type: "button",
|
|
5001
|
-
onClick: () => onTabClick(tab),
|
|
5002
|
-
className: `text-[11px] font-semibold px-3 py-1 rounded-full border transition-all ${tab.label === activeTab ? "bg-indigo-600 text-white border-indigo-600 shadow-sm" : "bg-white text-slate-500 border-slate-200 hover:border-slate-300 hover:text-slate-700"}`,
|
|
5003
|
-
children: tab.label
|
|
5004
|
-
},
|
|
5005
|
-
tab.hash
|
|
5006
|
-
)) }) : null,
|
|
5007
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: showCloseButton ? /* @__PURE__ */ jsx(
|
|
5008
|
-
"button",
|
|
5009
|
-
{
|
|
5010
|
-
type: "button",
|
|
5011
|
-
className: "text-[11px] font-medium px-3 py-1.5 rounded-md border border-slate-200 text-slate-600 hover:bg-slate-50 hover:border-slate-300 transition-all",
|
|
5012
|
-
onClick: () => sendToVvveb("close-editor", {}),
|
|
5013
|
-
children: closeLabel
|
|
5014
|
-
}
|
|
5015
|
-
) : null })
|
|
5016
|
-
] }) : null,
|
|
5017
|
-
/* @__PURE__ */ jsx("div", { className: editorClassName, children: /* @__PURE__ */ jsx(
|
|
5018
|
-
"iframe",
|
|
5019
|
-
{
|
|
5020
|
-
ref: iframeRef,
|
|
5021
|
-
src: editorSrc,
|
|
5022
|
-
className: "w-full h-full border-0",
|
|
5023
|
-
title: "Vvveb Visual Editor",
|
|
5024
|
-
allow: "same-origin"
|
|
5025
|
-
}
|
|
5026
|
-
) })
|
|
5027
|
-
] });
|
|
4975
|
+
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx("div", { className: editorClassName, children: /* @__PURE__ */ jsx(
|
|
4976
|
+
"iframe",
|
|
4977
|
+
{
|
|
4978
|
+
ref: iframeRef,
|
|
4979
|
+
src: editorSrc,
|
|
4980
|
+
className: "w-full h-full border-0",
|
|
4981
|
+
title: "Vvveb Visual Editor",
|
|
4982
|
+
allow: "same-origin"
|
|
4983
|
+
}
|
|
4984
|
+
) }) });
|
|
5028
4985
|
}
|
|
5029
4986
|
var AI_EDITOR_CHANNEL = "ve-ai-editor";
|
|
5030
4987
|
var AI_VIEWPORT_WIDTH = {
|
package/dist/vite.cjs
CHANGED
|
@@ -11,8 +11,20 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
|
11
11
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
12
12
|
|
|
13
13
|
// src/visualEditorProxyPlugin.ts
|
|
14
|
-
var
|
|
15
|
-
var
|
|
14
|
+
var iframeAlwaysShowCss = `<style id="__ce_force_show">#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#onetrust-consent-sdk,#onetrust-banner-sdk,.cc-window,.cc-banner,.cc-overlay,#cookie-notice,#cookie-banner,#cookie-consent,.cookie-notice,.cookie-banner,.cookie-consent,.cookie-popup,.cookie-bar,.cookie-message,.cookie-alert,.gdpr-banner,.gdpr-consent,.gdpr-popup,.gdpr-overlay,#gdpr-consent,#gdpr-banner,.consent-banner,.consent-popup,.consent-overlay,#consent-banner,#consent-popup,[class*="cookie-consent"],[class*="cookie-banner"],[class*="cookie-notice"],[class*="CookieConsent"],[class*="CookieBanner"],[id*="cookie-consent"],[id*="cookie-banner"],[id*="cookie-notice"],[aria-label*="cookie" i],[aria-label*="consent" i],.klaro,.klaro .cookie-modal,#usercentrics-root,.trustarc-banner,#truste-consent-track,#hs-eu-cookie-confirmation,.osano-cm-window,.osano-cm-dialog,.evidon-banner,#_evidon_banner,.js-cookie-consent,.cookie-disclaimer,.shopify-section-cookies,#shopify-section-cookies,#shopify-pc__banner,#shopify-pc__modal,.privacy-banner,.privacy-popup,[data-testid="cookie-banner"],[data-testid="consent-banner"],.amgdprcookie-bar-container,[data-amcookie-js="bar"],.amgdprjs-bar-template,.amgdprcookie-modal-container,.amgdprcookie-modal-overlay,#cmplz-cookiebanner-container,.cmplz-cookiebanner,#iubenda-cs-banner,.iubenda-cs-container,#qc-cmp2-container,.qc-cmp2-consent-info,#didomi-host,.didomi-popup-container,.didomi-notice,#termly-code-snippet-support,[class*="termly"],[class*="gdprcookie"],[class*="amgdpr"],[id*="gdpr-cookie"],[class*="cookie-modal"],[id*="cookie-modal"],[class*="cookieConsent"],[id*="cookieConsent"]{display:revert!important;visibility:visible!important;opacity:1!important;pointer-events:auto!important;height:auto!important;max-height:none!important;overflow:visible!important;}</style>`;
|
|
15
|
+
var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
|
|
16
|
+
function ensureForceShowStyleLast(){
|
|
17
|
+
var style=document.getElementById("__ce_force_show");
|
|
18
|
+
if(!style||!document.head)return;
|
|
19
|
+
if(document.head.lastElementChild!==style){
|
|
20
|
+
document.head.appendChild(style);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
ensureForceShowStyleLast();
|
|
24
|
+
var mo=new MutationObserver(function(){ensureForceShowStyleLast();});
|
|
25
|
+
if(document.head){mo.observe(document.head,{childList:true});}
|
|
26
|
+
window.addEventListener("beforeunload",function(){try{mo.disconnect();}catch(_){}});}
|
|
27
|
+
catch(_){}})();</script>`;
|
|
16
28
|
var AI_SYSTEM_PROMPT = `You are a CRO expert. Return JSON only with: hypothesis, mutations, summary. Keep 2-6 precise mutations and only valid selectors from snapshot.`;
|
|
17
29
|
var BRIDGE_SCRIPT = `(function(){if(window.__CONVERSION_BRIDGE_LOADED__)return;window.__CONVERSION_BRIDGE_LOADED__=true;var CHANNEL='conversion-editor';var highlightEl=null;function send(payload){window.parent.postMessage({channel:CHANNEL,payload:payload},'*');}function qs(selector){try{return document.querySelector(selector);}catch(_){return null;}}function getSelector(el){if(!el||el.nodeType!==1)return'';if(el.id)return'#'+CSS.escape(el.id);var parts=[];var current=el;var depth=0;while(current&¤t.nodeType===1&&depth<5){var part=current.tagName.toLowerCase();if(current.classList&¤t.classList.length){part+='.'+Array.from(current.classList).slice(0,2).map(function(c){return CSS.escape(c);}).join('.');}var parent=current.parentElement;if(parent){var siblings=Array.from(parent.children).filter(function(s){return s.tagName===current.tagName;});if(siblings.length>1)part+=':nth-of-type('+(siblings.indexOf(current)+1)+')';}parts.unshift(part);current=parent;depth+=1;}return parts.join(' > ');}function payloadOf(el){var rect=el.getBoundingClientRect();var style=window.getComputedStyle(el);return{selector:getSelector(el),tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,500),computedStyles:{color:style.color,backgroundColor:style.backgroundColor,fontSize:style.fontSize,fontWeight:style.fontWeight,lineHeight:style.lineHeight,display:style.display},rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}function applyMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.value;break;case'setText':el.textContent=m.value;break;case'setHTML':el.innerHTML=m.value;break;case'setAttribute':if(m.property)el.setAttribute(m.property,m.value);break;case'hide':el.style.display='none';break;case'show':el.style.display='';break;case'insertHTML':if(m.position)el.insertAdjacentHTML(m.position,m.value||'');break;case'insertSection':if(m.position)el.insertAdjacentHTML(m.position,m.sectionHtml||m.value||'');break;case'reorderElement':if(!m.targetSelector)break;var target=qs(m.targetSelector);if(!target||!target.parentNode||!el.parentNode)break;if(m.insertPosition==='before')target.parentNode.insertBefore(el,target);else target.parentNode.insertBefore(el,target.nextSibling);break;default:break;}}function revertMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.previous||'';break;case'setText':el.textContent=m.previous||'';break;case'setHTML':el.innerHTML=m.previous||'';break;case'setAttribute':if(m.property){if(m.previous!=null)el.setAttribute(m.property,m.previous);else el.removeAttribute(m.property);}break;case'hide':case'show':el.style.display=m.previous||'';break;default:break;}}function captureSnapshot(){var elements=Array.from(document.querySelectorAll('h1,h2,h3,p,button,a,input,select,img,section,div')).slice(0,700).map(function(el){var rect=el.getBoundingClientRect();var cs=window.getComputedStyle(el);return{selector:getSelector(el),parentSelector:el.parentElement?getSelector(el.parentElement):null,tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,300),attributes:Array.from(el.attributes||[]).reduce(function(acc,a){acc[a.name]=a.value;return acc;},{}),computedStyles:{color:cs.color,backgroundColor:cs.backgroundColor,fontSize:cs.fontSize,fontWeight:cs.fontWeight,display:cs.display},childrenCount:el.children?el.children.length:0,aboveFold:rect.top<window.innerHeight,depth:(function(){var d=0,p=el.parentElement;while(p&&d<25){d++;p=p.parentElement;}return d;})()};});send({type:'snapshotCaptured',snapshot:{url:window.location.href,title:document.title,viewport:{width:window.innerWidth,height:window.innerHeight},elements:elements}});}function captureTree(){function toNode(el,depth){var rect=el.getBoundingClientRect();var tag=el.tagName.toLowerCase();var type='generic';if(tag==='section')type='section';else if(tag==='img')type='image';else if(tag==='a')type='link';else if(tag==='button')type='button';else if(tag==='form')type='form';else if(['p','h1','h2','h3','h4','h5','h6','span'].indexOf(tag)>=0)type='text';else if(['div','main','article','aside','header','footer','nav'].indexOf(tag)>=0)type='container';var children=Array.from(el.children||[]).slice(0,50).map(function(c){return toNode(c,depth+1);});return{id:getSelector(el),selector:getSelector(el),tagName:tag,label:(el.getAttribute('aria-label')||el.getAttribute('id')||el.className||tag).toString().slice(0,80),type:type,children:children,depth:depth,isAboveFold:rect.top<window.innerHeight,rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}send({type:'pageTreeCaptured',tree:[toNode(document.body,0)]});}window.addEventListener('message',function(e){var msg=e.data;if(!msg||msg.channel!==CHANNEL||!msg.payload)return;var p=msg.payload;switch(p.type){case'ping':send({type:'pong'});break;case'applyMutation':applyMutation(p.mutation);break;case'applyMutationBatch':(p.mutations||[]).forEach(applyMutation);break;case'revert':revertMutation(p.mutation);break;case'clearAllMutations':window.location.reload();break;case'captureSnapshot':captureSnapshot();break;case'validateSelectors':send({type:'selectorsValidated',results:(p.selectors||[]).map(function(s){var el=qs(s);return{selector:s,found:!!el,tagName:el?el.tagName.toLowerCase():null};})});break;case'scrollToElement':case'selectElement':var target=qs(p.selector);if(target){target.scrollIntoView({behavior:'smooth',block:'center'});send({type:'elementSelected',element:payloadOf(target)});}break;case'hoverElement':var h=qs(p.selector);if(h){if(highlightEl)highlightEl.style.outline='';h.style.outline='2px solid #3b82f6';highlightEl=h;}break;case'capturePageTree':captureTree();break;default:break;}});document.addEventListener('click',function(e){var el=e.target;if(!(el instanceof Element))return;send({type:'elementSelected',element:payloadOf(el)});},true);send({type:'bridgeReady'});})();`;
|
|
18
30
|
function buildVvvebEditorHtml() {
|
|
@@ -254,7 +266,7 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
254
266
|
/* \u2500\u2500 DOM tree (Elements tab) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
255
267
|
.dt-tree{font-size:11px;padding:0px 0 0px 20px;user-select:none}
|
|
256
268
|
.dt-row{
|
|
257
|
-
display:flex;align-items:center;gap:2px;min-height:26px;padding:2px 8px 2px 4px;
|
|
269
|
+
width:fit-content;display:flex;align-items:center;gap:2px;min-height:26px;padding:2px 8px 2px 4px;
|
|
258
270
|
cursor:pointer;color:var(--text-2);border-radius:4px;margin:0 4px
|
|
259
271
|
}
|
|
260
272
|
.dt-row:hover{background:var(--bg-hover);color:var(--text)}
|
|
@@ -680,10 +692,10 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
680
692
|
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-magic"></i></button>
|
|
681
693
|
<button class="tb-dk-btn" title="Comments"><i class="bi bi-chat-dots"></i></button>
|
|
682
694
|
</div>
|
|
683
|
-
<!-- btn-close: hidden visually, kept for JS event listener -->
|
|
684
|
-
<button id="btn-close" style="display:none" title="Close editor"></button>
|
|
685
695
|
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"><i class="bi bi-lightning-charge-fill"></i> Simulate</button>
|
|
686
|
-
<button class="tb-fin-btn" id="btn-save">
|
|
696
|
+
<button class="tb-fin-btn" id="btn-save">Save Changes</button>
|
|
697
|
+
<!-- btn-close: kept for JS event listener -->
|
|
698
|
+
<button class="tb-fin-btn" id="btn-close">Close</button>
|
|
687
699
|
</div>
|
|
688
700
|
|
|
689
701
|
<!-- url-bar: hidden, kept for JS compatibility -->
|
|
@@ -1102,6 +1114,8 @@ var iframeContentNavGen = 0;
|
|
|
1102
1114
|
var iframeContentApplyTimer = null;
|
|
1103
1115
|
var iframeEarlyGranularPrimedForGen = null;
|
|
1104
1116
|
var iframeEarlySyncPrimedForGen = null;
|
|
1117
|
+
var iframeEarlyDomSignature = '';
|
|
1118
|
+
var iframeEarlyDomSignatureNavGen = 0;
|
|
1105
1119
|
/** insert/reorder entries are applied from early granular + full apply \u2014 skip exact duplicates per iframe nav */
|
|
1106
1120
|
var appliedStructuralChangesetKeys = {};
|
|
1107
1121
|
var isDirty = false;
|
|
@@ -1113,6 +1127,7 @@ var selectedEl = null;
|
|
|
1113
1127
|
var selectedElFingerprint = '';
|
|
1114
1128
|
var selectedElRecoverMisses = 0;
|
|
1115
1129
|
var MAX_SELECTED_RECOVER_MISSES = 12;
|
|
1130
|
+
var hoveredTreeEl = null;
|
|
1116
1131
|
var isDeselectingSelection = false;
|
|
1117
1132
|
var suppressClickUntil = 0;
|
|
1118
1133
|
var dragAttachDoc = null;
|
|
@@ -1126,6 +1141,7 @@ var iframeSyncAttempts = 0;
|
|
|
1126
1141
|
var selectionScrollWin = null;
|
|
1127
1142
|
var selectionResizeBound = false;
|
|
1128
1143
|
var clickAttachDoc = null;
|
|
1144
|
+
var hoverAttachDoc = null;
|
|
1129
1145
|
var changeObserver = null;
|
|
1130
1146
|
var changeObserverDoc = null;
|
|
1131
1147
|
/** Incremented while applying changesets / selection chrome so MutationObserver does not mark dirty */
|
|
@@ -1338,6 +1354,7 @@ function setMode(mode) {
|
|
|
1338
1354
|
document.getElementById('btn-mode-editor').classList.toggle('active', mode === 'editor');
|
|
1339
1355
|
document.getElementById('btn-mode-nav').classList.toggle('active', mode === 'navigate');
|
|
1340
1356
|
if (mode === 'navigate') {
|
|
1357
|
+
clearTreeHoverHighlight();
|
|
1341
1358
|
setDragHandleActive(false);
|
|
1342
1359
|
deselectElement();
|
|
1343
1360
|
} else if (mode === 'editor') {
|
|
@@ -1721,7 +1738,7 @@ function softReloadEditorIframe() {
|
|
|
1721
1738
|
resetIframeBindings();
|
|
1722
1739
|
setIframePageLoadingUi(true);
|
|
1723
1740
|
iframe.src = appendIframeReloadBust(src);
|
|
1724
|
-
startIframeContentApplyWatcher(navGen);
|
|
1741
|
+
startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
|
|
1725
1742
|
scheduleDomTreeRefresh();
|
|
1726
1743
|
}
|
|
1727
1744
|
|
|
@@ -2200,6 +2217,27 @@ function bodyHasFirstPaintChild(body) {
|
|
|
2200
2217
|
return false;
|
|
2201
2218
|
}
|
|
2202
2219
|
|
|
2220
|
+
function computeIframeDomSignature(doc) {
|
|
2221
|
+
if (!doc || !doc.body) return '';
|
|
2222
|
+
var body = doc.body;
|
|
2223
|
+
var tags = [];
|
|
2224
|
+
var walker = null;
|
|
2225
|
+
try {
|
|
2226
|
+
walker = doc.createTreeWalker(body, NodeFilter.SHOW_ELEMENT, null);
|
|
2227
|
+
} catch(_) {
|
|
2228
|
+
walker = null;
|
|
2229
|
+
}
|
|
2230
|
+
var count = 0;
|
|
2231
|
+
if (walker) {
|
|
2232
|
+
while (walker.nextNode() && count < 400) {
|
|
2233
|
+
var node = walker.currentNode;
|
|
2234
|
+
tags.push((node && node.tagName) ? String(node.tagName).toLowerCase() : '');
|
|
2235
|
+
count += 1;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
return String(body.children ? body.children.length : 0) + '|' + String(count) + '|' + tags.join(',');
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2203
2241
|
/** True when at least one granular changeset selector already matches (nested content painted). */
|
|
2204
2242
|
function granularAnySelectorMatches(doc, cs) {
|
|
2205
2243
|
if (!doc || !cs || !cs.length) return false;
|
|
@@ -2354,6 +2392,7 @@ function resetIframeBindings() {
|
|
|
2354
2392
|
appliedStructuralChangesetKeys = {};
|
|
2355
2393
|
clickAttachDoc = null;
|
|
2356
2394
|
dragAttachDoc = null;
|
|
2395
|
+
hoverAttachDoc = null;
|
|
2357
2396
|
changeObserverDoc = null;
|
|
2358
2397
|
clearPendingGranularChangesets();
|
|
2359
2398
|
if (changeObserver) {
|
|
@@ -2382,7 +2421,7 @@ function loadPage(proxyUrl) {
|
|
|
2382
2421
|
iframe.style.display = 'block';
|
|
2383
2422
|
setIframePageLoadingUi(true);
|
|
2384
2423
|
iframe.src = appendIframeReloadBust(proxyUrl);
|
|
2385
|
-
startIframeContentApplyWatcher(navGen);
|
|
2424
|
+
startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
|
|
2386
2425
|
scheduleDomTreeRefresh();
|
|
2387
2426
|
}
|
|
2388
2427
|
|
|
@@ -2454,7 +2493,7 @@ function switchVariation(varId) {
|
|
|
2454
2493
|
iframe.src = appendIframeReloadBust(src);
|
|
2455
2494
|
// Do not sync here: the document is still the previous navigation until the
|
|
2456
2495
|
// iframe load event; an eager sync attached observers / DOM tree to the wrong document.
|
|
2457
|
-
startIframeContentApplyWatcher(navGen);
|
|
2496
|
+
startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
|
|
2458
2497
|
scheduleDomTreeRefresh();
|
|
2459
2498
|
}
|
|
2460
2499
|
} catch(_) {}
|
|
@@ -2971,10 +3010,12 @@ function reapplyActiveVariationGranular(iframeDoc) {
|
|
|
2971
3010
|
}
|
|
2972
3011
|
|
|
2973
3012
|
/** Poll iframe document during navigation; apply granular edits as soon as DOM can match selectors. */
|
|
2974
|
-
function startIframeContentApplyWatcher(navGen) {
|
|
3013
|
+
function startIframeContentApplyWatcher(navGen, prevDocRef) {
|
|
2975
3014
|
stopIframeContentApplyWatcher();
|
|
2976
3015
|
iframeEarlyGranularPrimedForGen = null;
|
|
2977
3016
|
iframeEarlySyncPrimedForGen = null;
|
|
3017
|
+
iframeEarlyDomSignature = '';
|
|
3018
|
+
iframeEarlyDomSignatureNavGen = navGen;
|
|
2978
3019
|
var iframe = document.getElementById('iframeId');
|
|
2979
3020
|
iframeContentApplyTimer = setInterval(function() {
|
|
2980
3021
|
if (navGen !== iframeContentNavGen) {
|
|
@@ -2984,6 +3025,7 @@ function startIframeContentApplyWatcher(navGen) {
|
|
|
2984
3025
|
try {
|
|
2985
3026
|
var doc = iframe.contentDocument;
|
|
2986
3027
|
if (!doc || !doc.body) return;
|
|
3028
|
+
if (prevDocRef && doc === prevDocRef) return;
|
|
2987
3029
|
var docUrl = '';
|
|
2988
3030
|
try { docUrl = String(doc.URL || ''); } catch(_) {}
|
|
2989
3031
|
if (docUrl === 'about:blank') return;
|
|
@@ -3018,6 +3060,7 @@ function startIframeContentApplyWatcher(navGen) {
|
|
|
3018
3060
|
}
|
|
3019
3061
|
if (iframeEarlySyncPrimedForGen !== navGen) {
|
|
3020
3062
|
iframeEarlySyncPrimedForGen = navGen;
|
|
3063
|
+
iframeEarlyDomSignature = computeIframeDomSignature(doc);
|
|
3021
3064
|
syncIframeInteractions('iframe-early-paint');
|
|
3022
3065
|
}
|
|
3023
3066
|
}
|
|
@@ -3087,6 +3130,8 @@ function injectIframeSelectionStyles(doc) {
|
|
|
3087
3130
|
st.textContent =
|
|
3088
3131
|
'.vve-selected{outline:2px solid #6366f1!important;outline-offset:2px!important;' +
|
|
3089
3132
|
'box-shadow:0 0 0 2px rgba(99,102,241,.28),inset 0 0 0 1px rgba(99,102,241,.18)!important;}' +
|
|
3133
|
+
'.vve-tree-hover{outline:2px solid #6366f1!important;outline-offset:2px!important;' +
|
|
3134
|
+
'box-shadow:0 0 0 2px rgba(99,102,241,.22),inset 0 0 0 1px rgba(99,102,241,.12)!important;}' +
|
|
3090
3135
|
'html.vve-drag-armed .vve-selected{cursor:grab!important;}' +
|
|
3091
3136
|
'.vve-dragging{opacity:0.92!important;outline:2px dashed #f59e0b!important;' +
|
|
3092
3137
|
'outline-offset:2px!important;cursor:grabbing!important;box-shadow:none!important;}';
|
|
@@ -3098,6 +3143,47 @@ function injectIframeSelectionStyles(doc) {
|
|
|
3098
3143
|
}
|
|
3099
3144
|
}
|
|
3100
3145
|
|
|
3146
|
+
function clearTreeHoverHighlight() {
|
|
3147
|
+
if (!hoveredTreeEl) return;
|
|
3148
|
+
beginSuppressIframeMutationDirty();
|
|
3149
|
+
try {
|
|
3150
|
+
if (hoveredTreeEl.classList) hoveredTreeEl.classList.remove('vve-tree-hover');
|
|
3151
|
+
} catch(_) {
|
|
3152
|
+
} finally {
|
|
3153
|
+
endSuppressIframeMutationDirty();
|
|
3154
|
+
hoveredTreeEl = null;
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
function setTreeHoverHighlight(el) {
|
|
3159
|
+
if (!el || el.nodeType !== 1) {
|
|
3160
|
+
clearTreeHoverHighlight();
|
|
3161
|
+
return;
|
|
3162
|
+
}
|
|
3163
|
+
if (hoveredTreeEl === el) return;
|
|
3164
|
+
clearTreeHoverHighlight();
|
|
3165
|
+
beginSuppressIframeMutationDirty();
|
|
3166
|
+
try {
|
|
3167
|
+
if (el.classList) el.classList.add('vve-tree-hover');
|
|
3168
|
+
hoveredTreeEl = el;
|
|
3169
|
+
} catch(_) {
|
|
3170
|
+
hoveredTreeEl = null;
|
|
3171
|
+
} finally {
|
|
3172
|
+
endSuppressIframeMutationDirty();
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
function isTreeHoverOnlyClassMutation(mutation) {
|
|
3177
|
+
if (!mutation || mutation.type !== 'attributes' || mutation.attributeName !== 'class') return false;
|
|
3178
|
+
var oldClass = String(mutation.oldValue || '');
|
|
3179
|
+
var target = mutation.target;
|
|
3180
|
+
var nextClass = '';
|
|
3181
|
+
try {
|
|
3182
|
+
nextClass = target && typeof target.className === 'string' ? target.className : '';
|
|
3183
|
+
} catch(_) {}
|
|
3184
|
+
return oldClass.indexOf('vve-tree-hover') >= 0 || String(nextClass).indexOf('vve-tree-hover') >= 0;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3101
3187
|
function setDragHandleActive(on) {
|
|
3102
3188
|
dragHandleActive = !!on;
|
|
3103
3189
|
var b = document.getElementById('sf-drag');
|
|
@@ -3418,6 +3504,9 @@ function renderDomTree(filterRaw) {
|
|
|
3418
3504
|
if (e.target.closest && e.target.closest('.dt-chev')) return;
|
|
3419
3505
|
selectElementFromTree(el);
|
|
3420
3506
|
};
|
|
3507
|
+
row.onmouseenter = function() {
|
|
3508
|
+
setTreeHoverHighlight(el);
|
|
3509
|
+
};
|
|
3421
3510
|
root.appendChild(row);
|
|
3422
3511
|
|
|
3423
3512
|
if (!hasKids || collapsed) return;
|
|
@@ -3436,6 +3525,9 @@ function renderDomTree(filterRaw) {
|
|
|
3436
3525
|
? '<div class="dt-muted">No elements match your search.</div>'
|
|
3437
3526
|
: '<div class="dt-muted">No visible elements yet.</div>';
|
|
3438
3527
|
}
|
|
3528
|
+
root.onmouseleave = function() {
|
|
3529
|
+
clearTreeHoverHighlight();
|
|
3530
|
+
};
|
|
3439
3531
|
}
|
|
3440
3532
|
|
|
3441
3533
|
// \u2500\u2500 Utility helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -3855,12 +3947,25 @@ function renderRightPanel(el) {
|
|
|
3855
3947
|
var sel = buildSelector(el);
|
|
3856
3948
|
bindings.forEach(function(b){
|
|
3857
3949
|
var inp = document.getElementById(b[0]);
|
|
3858
|
-
if (inp)
|
|
3950
|
+
if (inp) {
|
|
3951
|
+
var onValueChange = function() {
|
|
3859
3952
|
// Read the original value BEFORE applying the change so we can revert later
|
|
3860
3953
|
var orig = getOriginalValue(b[0], el);
|
|
3861
3954
|
b[1](inp.value);
|
|
3862
|
-
|
|
3863
|
-
|
|
3955
|
+
var valueToLog = inp.value;
|
|
3956
|
+
try {
|
|
3957
|
+
console.log('[V2] input changed', {
|
|
3958
|
+
inputId: b[0],
|
|
3959
|
+
rawValue: inp.value,
|
|
3960
|
+
appliedValue: valueToLog,
|
|
3961
|
+
selector: sel,
|
|
3962
|
+
});
|
|
3963
|
+
} catch(_) {}
|
|
3964
|
+
logChange(sel, b[0], valueToLog, el, orig);
|
|
3965
|
+
};
|
|
3966
|
+
inp.addEventListener('input', onValueChange);
|
|
3967
|
+
inp.addEventListener('change', onValueChange);
|
|
3968
|
+
}
|
|
3864
3969
|
});
|
|
3865
3970
|
}
|
|
3866
3971
|
|
|
@@ -4123,6 +4228,32 @@ function attachClickHandler() {
|
|
|
4123
4228
|
} catch(_) {}
|
|
4124
4229
|
}
|
|
4125
4230
|
|
|
4231
|
+
function attachIframeHoverHandler() {
|
|
4232
|
+
try {
|
|
4233
|
+
var iframe = document.getElementById('iframeId');
|
|
4234
|
+
var doc = iframe && iframe.contentDocument;
|
|
4235
|
+
if (!doc || !doc.body) return;
|
|
4236
|
+
if (hoverAttachDoc === doc) return;
|
|
4237
|
+
hoverAttachDoc = doc;
|
|
4238
|
+
doc.addEventListener('mousemove', function(e) {
|
|
4239
|
+
if (currentMode !== 'editor') {
|
|
4240
|
+
clearTreeHoverHighlight();
|
|
4241
|
+
return;
|
|
4242
|
+
}
|
|
4243
|
+
var target = e.target;
|
|
4244
|
+
if (!target || target === doc.body || target === doc.documentElement) {
|
|
4245
|
+
clearTreeHoverHighlight();
|
|
4246
|
+
return;
|
|
4247
|
+
}
|
|
4248
|
+
setTreeHoverHighlight(target);
|
|
4249
|
+
}, true);
|
|
4250
|
+
doc.addEventListener('mouseout', function(e) {
|
|
4251
|
+
if (e.relatedTarget) return;
|
|
4252
|
+
clearTreeHoverHighlight();
|
|
4253
|
+
}, true);
|
|
4254
|
+
} catch(_) {}
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4126
4257
|
function attachChangeObserver() {
|
|
4127
4258
|
try {
|
|
4128
4259
|
var iframe = document.getElementById('iframeId');
|
|
@@ -4135,6 +4266,14 @@ function attachChangeObserver() {
|
|
|
4135
4266
|
changeObserverDoc = null;
|
|
4136
4267
|
}
|
|
4137
4268
|
changeObserver = new MutationObserver(function(mutations) {
|
|
4269
|
+
var hasMeaningfulMutation = false;
|
|
4270
|
+
for (var mi = 0; mi < mutations.length; mi++) {
|
|
4271
|
+
if (!isTreeHoverOnlyClassMutation(mutations[mi])) {
|
|
4272
|
+
hasMeaningfulMutation = true;
|
|
4273
|
+
break;
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4276
|
+
if (!hasMeaningfulMutation) return;
|
|
4138
4277
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
4139
4278
|
// Host scripts can replace selected nodes every few frames (e.g. A/B tool observers).
|
|
4140
4279
|
// Keep selection sticky by re-resolving from fingerprint.
|
|
@@ -4145,7 +4284,7 @@ function attachChangeObserver() {
|
|
|
4145
4284
|
updateSelectionToolbar();
|
|
4146
4285
|
});
|
|
4147
4286
|
changeObserver.observe(doc.body, {
|
|
4148
|
-
childList: true, subtree: true, attributes: true, characterData: true
|
|
4287
|
+
childList: true, subtree: true, attributes: true, characterData: true, attributeOldValue: true
|
|
4149
4288
|
});
|
|
4150
4289
|
changeObserverDoc = doc;
|
|
4151
4290
|
} catch(_) {}
|
|
@@ -4171,6 +4310,7 @@ function syncIframeInteractions(reason) {
|
|
|
4171
4310
|
injectIframeSelectionStyles(doc);
|
|
4172
4311
|
refreshPersistentChangesetStyleTagForActiveVariation();
|
|
4173
4312
|
attachClickHandler();
|
|
4313
|
+
attachIframeHoverHandler();
|
|
4174
4314
|
attachDragReposition();
|
|
4175
4315
|
attachChangeObserver();
|
|
4176
4316
|
startConsistencyWatchdog(doc);
|
|
@@ -4529,10 +4669,9 @@ window.addEventListener('load', function() {
|
|
|
4529
4669
|
var iframe = document.getElementById('iframeId');
|
|
4530
4670
|
iframe.addEventListener('load', function() {
|
|
4531
4671
|
if (!iframe.src || iframe.src === 'about:blank' || iframe.src === window.location.href) return;
|
|
4532
|
-
// New iframe navigation: always drop bindings tied to the previous document.
|
|
4533
|
-
resetIframeBindings();
|
|
4534
4672
|
var doc = iframe.contentDocument;
|
|
4535
4673
|
if (!doc) {
|
|
4674
|
+
resetIframeBindings();
|
|
4536
4675
|
syncIframeInteractions('iframe-load-no-doc');
|
|
4537
4676
|
return;
|
|
4538
4677
|
}
|
|
@@ -4541,14 +4680,32 @@ window.addEventListener('load', function() {
|
|
|
4541
4680
|
// Stale events: src may already be the proxy URL while the document is still
|
|
4542
4681
|
// about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
|
|
4543
4682
|
if (docUrl === 'about:blank') {
|
|
4683
|
+
resetIframeBindings();
|
|
4544
4684
|
syncIframeInteractions('iframe-load-about-blank');
|
|
4545
4685
|
return;
|
|
4546
4686
|
}
|
|
4687
|
+
// If early-paint and final load DOM signatures match, avoid a second full apply/reset
|
|
4688
|
+
// that steals focus from sidebar controls while the page is still stabilizing.
|
|
4689
|
+
var shouldRefreshOnFinalLoad = true;
|
|
4690
|
+
if (
|
|
4691
|
+
iframeEarlyDomSignatureNavGen === iframeContentNavGen &&
|
|
4692
|
+
iframeEarlySyncPrimedForGen === iframeContentNavGen &&
|
|
4693
|
+
iframeEarlyDomSignature
|
|
4694
|
+
) {
|
|
4695
|
+
var finalDomSignature = computeIframeDomSignature(doc);
|
|
4696
|
+
if (finalDomSignature && finalDomSignature === iframeEarlyDomSignature) {
|
|
4697
|
+
shouldRefreshOnFinalLoad = false;
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
if (clickAttachDoc !== doc || dragAttachDoc !== doc || changeObserverDoc !== doc || hoverAttachDoc !== doc) {
|
|
4701
|
+
resetIframeBindings();
|
|
4702
|
+
}
|
|
4547
4703
|
attachIframeLoadingUntilComplete(iframe);
|
|
4548
4704
|
if (doc.body && iframeDocMatchesNavigatedSrc(iframe, doc)) {
|
|
4549
4705
|
stopIframeContentApplyWatcher();
|
|
4550
|
-
|
|
4551
|
-
|
|
4706
|
+
if (shouldRefreshOnFinalLoad) {
|
|
4707
|
+
applyActiveVariationHtml();
|
|
4708
|
+
}
|
|
4552
4709
|
}
|
|
4553
4710
|
// Always attempt sync; it has its own readiness checks + retry loop.
|
|
4554
4711
|
syncIframeInteractions('iframe-load');
|
|
@@ -4890,9 +5047,12 @@ function createVisualEditorMiddleware(options) {
|
|
|
4890
5047
|
}
|
|
4891
5048
|
);
|
|
4892
5049
|
if (html.includes("</head>")) {
|
|
4893
|
-
html = html.replace(
|
|
4894
|
-
|
|
4895
|
-
|
|
5050
|
+
html = html.replace(
|
|
5051
|
+
"</head>",
|
|
5052
|
+
`${iframeAlwaysShowCss}
|
|
5053
|
+
${iframeAlwaysShowCssGuardScript}
|
|
5054
|
+
</head>`
|
|
5055
|
+
);
|
|
4896
5056
|
}
|
|
4897
5057
|
html = html.replace(
|
|
4898
5058
|
/<meta[^>]+http-equiv=["']?\s*(x-frame-options|content-security-policy)\s*["']?[^>]*>/gi,
|
package/dist/vite.js
CHANGED
|
@@ -3,8 +3,20 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
5
|
// src/visualEditorProxyPlugin.ts
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var iframeAlwaysShowCss = `<style id="__ce_force_show">#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#onetrust-consent-sdk,#onetrust-banner-sdk,.cc-window,.cc-banner,.cc-overlay,#cookie-notice,#cookie-banner,#cookie-consent,.cookie-notice,.cookie-banner,.cookie-consent,.cookie-popup,.cookie-bar,.cookie-message,.cookie-alert,.gdpr-banner,.gdpr-consent,.gdpr-popup,.gdpr-overlay,#gdpr-consent,#gdpr-banner,.consent-banner,.consent-popup,.consent-overlay,#consent-banner,#consent-popup,[class*="cookie-consent"],[class*="cookie-banner"],[class*="cookie-notice"],[class*="CookieConsent"],[class*="CookieBanner"],[id*="cookie-consent"],[id*="cookie-banner"],[id*="cookie-notice"],[aria-label*="cookie" i],[aria-label*="consent" i],.klaro,.klaro .cookie-modal,#usercentrics-root,.trustarc-banner,#truste-consent-track,#hs-eu-cookie-confirmation,.osano-cm-window,.osano-cm-dialog,.evidon-banner,#_evidon_banner,.js-cookie-consent,.cookie-disclaimer,.shopify-section-cookies,#shopify-section-cookies,#shopify-pc__banner,#shopify-pc__modal,.privacy-banner,.privacy-popup,[data-testid="cookie-banner"],[data-testid="consent-banner"],.amgdprcookie-bar-container,[data-amcookie-js="bar"],.amgdprjs-bar-template,.amgdprcookie-modal-container,.amgdprcookie-modal-overlay,#cmplz-cookiebanner-container,.cmplz-cookiebanner,#iubenda-cs-banner,.iubenda-cs-container,#qc-cmp2-container,.qc-cmp2-consent-info,#didomi-host,.didomi-popup-container,.didomi-notice,#termly-code-snippet-support,[class*="termly"],[class*="gdprcookie"],[class*="amgdpr"],[id*="gdpr-cookie"],[class*="cookie-modal"],[id*="cookie-modal"],[class*="cookieConsent"],[id*="cookieConsent"]{display:revert!important;visibility:visible!important;opacity:1!important;pointer-events:auto!important;height:auto!important;max-height:none!important;overflow:visible!important;}</style>`;
|
|
7
|
+
var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
|
|
8
|
+
function ensureForceShowStyleLast(){
|
|
9
|
+
var style=document.getElementById("__ce_force_show");
|
|
10
|
+
if(!style||!document.head)return;
|
|
11
|
+
if(document.head.lastElementChild!==style){
|
|
12
|
+
document.head.appendChild(style);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
ensureForceShowStyleLast();
|
|
16
|
+
var mo=new MutationObserver(function(){ensureForceShowStyleLast();});
|
|
17
|
+
if(document.head){mo.observe(document.head,{childList:true});}
|
|
18
|
+
window.addEventListener("beforeunload",function(){try{mo.disconnect();}catch(_){}});}
|
|
19
|
+
catch(_){}})();</script>`;
|
|
8
20
|
var AI_SYSTEM_PROMPT = `You are a CRO expert. Return JSON only with: hypothesis, mutations, summary. Keep 2-6 precise mutations and only valid selectors from snapshot.`;
|
|
9
21
|
var BRIDGE_SCRIPT = `(function(){if(window.__CONVERSION_BRIDGE_LOADED__)return;window.__CONVERSION_BRIDGE_LOADED__=true;var CHANNEL='conversion-editor';var highlightEl=null;function send(payload){window.parent.postMessage({channel:CHANNEL,payload:payload},'*');}function qs(selector){try{return document.querySelector(selector);}catch(_){return null;}}function getSelector(el){if(!el||el.nodeType!==1)return'';if(el.id)return'#'+CSS.escape(el.id);var parts=[];var current=el;var depth=0;while(current&¤t.nodeType===1&&depth<5){var part=current.tagName.toLowerCase();if(current.classList&¤t.classList.length){part+='.'+Array.from(current.classList).slice(0,2).map(function(c){return CSS.escape(c);}).join('.');}var parent=current.parentElement;if(parent){var siblings=Array.from(parent.children).filter(function(s){return s.tagName===current.tagName;});if(siblings.length>1)part+=':nth-of-type('+(siblings.indexOf(current)+1)+')';}parts.unshift(part);current=parent;depth+=1;}return parts.join(' > ');}function payloadOf(el){var rect=el.getBoundingClientRect();var style=window.getComputedStyle(el);return{selector:getSelector(el),tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,500),computedStyles:{color:style.color,backgroundColor:style.backgroundColor,fontSize:style.fontSize,fontWeight:style.fontWeight,lineHeight:style.lineHeight,display:style.display},rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}function applyMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.value;break;case'setText':el.textContent=m.value;break;case'setHTML':el.innerHTML=m.value;break;case'setAttribute':if(m.property)el.setAttribute(m.property,m.value);break;case'hide':el.style.display='none';break;case'show':el.style.display='';break;case'insertHTML':if(m.position)el.insertAdjacentHTML(m.position,m.value||'');break;case'insertSection':if(m.position)el.insertAdjacentHTML(m.position,m.sectionHtml||m.value||'');break;case'reorderElement':if(!m.targetSelector)break;var target=qs(m.targetSelector);if(!target||!target.parentNode||!el.parentNode)break;if(m.insertPosition==='before')target.parentNode.insertBefore(el,target);else target.parentNode.insertBefore(el,target.nextSibling);break;default:break;}}function revertMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.previous||'';break;case'setText':el.textContent=m.previous||'';break;case'setHTML':el.innerHTML=m.previous||'';break;case'setAttribute':if(m.property){if(m.previous!=null)el.setAttribute(m.property,m.previous);else el.removeAttribute(m.property);}break;case'hide':case'show':el.style.display=m.previous||'';break;default:break;}}function captureSnapshot(){var elements=Array.from(document.querySelectorAll('h1,h2,h3,p,button,a,input,select,img,section,div')).slice(0,700).map(function(el){var rect=el.getBoundingClientRect();var cs=window.getComputedStyle(el);return{selector:getSelector(el),parentSelector:el.parentElement?getSelector(el.parentElement):null,tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,300),attributes:Array.from(el.attributes||[]).reduce(function(acc,a){acc[a.name]=a.value;return acc;},{}),computedStyles:{color:cs.color,backgroundColor:cs.backgroundColor,fontSize:cs.fontSize,fontWeight:cs.fontWeight,display:cs.display},childrenCount:el.children?el.children.length:0,aboveFold:rect.top<window.innerHeight,depth:(function(){var d=0,p=el.parentElement;while(p&&d<25){d++;p=p.parentElement;}return d;})()};});send({type:'snapshotCaptured',snapshot:{url:window.location.href,title:document.title,viewport:{width:window.innerWidth,height:window.innerHeight},elements:elements}});}function captureTree(){function toNode(el,depth){var rect=el.getBoundingClientRect();var tag=el.tagName.toLowerCase();var type='generic';if(tag==='section')type='section';else if(tag==='img')type='image';else if(tag==='a')type='link';else if(tag==='button')type='button';else if(tag==='form')type='form';else if(['p','h1','h2','h3','h4','h5','h6','span'].indexOf(tag)>=0)type='text';else if(['div','main','article','aside','header','footer','nav'].indexOf(tag)>=0)type='container';var children=Array.from(el.children||[]).slice(0,50).map(function(c){return toNode(c,depth+1);});return{id:getSelector(el),selector:getSelector(el),tagName:tag,label:(el.getAttribute('aria-label')||el.getAttribute('id')||el.className||tag).toString().slice(0,80),type:type,children:children,depth:depth,isAboveFold:rect.top<window.innerHeight,rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}send({type:'pageTreeCaptured',tree:[toNode(document.body,0)]});}window.addEventListener('message',function(e){var msg=e.data;if(!msg||msg.channel!==CHANNEL||!msg.payload)return;var p=msg.payload;switch(p.type){case'ping':send({type:'pong'});break;case'applyMutation':applyMutation(p.mutation);break;case'applyMutationBatch':(p.mutations||[]).forEach(applyMutation);break;case'revert':revertMutation(p.mutation);break;case'clearAllMutations':window.location.reload();break;case'captureSnapshot':captureSnapshot();break;case'validateSelectors':send({type:'selectorsValidated',results:(p.selectors||[]).map(function(s){var el=qs(s);return{selector:s,found:!!el,tagName:el?el.tagName.toLowerCase():null};})});break;case'scrollToElement':case'selectElement':var target=qs(p.selector);if(target){target.scrollIntoView({behavior:'smooth',block:'center'});send({type:'elementSelected',element:payloadOf(target)});}break;case'hoverElement':var h=qs(p.selector);if(h){if(highlightEl)highlightEl.style.outline='';h.style.outline='2px solid #3b82f6';highlightEl=h;}break;case'capturePageTree':captureTree();break;default:break;}});document.addEventListener('click',function(e){var el=e.target;if(!(el instanceof Element))return;send({type:'elementSelected',element:payloadOf(el)});},true);send({type:'bridgeReady'});})();`;
|
|
10
22
|
function buildVvvebEditorHtml() {
|
|
@@ -246,7 +258,7 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
246
258
|
/* \u2500\u2500 DOM tree (Elements tab) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
247
259
|
.dt-tree{font-size:11px;padding:0px 0 0px 20px;user-select:none}
|
|
248
260
|
.dt-row{
|
|
249
|
-
display:flex;align-items:center;gap:2px;min-height:26px;padding:2px 8px 2px 4px;
|
|
261
|
+
width:fit-content;display:flex;align-items:center;gap:2px;min-height:26px;padding:2px 8px 2px 4px;
|
|
250
262
|
cursor:pointer;color:var(--text-2);border-radius:4px;margin:0 4px
|
|
251
263
|
}
|
|
252
264
|
.dt-row:hover{background:var(--bg-hover);color:var(--text)}
|
|
@@ -672,10 +684,10 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
672
684
|
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-magic"></i></button>
|
|
673
685
|
<button class="tb-dk-btn" title="Comments"><i class="bi bi-chat-dots"></i></button>
|
|
674
686
|
</div>
|
|
675
|
-
<!-- btn-close: hidden visually, kept for JS event listener -->
|
|
676
|
-
<button id="btn-close" style="display:none" title="Close editor"></button>
|
|
677
687
|
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"><i class="bi bi-lightning-charge-fill"></i> Simulate</button>
|
|
678
|
-
<button class="tb-fin-btn" id="btn-save">
|
|
688
|
+
<button class="tb-fin-btn" id="btn-save">Save Changes</button>
|
|
689
|
+
<!-- btn-close: kept for JS event listener -->
|
|
690
|
+
<button class="tb-fin-btn" id="btn-close">Close</button>
|
|
679
691
|
</div>
|
|
680
692
|
|
|
681
693
|
<!-- url-bar: hidden, kept for JS compatibility -->
|
|
@@ -1094,6 +1106,8 @@ var iframeContentNavGen = 0;
|
|
|
1094
1106
|
var iframeContentApplyTimer = null;
|
|
1095
1107
|
var iframeEarlyGranularPrimedForGen = null;
|
|
1096
1108
|
var iframeEarlySyncPrimedForGen = null;
|
|
1109
|
+
var iframeEarlyDomSignature = '';
|
|
1110
|
+
var iframeEarlyDomSignatureNavGen = 0;
|
|
1097
1111
|
/** insert/reorder entries are applied from early granular + full apply \u2014 skip exact duplicates per iframe nav */
|
|
1098
1112
|
var appliedStructuralChangesetKeys = {};
|
|
1099
1113
|
var isDirty = false;
|
|
@@ -1105,6 +1119,7 @@ var selectedEl = null;
|
|
|
1105
1119
|
var selectedElFingerprint = '';
|
|
1106
1120
|
var selectedElRecoverMisses = 0;
|
|
1107
1121
|
var MAX_SELECTED_RECOVER_MISSES = 12;
|
|
1122
|
+
var hoveredTreeEl = null;
|
|
1108
1123
|
var isDeselectingSelection = false;
|
|
1109
1124
|
var suppressClickUntil = 0;
|
|
1110
1125
|
var dragAttachDoc = null;
|
|
@@ -1118,6 +1133,7 @@ var iframeSyncAttempts = 0;
|
|
|
1118
1133
|
var selectionScrollWin = null;
|
|
1119
1134
|
var selectionResizeBound = false;
|
|
1120
1135
|
var clickAttachDoc = null;
|
|
1136
|
+
var hoverAttachDoc = null;
|
|
1121
1137
|
var changeObserver = null;
|
|
1122
1138
|
var changeObserverDoc = null;
|
|
1123
1139
|
/** Incremented while applying changesets / selection chrome so MutationObserver does not mark dirty */
|
|
@@ -1330,6 +1346,7 @@ function setMode(mode) {
|
|
|
1330
1346
|
document.getElementById('btn-mode-editor').classList.toggle('active', mode === 'editor');
|
|
1331
1347
|
document.getElementById('btn-mode-nav').classList.toggle('active', mode === 'navigate');
|
|
1332
1348
|
if (mode === 'navigate') {
|
|
1349
|
+
clearTreeHoverHighlight();
|
|
1333
1350
|
setDragHandleActive(false);
|
|
1334
1351
|
deselectElement();
|
|
1335
1352
|
} else if (mode === 'editor') {
|
|
@@ -1713,7 +1730,7 @@ function softReloadEditorIframe() {
|
|
|
1713
1730
|
resetIframeBindings();
|
|
1714
1731
|
setIframePageLoadingUi(true);
|
|
1715
1732
|
iframe.src = appendIframeReloadBust(src);
|
|
1716
|
-
startIframeContentApplyWatcher(navGen);
|
|
1733
|
+
startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
|
|
1717
1734
|
scheduleDomTreeRefresh();
|
|
1718
1735
|
}
|
|
1719
1736
|
|
|
@@ -2192,6 +2209,27 @@ function bodyHasFirstPaintChild(body) {
|
|
|
2192
2209
|
return false;
|
|
2193
2210
|
}
|
|
2194
2211
|
|
|
2212
|
+
function computeIframeDomSignature(doc) {
|
|
2213
|
+
if (!doc || !doc.body) return '';
|
|
2214
|
+
var body = doc.body;
|
|
2215
|
+
var tags = [];
|
|
2216
|
+
var walker = null;
|
|
2217
|
+
try {
|
|
2218
|
+
walker = doc.createTreeWalker(body, NodeFilter.SHOW_ELEMENT, null);
|
|
2219
|
+
} catch(_) {
|
|
2220
|
+
walker = null;
|
|
2221
|
+
}
|
|
2222
|
+
var count = 0;
|
|
2223
|
+
if (walker) {
|
|
2224
|
+
while (walker.nextNode() && count < 400) {
|
|
2225
|
+
var node = walker.currentNode;
|
|
2226
|
+
tags.push((node && node.tagName) ? String(node.tagName).toLowerCase() : '');
|
|
2227
|
+
count += 1;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
return String(body.children ? body.children.length : 0) + '|' + String(count) + '|' + tags.join(',');
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2195
2233
|
/** True when at least one granular changeset selector already matches (nested content painted). */
|
|
2196
2234
|
function granularAnySelectorMatches(doc, cs) {
|
|
2197
2235
|
if (!doc || !cs || !cs.length) return false;
|
|
@@ -2346,6 +2384,7 @@ function resetIframeBindings() {
|
|
|
2346
2384
|
appliedStructuralChangesetKeys = {};
|
|
2347
2385
|
clickAttachDoc = null;
|
|
2348
2386
|
dragAttachDoc = null;
|
|
2387
|
+
hoverAttachDoc = null;
|
|
2349
2388
|
changeObserverDoc = null;
|
|
2350
2389
|
clearPendingGranularChangesets();
|
|
2351
2390
|
if (changeObserver) {
|
|
@@ -2374,7 +2413,7 @@ function loadPage(proxyUrl) {
|
|
|
2374
2413
|
iframe.style.display = 'block';
|
|
2375
2414
|
setIframePageLoadingUi(true);
|
|
2376
2415
|
iframe.src = appendIframeReloadBust(proxyUrl);
|
|
2377
|
-
startIframeContentApplyWatcher(navGen);
|
|
2416
|
+
startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
|
|
2378
2417
|
scheduleDomTreeRefresh();
|
|
2379
2418
|
}
|
|
2380
2419
|
|
|
@@ -2446,7 +2485,7 @@ function switchVariation(varId) {
|
|
|
2446
2485
|
iframe.src = appendIframeReloadBust(src);
|
|
2447
2486
|
// Do not sync here: the document is still the previous navigation until the
|
|
2448
2487
|
// iframe load event; an eager sync attached observers / DOM tree to the wrong document.
|
|
2449
|
-
startIframeContentApplyWatcher(navGen);
|
|
2488
|
+
startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
|
|
2450
2489
|
scheduleDomTreeRefresh();
|
|
2451
2490
|
}
|
|
2452
2491
|
} catch(_) {}
|
|
@@ -2963,10 +3002,12 @@ function reapplyActiveVariationGranular(iframeDoc) {
|
|
|
2963
3002
|
}
|
|
2964
3003
|
|
|
2965
3004
|
/** Poll iframe document during navigation; apply granular edits as soon as DOM can match selectors. */
|
|
2966
|
-
function startIframeContentApplyWatcher(navGen) {
|
|
3005
|
+
function startIframeContentApplyWatcher(navGen, prevDocRef) {
|
|
2967
3006
|
stopIframeContentApplyWatcher();
|
|
2968
3007
|
iframeEarlyGranularPrimedForGen = null;
|
|
2969
3008
|
iframeEarlySyncPrimedForGen = null;
|
|
3009
|
+
iframeEarlyDomSignature = '';
|
|
3010
|
+
iframeEarlyDomSignatureNavGen = navGen;
|
|
2970
3011
|
var iframe = document.getElementById('iframeId');
|
|
2971
3012
|
iframeContentApplyTimer = setInterval(function() {
|
|
2972
3013
|
if (navGen !== iframeContentNavGen) {
|
|
@@ -2976,6 +3017,7 @@ function startIframeContentApplyWatcher(navGen) {
|
|
|
2976
3017
|
try {
|
|
2977
3018
|
var doc = iframe.contentDocument;
|
|
2978
3019
|
if (!doc || !doc.body) return;
|
|
3020
|
+
if (prevDocRef && doc === prevDocRef) return;
|
|
2979
3021
|
var docUrl = '';
|
|
2980
3022
|
try { docUrl = String(doc.URL || ''); } catch(_) {}
|
|
2981
3023
|
if (docUrl === 'about:blank') return;
|
|
@@ -3010,6 +3052,7 @@ function startIframeContentApplyWatcher(navGen) {
|
|
|
3010
3052
|
}
|
|
3011
3053
|
if (iframeEarlySyncPrimedForGen !== navGen) {
|
|
3012
3054
|
iframeEarlySyncPrimedForGen = navGen;
|
|
3055
|
+
iframeEarlyDomSignature = computeIframeDomSignature(doc);
|
|
3013
3056
|
syncIframeInteractions('iframe-early-paint');
|
|
3014
3057
|
}
|
|
3015
3058
|
}
|
|
@@ -3079,6 +3122,8 @@ function injectIframeSelectionStyles(doc) {
|
|
|
3079
3122
|
st.textContent =
|
|
3080
3123
|
'.vve-selected{outline:2px solid #6366f1!important;outline-offset:2px!important;' +
|
|
3081
3124
|
'box-shadow:0 0 0 2px rgba(99,102,241,.28),inset 0 0 0 1px rgba(99,102,241,.18)!important;}' +
|
|
3125
|
+
'.vve-tree-hover{outline:2px solid #6366f1!important;outline-offset:2px!important;' +
|
|
3126
|
+
'box-shadow:0 0 0 2px rgba(99,102,241,.22),inset 0 0 0 1px rgba(99,102,241,.12)!important;}' +
|
|
3082
3127
|
'html.vve-drag-armed .vve-selected{cursor:grab!important;}' +
|
|
3083
3128
|
'.vve-dragging{opacity:0.92!important;outline:2px dashed #f59e0b!important;' +
|
|
3084
3129
|
'outline-offset:2px!important;cursor:grabbing!important;box-shadow:none!important;}';
|
|
@@ -3090,6 +3135,47 @@ function injectIframeSelectionStyles(doc) {
|
|
|
3090
3135
|
}
|
|
3091
3136
|
}
|
|
3092
3137
|
|
|
3138
|
+
function clearTreeHoverHighlight() {
|
|
3139
|
+
if (!hoveredTreeEl) return;
|
|
3140
|
+
beginSuppressIframeMutationDirty();
|
|
3141
|
+
try {
|
|
3142
|
+
if (hoveredTreeEl.classList) hoveredTreeEl.classList.remove('vve-tree-hover');
|
|
3143
|
+
} catch(_) {
|
|
3144
|
+
} finally {
|
|
3145
|
+
endSuppressIframeMutationDirty();
|
|
3146
|
+
hoveredTreeEl = null;
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
function setTreeHoverHighlight(el) {
|
|
3151
|
+
if (!el || el.nodeType !== 1) {
|
|
3152
|
+
clearTreeHoverHighlight();
|
|
3153
|
+
return;
|
|
3154
|
+
}
|
|
3155
|
+
if (hoveredTreeEl === el) return;
|
|
3156
|
+
clearTreeHoverHighlight();
|
|
3157
|
+
beginSuppressIframeMutationDirty();
|
|
3158
|
+
try {
|
|
3159
|
+
if (el.classList) el.classList.add('vve-tree-hover');
|
|
3160
|
+
hoveredTreeEl = el;
|
|
3161
|
+
} catch(_) {
|
|
3162
|
+
hoveredTreeEl = null;
|
|
3163
|
+
} finally {
|
|
3164
|
+
endSuppressIframeMutationDirty();
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
function isTreeHoverOnlyClassMutation(mutation) {
|
|
3169
|
+
if (!mutation || mutation.type !== 'attributes' || mutation.attributeName !== 'class') return false;
|
|
3170
|
+
var oldClass = String(mutation.oldValue || '');
|
|
3171
|
+
var target = mutation.target;
|
|
3172
|
+
var nextClass = '';
|
|
3173
|
+
try {
|
|
3174
|
+
nextClass = target && typeof target.className === 'string' ? target.className : '';
|
|
3175
|
+
} catch(_) {}
|
|
3176
|
+
return oldClass.indexOf('vve-tree-hover') >= 0 || String(nextClass).indexOf('vve-tree-hover') >= 0;
|
|
3177
|
+
}
|
|
3178
|
+
|
|
3093
3179
|
function setDragHandleActive(on) {
|
|
3094
3180
|
dragHandleActive = !!on;
|
|
3095
3181
|
var b = document.getElementById('sf-drag');
|
|
@@ -3410,6 +3496,9 @@ function renderDomTree(filterRaw) {
|
|
|
3410
3496
|
if (e.target.closest && e.target.closest('.dt-chev')) return;
|
|
3411
3497
|
selectElementFromTree(el);
|
|
3412
3498
|
};
|
|
3499
|
+
row.onmouseenter = function() {
|
|
3500
|
+
setTreeHoverHighlight(el);
|
|
3501
|
+
};
|
|
3413
3502
|
root.appendChild(row);
|
|
3414
3503
|
|
|
3415
3504
|
if (!hasKids || collapsed) return;
|
|
@@ -3428,6 +3517,9 @@ function renderDomTree(filterRaw) {
|
|
|
3428
3517
|
? '<div class="dt-muted">No elements match your search.</div>'
|
|
3429
3518
|
: '<div class="dt-muted">No visible elements yet.</div>';
|
|
3430
3519
|
}
|
|
3520
|
+
root.onmouseleave = function() {
|
|
3521
|
+
clearTreeHoverHighlight();
|
|
3522
|
+
};
|
|
3431
3523
|
}
|
|
3432
3524
|
|
|
3433
3525
|
// \u2500\u2500 Utility helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -3847,12 +3939,25 @@ function renderRightPanel(el) {
|
|
|
3847
3939
|
var sel = buildSelector(el);
|
|
3848
3940
|
bindings.forEach(function(b){
|
|
3849
3941
|
var inp = document.getElementById(b[0]);
|
|
3850
|
-
if (inp)
|
|
3942
|
+
if (inp) {
|
|
3943
|
+
var onValueChange = function() {
|
|
3851
3944
|
// Read the original value BEFORE applying the change so we can revert later
|
|
3852
3945
|
var orig = getOriginalValue(b[0], el);
|
|
3853
3946
|
b[1](inp.value);
|
|
3854
|
-
|
|
3855
|
-
|
|
3947
|
+
var valueToLog = inp.value;
|
|
3948
|
+
try {
|
|
3949
|
+
console.log('[V2] input changed', {
|
|
3950
|
+
inputId: b[0],
|
|
3951
|
+
rawValue: inp.value,
|
|
3952
|
+
appliedValue: valueToLog,
|
|
3953
|
+
selector: sel,
|
|
3954
|
+
});
|
|
3955
|
+
} catch(_) {}
|
|
3956
|
+
logChange(sel, b[0], valueToLog, el, orig);
|
|
3957
|
+
};
|
|
3958
|
+
inp.addEventListener('input', onValueChange);
|
|
3959
|
+
inp.addEventListener('change', onValueChange);
|
|
3960
|
+
}
|
|
3856
3961
|
});
|
|
3857
3962
|
}
|
|
3858
3963
|
|
|
@@ -4115,6 +4220,32 @@ function attachClickHandler() {
|
|
|
4115
4220
|
} catch(_) {}
|
|
4116
4221
|
}
|
|
4117
4222
|
|
|
4223
|
+
function attachIframeHoverHandler() {
|
|
4224
|
+
try {
|
|
4225
|
+
var iframe = document.getElementById('iframeId');
|
|
4226
|
+
var doc = iframe && iframe.contentDocument;
|
|
4227
|
+
if (!doc || !doc.body) return;
|
|
4228
|
+
if (hoverAttachDoc === doc) return;
|
|
4229
|
+
hoverAttachDoc = doc;
|
|
4230
|
+
doc.addEventListener('mousemove', function(e) {
|
|
4231
|
+
if (currentMode !== 'editor') {
|
|
4232
|
+
clearTreeHoverHighlight();
|
|
4233
|
+
return;
|
|
4234
|
+
}
|
|
4235
|
+
var target = e.target;
|
|
4236
|
+
if (!target || target === doc.body || target === doc.documentElement) {
|
|
4237
|
+
clearTreeHoverHighlight();
|
|
4238
|
+
return;
|
|
4239
|
+
}
|
|
4240
|
+
setTreeHoverHighlight(target);
|
|
4241
|
+
}, true);
|
|
4242
|
+
doc.addEventListener('mouseout', function(e) {
|
|
4243
|
+
if (e.relatedTarget) return;
|
|
4244
|
+
clearTreeHoverHighlight();
|
|
4245
|
+
}, true);
|
|
4246
|
+
} catch(_) {}
|
|
4247
|
+
}
|
|
4248
|
+
|
|
4118
4249
|
function attachChangeObserver() {
|
|
4119
4250
|
try {
|
|
4120
4251
|
var iframe = document.getElementById('iframeId');
|
|
@@ -4127,6 +4258,14 @@ function attachChangeObserver() {
|
|
|
4127
4258
|
changeObserverDoc = null;
|
|
4128
4259
|
}
|
|
4129
4260
|
changeObserver = new MutationObserver(function(mutations) {
|
|
4261
|
+
var hasMeaningfulMutation = false;
|
|
4262
|
+
for (var mi = 0; mi < mutations.length; mi++) {
|
|
4263
|
+
if (!isTreeHoverOnlyClassMutation(mutations[mi])) {
|
|
4264
|
+
hasMeaningfulMutation = true;
|
|
4265
|
+
break;
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
if (!hasMeaningfulMutation) return;
|
|
4130
4269
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
4131
4270
|
// Host scripts can replace selected nodes every few frames (e.g. A/B tool observers).
|
|
4132
4271
|
// Keep selection sticky by re-resolving from fingerprint.
|
|
@@ -4137,7 +4276,7 @@ function attachChangeObserver() {
|
|
|
4137
4276
|
updateSelectionToolbar();
|
|
4138
4277
|
});
|
|
4139
4278
|
changeObserver.observe(doc.body, {
|
|
4140
|
-
childList: true, subtree: true, attributes: true, characterData: true
|
|
4279
|
+
childList: true, subtree: true, attributes: true, characterData: true, attributeOldValue: true
|
|
4141
4280
|
});
|
|
4142
4281
|
changeObserverDoc = doc;
|
|
4143
4282
|
} catch(_) {}
|
|
@@ -4163,6 +4302,7 @@ function syncIframeInteractions(reason) {
|
|
|
4163
4302
|
injectIframeSelectionStyles(doc);
|
|
4164
4303
|
refreshPersistentChangesetStyleTagForActiveVariation();
|
|
4165
4304
|
attachClickHandler();
|
|
4305
|
+
attachIframeHoverHandler();
|
|
4166
4306
|
attachDragReposition();
|
|
4167
4307
|
attachChangeObserver();
|
|
4168
4308
|
startConsistencyWatchdog(doc);
|
|
@@ -4521,10 +4661,9 @@ window.addEventListener('load', function() {
|
|
|
4521
4661
|
var iframe = document.getElementById('iframeId');
|
|
4522
4662
|
iframe.addEventListener('load', function() {
|
|
4523
4663
|
if (!iframe.src || iframe.src === 'about:blank' || iframe.src === window.location.href) return;
|
|
4524
|
-
// New iframe navigation: always drop bindings tied to the previous document.
|
|
4525
|
-
resetIframeBindings();
|
|
4526
4664
|
var doc = iframe.contentDocument;
|
|
4527
4665
|
if (!doc) {
|
|
4666
|
+
resetIframeBindings();
|
|
4528
4667
|
syncIframeInteractions('iframe-load-no-doc');
|
|
4529
4668
|
return;
|
|
4530
4669
|
}
|
|
@@ -4533,14 +4672,32 @@ window.addEventListener('load', function() {
|
|
|
4533
4672
|
// Stale events: src may already be the proxy URL while the document is still
|
|
4534
4673
|
// about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
|
|
4535
4674
|
if (docUrl === 'about:blank') {
|
|
4675
|
+
resetIframeBindings();
|
|
4536
4676
|
syncIframeInteractions('iframe-load-about-blank');
|
|
4537
4677
|
return;
|
|
4538
4678
|
}
|
|
4679
|
+
// If early-paint and final load DOM signatures match, avoid a second full apply/reset
|
|
4680
|
+
// that steals focus from sidebar controls while the page is still stabilizing.
|
|
4681
|
+
var shouldRefreshOnFinalLoad = true;
|
|
4682
|
+
if (
|
|
4683
|
+
iframeEarlyDomSignatureNavGen === iframeContentNavGen &&
|
|
4684
|
+
iframeEarlySyncPrimedForGen === iframeContentNavGen &&
|
|
4685
|
+
iframeEarlyDomSignature
|
|
4686
|
+
) {
|
|
4687
|
+
var finalDomSignature = computeIframeDomSignature(doc);
|
|
4688
|
+
if (finalDomSignature && finalDomSignature === iframeEarlyDomSignature) {
|
|
4689
|
+
shouldRefreshOnFinalLoad = false;
|
|
4690
|
+
}
|
|
4691
|
+
}
|
|
4692
|
+
if (clickAttachDoc !== doc || dragAttachDoc !== doc || changeObserverDoc !== doc || hoverAttachDoc !== doc) {
|
|
4693
|
+
resetIframeBindings();
|
|
4694
|
+
}
|
|
4539
4695
|
attachIframeLoadingUntilComplete(iframe);
|
|
4540
4696
|
if (doc.body && iframeDocMatchesNavigatedSrc(iframe, doc)) {
|
|
4541
4697
|
stopIframeContentApplyWatcher();
|
|
4542
|
-
|
|
4543
|
-
|
|
4698
|
+
if (shouldRefreshOnFinalLoad) {
|
|
4699
|
+
applyActiveVariationHtml();
|
|
4700
|
+
}
|
|
4544
4701
|
}
|
|
4545
4702
|
// Always attempt sync; it has its own readiness checks + retry loop.
|
|
4546
4703
|
syncIframeInteractions('iframe-load');
|
|
@@ -4882,9 +5039,12 @@ function createVisualEditorMiddleware(options) {
|
|
|
4882
5039
|
}
|
|
4883
5040
|
);
|
|
4884
5041
|
if (html.includes("</head>")) {
|
|
4885
|
-
html = html.replace(
|
|
4886
|
-
|
|
4887
|
-
|
|
5042
|
+
html = html.replace(
|
|
5043
|
+
"</head>",
|
|
5044
|
+
`${iframeAlwaysShowCss}
|
|
5045
|
+
${iframeAlwaysShowCssGuardScript}
|
|
5046
|
+
</head>`
|
|
5047
|
+
);
|
|
4888
5048
|
}
|
|
4889
5049
|
html = html.replace(
|
|
4890
5050
|
/<meta[^>]+http-equiv=["']?\s*(x-frame-options|content-security-policy)\s*["']?[^>]*>/gi,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@accelerated-agency/visual-editor",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Conversion visual editor as a reusable React package",
|
|
6
6
|
"type": "module",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"dev": "tsup --watch",
|
|
26
26
|
"clean": "rm -rf dist",
|
|
27
27
|
"build": "tsup",
|
|
28
|
+
"local:build": "tsup && yarn --cwd ../codebase-server clean && yarn --cwd ../codebase-server dev",
|
|
28
29
|
"watch": "tsup --watch"
|
|
29
30
|
},
|
|
30
31
|
"peerDependencies": {
|