@accelerated-agency/visual-editor 0.2.5 → 0.2.7
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 +33 -2
- package/dist/vite.cjs +140 -2
- package/dist/vite.js +140 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1842,6 +1842,31 @@ function ElementIcon({ tag }) {
|
|
|
1842
1842
|
}
|
|
1843
1843
|
return /* @__PURE__ */ jsx("span", { className: "shrink-0 w-5 h-5 rounded flex items-center justify-center", style: { backgroundColor: bgColor }, children: /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx("rect", { x: "1.5", y: "1.5", width: "9", height: "9", rx: "1.5", stroke: iconColor, strokeWidth: "1.2" }) }) });
|
|
1844
1844
|
}
|
|
1845
|
+
|
|
1846
|
+
// src/lib/normalizeProxyBaseUrl.ts
|
|
1847
|
+
function normalizeProxyBaseUrl(proxyBaseUrl) {
|
|
1848
|
+
const raw = (proxyBaseUrl || "").trim().replace(/\/+$/, "");
|
|
1849
|
+
if (!raw) return "";
|
|
1850
|
+
const isAbsoluteHttpUrl = /^https?:\/\//i.test(raw);
|
|
1851
|
+
if (!isAbsoluteHttpUrl || typeof window === "undefined") {
|
|
1852
|
+
return raw;
|
|
1853
|
+
}
|
|
1854
|
+
try {
|
|
1855
|
+
const parsed = new URL(raw);
|
|
1856
|
+
const pageIsHttps = window.location.protocol === "https:";
|
|
1857
|
+
const targetIsHttp = parsed.protocol === "http:";
|
|
1858
|
+
if (pageIsHttps && targetIsHttp) {
|
|
1859
|
+
if (parsed.hostname === window.location.hostname) {
|
|
1860
|
+
const basePath = parsed.pathname === "/" ? "" : parsed.pathname.replace(/\/+$/, "");
|
|
1861
|
+
return `${window.location.origin}${basePath}`;
|
|
1862
|
+
}
|
|
1863
|
+
parsed.protocol = "https:";
|
|
1864
|
+
}
|
|
1865
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
1866
|
+
} catch {
|
|
1867
|
+
return raw;
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1845
1870
|
var CHANNEL = "conversion-editor";
|
|
1846
1871
|
function IframeCanvas({ url, password, proxyBaseUrl = "", onBridgeReady, onPong }) {
|
|
1847
1872
|
const iframeElRef = useRef(null);
|
|
@@ -1885,11 +1910,12 @@ function IframeCanvas({ url, password, proxyBaseUrl = "", onBridgeReady, onPong
|
|
|
1885
1910
|
window.addEventListener("message", handleMessage);
|
|
1886
1911
|
return () => window.removeEventListener("message", handleMessage);
|
|
1887
1912
|
}, [handleMessage]);
|
|
1913
|
+
const resolvedProxyBaseUrl = normalizeProxyBaseUrl(proxyBaseUrl);
|
|
1888
1914
|
let resolvedUrl;
|
|
1889
1915
|
if (url.toLowerCase() === "test") {
|
|
1890
1916
|
resolvedUrl = "/test";
|
|
1891
1917
|
} else if (url.startsWith("http")) {
|
|
1892
|
-
resolvedUrl = `${
|
|
1918
|
+
resolvedUrl = `${resolvedProxyBaseUrl}/api/conversion-proxy?password=${encodeURIComponent(password || "")}&url=${encodeURIComponent(url)}`;
|
|
1893
1919
|
} else {
|
|
1894
1920
|
resolvedUrl = url;
|
|
1895
1921
|
}
|
|
@@ -4777,6 +4803,7 @@ var VVVEB_CHANNEL = "vvveb-bridge";
|
|
|
4777
4803
|
function PlatformVisualEditorV2({
|
|
4778
4804
|
// channel kept for API compatibility; VvvebJs uses its own internal channel
|
|
4779
4805
|
embeddedGlobalKey = "__CONVERSION_EMBEDDED__",
|
|
4806
|
+
proxyBaseUrl = "",
|
|
4780
4807
|
className = "fixed inset-0 z-[9999] flex flex-col bg-white",
|
|
4781
4808
|
editorClassName = "flex-1 min-h-0",
|
|
4782
4809
|
showHeader = true,
|
|
@@ -4839,6 +4866,10 @@ function PlatformVisualEditorV2({
|
|
|
4839
4866
|
}),
|
|
4840
4867
|
[experiment]
|
|
4841
4868
|
);
|
|
4869
|
+
const editorSrc = useMemo(() => {
|
|
4870
|
+
const safeBaseUrl = normalizeProxyBaseUrl(proxyBaseUrl);
|
|
4871
|
+
return safeBaseUrl ? `${safeBaseUrl}/vvveb-editor` : "/vvveb-editor";
|
|
4872
|
+
}, [proxyBaseUrl]);
|
|
4842
4873
|
useEffect(() => {
|
|
4843
4874
|
if (!editorReady) return;
|
|
4844
4875
|
const key = JSON.stringify(loadPayload);
|
|
@@ -4981,7 +5012,7 @@ function PlatformVisualEditorV2({
|
|
|
4981
5012
|
"iframe",
|
|
4982
5013
|
{
|
|
4983
5014
|
ref: iframeRef,
|
|
4984
|
-
src:
|
|
5015
|
+
src: editorSrc,
|
|
4985
5016
|
className: "w-full h-full border-0",
|
|
4986
5017
|
title: "Vvveb Visual Editor",
|
|
4987
5018
|
allow: "same-origin"
|
package/dist/vite.cjs
CHANGED
|
@@ -627,7 +627,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
627
627
|
</div>
|
|
628
628
|
<!-- btn-close: hidden visually, kept for JS event listener -->
|
|
629
629
|
<button id="btn-close" style="display:none" title="Close editor"></button>
|
|
630
|
-
<button class="tb-sim-btn" id="btn-simulate"><i class="bi bi-lightning-charge-fill"></i> Simulate</button>
|
|
630
|
+
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"><i class="bi bi-lightning-charge-fill"></i> Simulate</button>
|
|
631
631
|
<button class="tb-fin-btn" id="btn-save">Finalize</button>
|
|
632
632
|
</div>
|
|
633
633
|
|
|
@@ -914,6 +914,52 @@ function send(type, payload) {
|
|
|
914
914
|
window.parent.postMessage({ channel: CHANNEL, type: type, payload: payload || {} }, '*');
|
|
915
915
|
}
|
|
916
916
|
|
|
917
|
+
function generatePreviewUrlString(args) {
|
|
918
|
+
var baseUrl = (args && args.url) || '';
|
|
919
|
+
var test = (args && args.test) || {};
|
|
920
|
+
var variation = (args && args.variation) || {};
|
|
921
|
+
if (!baseUrl) return '';
|
|
922
|
+
var testId = test.iid || test.experimentId || test._id || '';
|
|
923
|
+
var variationId = variation.iid || variation._id || '';
|
|
924
|
+
var cId = String(testId || '') + '_' + String(variationId || '');
|
|
925
|
+
var hasQueryParams = String(baseUrl).indexOf('?') >= 0;
|
|
926
|
+
return (
|
|
927
|
+
baseUrl +
|
|
928
|
+
(hasQueryParams ? '&' : '?') +
|
|
929
|
+
'codebase_debug=true&cId=' +
|
|
930
|
+
encodeURIComponent(cId)
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
function simulateExperiment() {
|
|
935
|
+
var test = experimentData || {};
|
|
936
|
+
var activeVariation = null;
|
|
937
|
+
if (Array.isArray(variations) && variations.length) {
|
|
938
|
+
activeVariation =
|
|
939
|
+
variations.find(function(v) { return v && v._id === activeVarId; }) ||
|
|
940
|
+
variations[0];
|
|
941
|
+
}
|
|
942
|
+
var targetUrl =
|
|
943
|
+
(Array.isArray(test.urltargeting) && test.urltargeting[0]) ||
|
|
944
|
+
test.pageUrl ||
|
|
945
|
+
(test.metadata_1 && test.metadata_1.editor_url) ||
|
|
946
|
+
'';
|
|
947
|
+
var url = generatePreviewUrlString({
|
|
948
|
+
url: targetUrl,
|
|
949
|
+
test: test,
|
|
950
|
+
variation: activeVariation || {},
|
|
951
|
+
});
|
|
952
|
+
if (!url) {
|
|
953
|
+
console.warn('[V2] simulateExperiment: missing target URL');
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
try {
|
|
957
|
+
window.open(url, '_blank');
|
|
958
|
+
} catch(err) {
|
|
959
|
+
console.warn('[V2] simulateExperiment:', err);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
917
963
|
window.addEventListener('message', function(e) {
|
|
918
964
|
if (!e.data || e.data.channel !== CHANNEL) return;
|
|
919
965
|
switch (e.data.type) {
|
|
@@ -965,6 +1011,13 @@ var changeObserver = null;
|
|
|
965
1011
|
var changeObserverDoc = null;
|
|
966
1012
|
/** Incremented while applying changesets / selection chrome so MutationObserver does not mark dirty */
|
|
967
1013
|
var suppressIframeMutationDirty = 0;
|
|
1014
|
+
/** Throttled reconcile timer to keep DOM aligned with saved changesets. */
|
|
1015
|
+
var consistencyReconcileTimer = null;
|
|
1016
|
+
/** Background watchdog for late client-side re-renders that wipe applied changesets. */
|
|
1017
|
+
var consistencyWatchTimer = null;
|
|
1018
|
+
var consistencyWatchDoc = null;
|
|
1019
|
+
var consistencyWatchTicks = 0;
|
|
1020
|
+
var CONSISTENCY_WATCH_MAX_TICKS = 160;
|
|
968
1021
|
/** { doc, onRS } \u2014 iframe document readystate until complete */
|
|
969
1022
|
var iframeDocLoadingListeners = null;
|
|
970
1023
|
// Each entry: {selector, label, cssProp, value, targetEl}
|
|
@@ -1948,9 +2001,71 @@ function clearPendingGranularChangesets() {
|
|
|
1948
2001
|
}
|
|
1949
2002
|
}
|
|
1950
2003
|
|
|
2004
|
+
function stopConsistencyWatchdog() {
|
|
2005
|
+
if (consistencyWatchTimer) {
|
|
2006
|
+
clearInterval(consistencyWatchTimer);
|
|
2007
|
+
consistencyWatchTimer = null;
|
|
2008
|
+
}
|
|
2009
|
+
consistencyWatchDoc = null;
|
|
2010
|
+
consistencyWatchTicks = 0;
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
function runConsistencyReconcile() {
|
|
2014
|
+
if (!activeVarId) return;
|
|
2015
|
+
var iframe = document.getElementById('iframeId');
|
|
2016
|
+
var doc = iframe && iframe.contentDocument;
|
|
2017
|
+
if (!doc || !doc.body) return;
|
|
2018
|
+
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
2019
|
+
var cs = parseVariationChangesets(variation);
|
|
2020
|
+
if (!cs.length || changesetsHaveBodySnapshot(cs)) return;
|
|
2021
|
+
var granular = filterGranularChangesetEntries(cs);
|
|
2022
|
+
var unresolved = countUnresolvedGranularSelectors(doc, granular);
|
|
2023
|
+
if (unresolved > 0 || changesetListHasStructural(cs)) {
|
|
2024
|
+
reapplyActiveVariationGranular(doc);
|
|
2025
|
+
registerPendingGranularChangesets(cs, doc);
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
function scheduleConsistencyReconcile() {
|
|
2030
|
+
if (consistencyReconcileTimer) return;
|
|
2031
|
+
consistencyReconcileTimer = setTimeout(function() {
|
|
2032
|
+
consistencyReconcileTimer = null;
|
|
2033
|
+
runConsistencyReconcile();
|
|
2034
|
+
}, 80);
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
function startConsistencyWatchdog(doc) {
|
|
2038
|
+
if (!doc || !doc.body) return;
|
|
2039
|
+
if (consistencyWatchDoc === doc && consistencyWatchTimer) return;
|
|
2040
|
+
stopConsistencyWatchdog();
|
|
2041
|
+
consistencyWatchDoc = doc;
|
|
2042
|
+
consistencyWatchTicks = 0;
|
|
2043
|
+
consistencyWatchTimer = setInterval(function() {
|
|
2044
|
+
if (consistencyWatchDoc !== doc) {
|
|
2045
|
+
stopConsistencyWatchdog();
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
var iframe = document.getElementById('iframeId');
|
|
2049
|
+
if (!iframe || iframe.contentDocument !== doc || !doc.body) {
|
|
2050
|
+
stopConsistencyWatchdog();
|
|
2051
|
+
return;
|
|
2052
|
+
}
|
|
2053
|
+
consistencyWatchTicks += 1;
|
|
2054
|
+
scheduleConsistencyReconcile();
|
|
2055
|
+
if (consistencyWatchTicks >= CONSISTENCY_WATCH_MAX_TICKS) {
|
|
2056
|
+
stopConsistencyWatchdog();
|
|
2057
|
+
}
|
|
2058
|
+
}, 400);
|
|
2059
|
+
}
|
|
2060
|
+
|
|
1951
2061
|
function resetIframeBindings() {
|
|
1952
2062
|
detachIframeLoadingListeners();
|
|
1953
2063
|
stopIframeContentApplyWatcher();
|
|
2064
|
+
stopConsistencyWatchdog();
|
|
2065
|
+
if (consistencyReconcileTimer) {
|
|
2066
|
+
clearTimeout(consistencyReconcileTimer);
|
|
2067
|
+
consistencyReconcileTimer = null;
|
|
2068
|
+
}
|
|
1954
2069
|
appliedChangesetSnapshots = {};
|
|
1955
2070
|
appliedStructuralChangesetKeys = {};
|
|
1956
2071
|
clickAttachDoc = null;
|
|
@@ -3564,10 +3679,31 @@ function attachChangeObserver() {
|
|
|
3564
3679
|
changeObserver = null;
|
|
3565
3680
|
changeObserverDoc = null;
|
|
3566
3681
|
}
|
|
3567
|
-
changeObserver = new MutationObserver(function() {
|
|
3682
|
+
changeObserver = new MutationObserver(function(mutations) {
|
|
3568
3683
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
3684
|
+
var bodyReplaced = false;
|
|
3685
|
+
for (var mi = 0; mi < mutations.length; mi++) {
|
|
3686
|
+
var m = mutations[mi];
|
|
3687
|
+
if (
|
|
3688
|
+
m &&
|
|
3689
|
+
m.type === 'childList' &&
|
|
3690
|
+
m.target === doc.body &&
|
|
3691
|
+
m.addedNodes &&
|
|
3692
|
+
m.removedNodes &&
|
|
3693
|
+
m.addedNodes.length > 0 &&
|
|
3694
|
+
m.removedNodes.length > 0
|
|
3695
|
+
) {
|
|
3696
|
+
bodyReplaced = true;
|
|
3697
|
+
break;
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
if (bodyReplaced) {
|
|
3701
|
+
// Page JS replaced body children; allow structural rows (insert/reorder) to apply again.
|
|
3702
|
+
appliedStructuralChangesetKeys = {};
|
|
3703
|
+
}
|
|
3569
3704
|
scheduleDomTreeRefresh();
|
|
3570
3705
|
scheduleGranularChangesetReapply();
|
|
3706
|
+
scheduleConsistencyReconcile();
|
|
3571
3707
|
});
|
|
3572
3708
|
changeObserver.observe(doc.body, {
|
|
3573
3709
|
childList: true, subtree: true, attributes: true, characterData: true
|
|
@@ -3597,6 +3733,8 @@ function syncIframeInteractions(reason) {
|
|
|
3597
3733
|
attachClickHandler();
|
|
3598
3734
|
attachDragReposition();
|
|
3599
3735
|
attachChangeObserver();
|
|
3736
|
+
startConsistencyWatchdog(doc);
|
|
3737
|
+
scheduleConsistencyReconcile();
|
|
3600
3738
|
bindSelectionToolbarScroll();
|
|
3601
3739
|
var inp = document.getElementById('comp-search');
|
|
3602
3740
|
renderDomTree(inp ? inp.value : '');
|
package/dist/vite.js
CHANGED
|
@@ -619,7 +619,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
619
619
|
</div>
|
|
620
620
|
<!-- btn-close: hidden visually, kept for JS event listener -->
|
|
621
621
|
<button id="btn-close" style="display:none" title="Close editor"></button>
|
|
622
|
-
<button class="tb-sim-btn" id="btn-simulate"><i class="bi bi-lightning-charge-fill"></i> Simulate</button>
|
|
622
|
+
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"><i class="bi bi-lightning-charge-fill"></i> Simulate</button>
|
|
623
623
|
<button class="tb-fin-btn" id="btn-save">Finalize</button>
|
|
624
624
|
</div>
|
|
625
625
|
|
|
@@ -906,6 +906,52 @@ function send(type, payload) {
|
|
|
906
906
|
window.parent.postMessage({ channel: CHANNEL, type: type, payload: payload || {} }, '*');
|
|
907
907
|
}
|
|
908
908
|
|
|
909
|
+
function generatePreviewUrlString(args) {
|
|
910
|
+
var baseUrl = (args && args.url) || '';
|
|
911
|
+
var test = (args && args.test) || {};
|
|
912
|
+
var variation = (args && args.variation) || {};
|
|
913
|
+
if (!baseUrl) return '';
|
|
914
|
+
var testId = test.iid || test.experimentId || test._id || '';
|
|
915
|
+
var variationId = variation.iid || variation._id || '';
|
|
916
|
+
var cId = String(testId || '') + '_' + String(variationId || '');
|
|
917
|
+
var hasQueryParams = String(baseUrl).indexOf('?') >= 0;
|
|
918
|
+
return (
|
|
919
|
+
baseUrl +
|
|
920
|
+
(hasQueryParams ? '&' : '?') +
|
|
921
|
+
'codebase_debug=true&cId=' +
|
|
922
|
+
encodeURIComponent(cId)
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
function simulateExperiment() {
|
|
927
|
+
var test = experimentData || {};
|
|
928
|
+
var activeVariation = null;
|
|
929
|
+
if (Array.isArray(variations) && variations.length) {
|
|
930
|
+
activeVariation =
|
|
931
|
+
variations.find(function(v) { return v && v._id === activeVarId; }) ||
|
|
932
|
+
variations[0];
|
|
933
|
+
}
|
|
934
|
+
var targetUrl =
|
|
935
|
+
(Array.isArray(test.urltargeting) && test.urltargeting[0]) ||
|
|
936
|
+
test.pageUrl ||
|
|
937
|
+
(test.metadata_1 && test.metadata_1.editor_url) ||
|
|
938
|
+
'';
|
|
939
|
+
var url = generatePreviewUrlString({
|
|
940
|
+
url: targetUrl,
|
|
941
|
+
test: test,
|
|
942
|
+
variation: activeVariation || {},
|
|
943
|
+
});
|
|
944
|
+
if (!url) {
|
|
945
|
+
console.warn('[V2] simulateExperiment: missing target URL');
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
try {
|
|
949
|
+
window.open(url, '_blank');
|
|
950
|
+
} catch(err) {
|
|
951
|
+
console.warn('[V2] simulateExperiment:', err);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
909
955
|
window.addEventListener('message', function(e) {
|
|
910
956
|
if (!e.data || e.data.channel !== CHANNEL) return;
|
|
911
957
|
switch (e.data.type) {
|
|
@@ -957,6 +1003,13 @@ var changeObserver = null;
|
|
|
957
1003
|
var changeObserverDoc = null;
|
|
958
1004
|
/** Incremented while applying changesets / selection chrome so MutationObserver does not mark dirty */
|
|
959
1005
|
var suppressIframeMutationDirty = 0;
|
|
1006
|
+
/** Throttled reconcile timer to keep DOM aligned with saved changesets. */
|
|
1007
|
+
var consistencyReconcileTimer = null;
|
|
1008
|
+
/** Background watchdog for late client-side re-renders that wipe applied changesets. */
|
|
1009
|
+
var consistencyWatchTimer = null;
|
|
1010
|
+
var consistencyWatchDoc = null;
|
|
1011
|
+
var consistencyWatchTicks = 0;
|
|
1012
|
+
var CONSISTENCY_WATCH_MAX_TICKS = 160;
|
|
960
1013
|
/** { doc, onRS } \u2014 iframe document readystate until complete */
|
|
961
1014
|
var iframeDocLoadingListeners = null;
|
|
962
1015
|
// Each entry: {selector, label, cssProp, value, targetEl}
|
|
@@ -1940,9 +1993,71 @@ function clearPendingGranularChangesets() {
|
|
|
1940
1993
|
}
|
|
1941
1994
|
}
|
|
1942
1995
|
|
|
1996
|
+
function stopConsistencyWatchdog() {
|
|
1997
|
+
if (consistencyWatchTimer) {
|
|
1998
|
+
clearInterval(consistencyWatchTimer);
|
|
1999
|
+
consistencyWatchTimer = null;
|
|
2000
|
+
}
|
|
2001
|
+
consistencyWatchDoc = null;
|
|
2002
|
+
consistencyWatchTicks = 0;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
function runConsistencyReconcile() {
|
|
2006
|
+
if (!activeVarId) return;
|
|
2007
|
+
var iframe = document.getElementById('iframeId');
|
|
2008
|
+
var doc = iframe && iframe.contentDocument;
|
|
2009
|
+
if (!doc || !doc.body) return;
|
|
2010
|
+
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
2011
|
+
var cs = parseVariationChangesets(variation);
|
|
2012
|
+
if (!cs.length || changesetsHaveBodySnapshot(cs)) return;
|
|
2013
|
+
var granular = filterGranularChangesetEntries(cs);
|
|
2014
|
+
var unresolved = countUnresolvedGranularSelectors(doc, granular);
|
|
2015
|
+
if (unresolved > 0 || changesetListHasStructural(cs)) {
|
|
2016
|
+
reapplyActiveVariationGranular(doc);
|
|
2017
|
+
registerPendingGranularChangesets(cs, doc);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
function scheduleConsistencyReconcile() {
|
|
2022
|
+
if (consistencyReconcileTimer) return;
|
|
2023
|
+
consistencyReconcileTimer = setTimeout(function() {
|
|
2024
|
+
consistencyReconcileTimer = null;
|
|
2025
|
+
runConsistencyReconcile();
|
|
2026
|
+
}, 80);
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
function startConsistencyWatchdog(doc) {
|
|
2030
|
+
if (!doc || !doc.body) return;
|
|
2031
|
+
if (consistencyWatchDoc === doc && consistencyWatchTimer) return;
|
|
2032
|
+
stopConsistencyWatchdog();
|
|
2033
|
+
consistencyWatchDoc = doc;
|
|
2034
|
+
consistencyWatchTicks = 0;
|
|
2035
|
+
consistencyWatchTimer = setInterval(function() {
|
|
2036
|
+
if (consistencyWatchDoc !== doc) {
|
|
2037
|
+
stopConsistencyWatchdog();
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
var iframe = document.getElementById('iframeId');
|
|
2041
|
+
if (!iframe || iframe.contentDocument !== doc || !doc.body) {
|
|
2042
|
+
stopConsistencyWatchdog();
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
consistencyWatchTicks += 1;
|
|
2046
|
+
scheduleConsistencyReconcile();
|
|
2047
|
+
if (consistencyWatchTicks >= CONSISTENCY_WATCH_MAX_TICKS) {
|
|
2048
|
+
stopConsistencyWatchdog();
|
|
2049
|
+
}
|
|
2050
|
+
}, 400);
|
|
2051
|
+
}
|
|
2052
|
+
|
|
1943
2053
|
function resetIframeBindings() {
|
|
1944
2054
|
detachIframeLoadingListeners();
|
|
1945
2055
|
stopIframeContentApplyWatcher();
|
|
2056
|
+
stopConsistencyWatchdog();
|
|
2057
|
+
if (consistencyReconcileTimer) {
|
|
2058
|
+
clearTimeout(consistencyReconcileTimer);
|
|
2059
|
+
consistencyReconcileTimer = null;
|
|
2060
|
+
}
|
|
1946
2061
|
appliedChangesetSnapshots = {};
|
|
1947
2062
|
appliedStructuralChangesetKeys = {};
|
|
1948
2063
|
clickAttachDoc = null;
|
|
@@ -3556,10 +3671,31 @@ function attachChangeObserver() {
|
|
|
3556
3671
|
changeObserver = null;
|
|
3557
3672
|
changeObserverDoc = null;
|
|
3558
3673
|
}
|
|
3559
|
-
changeObserver = new MutationObserver(function() {
|
|
3674
|
+
changeObserver = new MutationObserver(function(mutations) {
|
|
3560
3675
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
3676
|
+
var bodyReplaced = false;
|
|
3677
|
+
for (var mi = 0; mi < mutations.length; mi++) {
|
|
3678
|
+
var m = mutations[mi];
|
|
3679
|
+
if (
|
|
3680
|
+
m &&
|
|
3681
|
+
m.type === 'childList' &&
|
|
3682
|
+
m.target === doc.body &&
|
|
3683
|
+
m.addedNodes &&
|
|
3684
|
+
m.removedNodes &&
|
|
3685
|
+
m.addedNodes.length > 0 &&
|
|
3686
|
+
m.removedNodes.length > 0
|
|
3687
|
+
) {
|
|
3688
|
+
bodyReplaced = true;
|
|
3689
|
+
break;
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
if (bodyReplaced) {
|
|
3693
|
+
// Page JS replaced body children; allow structural rows (insert/reorder) to apply again.
|
|
3694
|
+
appliedStructuralChangesetKeys = {};
|
|
3695
|
+
}
|
|
3561
3696
|
scheduleDomTreeRefresh();
|
|
3562
3697
|
scheduleGranularChangesetReapply();
|
|
3698
|
+
scheduleConsistencyReconcile();
|
|
3563
3699
|
});
|
|
3564
3700
|
changeObserver.observe(doc.body, {
|
|
3565
3701
|
childList: true, subtree: true, attributes: true, characterData: true
|
|
@@ -3589,6 +3725,8 @@ function syncIframeInteractions(reason) {
|
|
|
3589
3725
|
attachClickHandler();
|
|
3590
3726
|
attachDragReposition();
|
|
3591
3727
|
attachChangeObserver();
|
|
3728
|
+
startConsistencyWatchdog(doc);
|
|
3729
|
+
scheduleConsistencyReconcile();
|
|
3592
3730
|
bindSelectionToolbarScroll();
|
|
3593
3731
|
var inp = document.getElementById('comp-search');
|
|
3594
3732
|
renderDomTree(inp ? inp.value : '');
|