@accelerated-agency/visual-editor 0.3.4 → 0.3.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 +5 -0
- package/dist/vite.cjs +711 -190
- package/dist/vite.js +711 -190
- package/package.json +2 -1
package/dist/vite.js
CHANGED
|
@@ -3,6 +3,42 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
5
|
// src/visualEditorProxyPlugin.ts
|
|
6
|
+
var SCRAPER_PROXY_HOST = process.env.SCRAPERAPI_PROXY_HOST || "proxy-server.scraperapi.com";
|
|
7
|
+
var SCRAPER_PROXY_PORT = Number(process.env.SCRAPERAPI_PROXY_PORT || "8001");
|
|
8
|
+
var SCRAPER_PROXY_USERNAME_BASE = process.env.SCRAPERAPI_PROXY_USERNAME_BASE || "scraperapi";
|
|
9
|
+
var SCRAPER_PROXY_USERNAME_PARAMS = process.env.SCRAPERAPI_PROXY_USERNAME_PARAMS || "render=true.wait_for_selector=body.follow_redirect=false.keep_headers=true";
|
|
10
|
+
var SCRAPER_PROXY_USERNAME = process.env.SCRAPERAPI_PROXY_USERNAME || [
|
|
11
|
+
SCRAPER_PROXY_USERNAME_BASE,
|
|
12
|
+
SCRAPER_PROXY_USERNAME_PARAMS
|
|
13
|
+
].filter(Boolean).join(".");
|
|
14
|
+
var SCRAPER_PROXY_PASSWORD = process.env.SCRAPERAPI_PROXY_PASSWORD || process.env.SCRAPERAPI_API_KEY || "e0252333bde7cbf61d2d388e8c4a962a";
|
|
15
|
+
var SCRAPER_API_ENDPOINT = process.env.SCRAPERAPI_ENDPOINT || "https://api.scraperapi.com/";
|
|
16
|
+
var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW = process.env.SCRAPERAPI_REQUEST_TLS_REJECT_UNAUTHORIZED || "false";
|
|
17
|
+
var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED = !["0", "false", "no"].includes(
|
|
18
|
+
SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW.toLowerCase()
|
|
19
|
+
);
|
|
20
|
+
var scraperProxyClientPromise = null;
|
|
21
|
+
async function getScraperProxyClient() {
|
|
22
|
+
if (scraperProxyClientPromise) return scraperProxyClientPromise;
|
|
23
|
+
scraperProxyClientPromise = (async () => {
|
|
24
|
+
try {
|
|
25
|
+
const undici = await import('undici');
|
|
26
|
+
const proxyUrl = "http://" + encodeURIComponent(SCRAPER_PROXY_USERNAME) + ":" + encodeURIComponent(SCRAPER_PROXY_PASSWORD) + "@" + SCRAPER_PROXY_HOST + ":" + String(SCRAPER_PROXY_PORT);
|
|
27
|
+
return {
|
|
28
|
+
dispatcher: new undici.ProxyAgent({
|
|
29
|
+
uri: proxyUrl,
|
|
30
|
+
requestTls: {
|
|
31
|
+
rejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
|
|
32
|
+
}
|
|
33
|
+
}),
|
|
34
|
+
fetchFn: undici.fetch
|
|
35
|
+
};
|
|
36
|
+
} catch (_) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
return scraperProxyClientPromise;
|
|
41
|
+
}
|
|
6
42
|
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
43
|
var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
|
|
8
44
|
function ensureForceShowStyleLast(){
|
|
@@ -347,21 +383,21 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
347
383
|
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px;}
|
|
348
384
|
.lp-sec-no-border{border-bottom:none!important}
|
|
349
385
|
.lp-sec-hd{
|
|
350
|
-
|
|
386
|
+
margin-bottom: 12px;
|
|
387
|
+
font-size:14px;font-weight:600;
|
|
351
388
|
color:#404040;display:flex;align-items:center;justify-content:space-between;gap:5px
|
|
352
389
|
}
|
|
353
390
|
.lp-sec-hd-left{display:flex;align-items:center;gap:5px}
|
|
354
391
|
#active-var-label{display:none;color:var(--accent-txt);font-size:10px;font-weight:500}
|
|
355
392
|
.lp-info-icon{font-size:11px;color:var(--text-3);cursor:default;opacity:.7}
|
|
356
393
|
.lp-add-btn{
|
|
357
|
-
display:none;
|
|
358
394
|
background:none;border:none;color:var(--text);font-size:14px;font-weight:500;
|
|
359
395
|
cursor:pointer;padding:2px 5px;border-radius:4px;transition:all .12s;flex-shrink:0
|
|
360
396
|
}
|
|
361
397
|
.lp-add-btn:hover{background:var(--bg-hover);color:var(--accent-txt)}
|
|
362
398
|
|
|
363
399
|
/* \u2500\u2500 Variation tabs \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 */
|
|
364
|
-
#variation-tabs{
|
|
400
|
+
#variation-tabs{display:flex;flex-direction:column; gap:8px;}
|
|
365
401
|
.var-tab{
|
|
366
402
|
border-radius: 4px;
|
|
367
403
|
border: 1px solid #e5e7eb;
|
|
@@ -392,7 +428,7 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
392
428
|
#comp-search:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(99,102,241,.12)}
|
|
393
429
|
|
|
394
430
|
/* \u2500\u2500 Left tabs \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\u2500\u2500\u2500\u2500\u2500 */
|
|
395
|
-
.lp-tabs{display:flex;border-bottom:1px solid var(--border);flex-shrink:0;background:#fff}
|
|
431
|
+
.lp-tabs, .section-components-tabs{display:flex;border-bottom:1px solid var(--border);flex-shrink:0;background:#fff}
|
|
396
432
|
.lp-tab{
|
|
397
433
|
flex:1;padding:8px 2px;text-align:center;font-size:10px;color:var(--text-3);
|
|
398
434
|
cursor:pointer;border-bottom:2px solid transparent;transition:all .15s;font-weight:600;line-height:1.15
|
|
@@ -402,10 +438,10 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
402
438
|
.future-hidden{display:none!important}
|
|
403
439
|
|
|
404
440
|
/* \u2500\u2500 Left panel body \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 */
|
|
405
|
-
.lp-body{flex:1;overflow-y:auto}
|
|
406
|
-
.lp-body::-webkit-scrollbar{width:3px}
|
|
407
|
-
.lp-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}
|
|
408
|
-
.tab-pane{display:none}.tab-pane.active{display:block}
|
|
441
|
+
.lp-body, .section-components-body{flex:1;overflow-y:auto}
|
|
442
|
+
.lp-body::-webkit-scrollbar, .section-components-body::-webkit-scrollbar{width:3px}
|
|
443
|
+
.lp-body::-webkit-scrollbar-thumb, .section-components-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}
|
|
444
|
+
.tab-pane, .section-components-tab-pane{display:none}.tab-pane.active, .section-components-tab-pane.active{display:block}
|
|
409
445
|
|
|
410
446
|
/* \u2500\u2500 Component grid \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 */
|
|
411
447
|
.cg-hdr{padding:8px 10px 4px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)}
|
|
@@ -617,12 +653,83 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
617
653
|
}
|
|
618
654
|
#states-clear:hover{border-color:#fca5a5;color:#ef4444;background:#fef2f2}
|
|
619
655
|
#history-clear{
|
|
620
|
-
display:block;width:calc(100% - 24px);margin:10px 12px;
|
|
656
|
+
display:block;width:calc(100% - 24px);margin:10px 12px 8px;
|
|
621
657
|
background:none;border:1px solid var(--border);border-radius:6px;
|
|
622
658
|
padding:6px;font-size:11px;color:var(--text-2);cursor:pointer;font-family:inherit;
|
|
623
659
|
transition:all .15s
|
|
624
660
|
}
|
|
625
661
|
#history-clear:hover{border-color:#fca5a5;color:#ef4444;background:#fef2f2}
|
|
662
|
+
.history-timeline{
|
|
663
|
+
position:relative;
|
|
664
|
+
margin:8px 0 12px;
|
|
665
|
+
padding:0 12px 0 36px;
|
|
666
|
+
}
|
|
667
|
+
.history-timeline::before{
|
|
668
|
+
content:'';
|
|
669
|
+
position:absolute;
|
|
670
|
+
left:20px;
|
|
671
|
+
top:4px;
|
|
672
|
+
bottom:4px;
|
|
673
|
+
width:2px;
|
|
674
|
+
background:#eceff3;
|
|
675
|
+
border-radius:2px;
|
|
676
|
+
}
|
|
677
|
+
.history-item{
|
|
678
|
+
position:relative;
|
|
679
|
+
display:flex;
|
|
680
|
+
align-items:flex-start;
|
|
681
|
+
gap:10px;
|
|
682
|
+
padding:10px 8px 10px 0;
|
|
683
|
+
cursor:pointer;
|
|
684
|
+
}
|
|
685
|
+
.history-dot{
|
|
686
|
+
position:absolute;
|
|
687
|
+
left:-20px;
|
|
688
|
+
top:18px;
|
|
689
|
+
width:10px;
|
|
690
|
+
height:10px;
|
|
691
|
+
border-radius:50%;
|
|
692
|
+
background:#fff;
|
|
693
|
+
border:2px solid #d7dde6;
|
|
694
|
+
}
|
|
695
|
+
.history-card{
|
|
696
|
+
flex:1;
|
|
697
|
+
min-width:0;
|
|
698
|
+
}
|
|
699
|
+
.history-title{
|
|
700
|
+
font-size:14px;
|
|
701
|
+
font-weight:600;
|
|
702
|
+
color:var(--text);
|
|
703
|
+
line-height:1.3;
|
|
704
|
+
}
|
|
705
|
+
.history-meta{
|
|
706
|
+
margin-top:4px;
|
|
707
|
+
display:flex;
|
|
708
|
+
align-items:center;
|
|
709
|
+
gap:6px;
|
|
710
|
+
color:var(--text-2);
|
|
711
|
+
font-size:11px;
|
|
712
|
+
}
|
|
713
|
+
.history-avatar{
|
|
714
|
+
width:18px;
|
|
715
|
+
height:18px;
|
|
716
|
+
border-radius:50%;
|
|
717
|
+
background:#e9e5ff;
|
|
718
|
+
color:#5b47d6;
|
|
719
|
+
display:flex;
|
|
720
|
+
align-items:center;
|
|
721
|
+
justify-content:center;
|
|
722
|
+
font-size:10px;
|
|
723
|
+
font-weight:700;
|
|
724
|
+
}
|
|
725
|
+
.history-time{
|
|
726
|
+
margin-top:3px;
|
|
727
|
+
font-size:11px;
|
|
728
|
+
color:var(--text-3);
|
|
729
|
+
}
|
|
730
|
+
.history-remove{
|
|
731
|
+
margin-top:2px;
|
|
732
|
+
}
|
|
626
733
|
</style>
|
|
627
734
|
</head>
|
|
628
735
|
<body class="mode-editor">
|
|
@@ -704,7 +811,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
704
811
|
<div class="lp-sec">
|
|
705
812
|
<div class="lp-sec-hd">
|
|
706
813
|
<span class="lp-sec-hd-left">Variations <span id="active-var-label"></span></span>
|
|
707
|
-
<button class="lp-add-btn" title="Add variation">+ Add</button>
|
|
814
|
+
<button class="lp-add-btn" style="display:none" title="Add variation">+ Add</button>
|
|
708
815
|
</div>
|
|
709
816
|
<div id="variation-tabs"></div>
|
|
710
817
|
</div>
|
|
@@ -729,27 +836,39 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
729
836
|
<span class="lp-sec-hd-left">Elements <i class="bi bi-info-circle lp-info-icon" title="Page elements"></i></span>
|
|
730
837
|
<button class="lp-add-btn" title="Add element">+ Add</button>
|
|
731
838
|
</div>
|
|
732
|
-
</div>
|
|
733
839
|
|
|
734
|
-
|
|
735
|
-
<div
|
|
840
|
+
<!-- Search (hidden, kept for JS) -->
|
|
841
|
+
<div>
|
|
736
842
|
<input type="search" id="comp-search" placeholder="Search layers\u2026" autocomplete="off">
|
|
737
843
|
</div>
|
|
738
844
|
|
|
845
|
+
|
|
739
846
|
<!-- Tabs (hidden, kept for JS) -->
|
|
740
|
-
<div class="lp-tabs"
|
|
741
|
-
|
|
742
|
-
<div class="lp-tab
|
|
743
|
-
|
|
847
|
+
<div class="lp-tabs" >
|
|
848
|
+
<div class="lp-tab active" onclick="switchLeftTab('elements')">Elements</div>
|
|
849
|
+
<div class="lp-tab" onclick="switchLeftTab('dom-tree')">DOM Tree</div>
|
|
850
|
+
</div>
|
|
851
|
+
|
|
744
852
|
</div>
|
|
745
853
|
|
|
746
854
|
<!-- Tab content -->
|
|
747
855
|
<div class="lp-body">
|
|
748
|
-
<div id="tab-
|
|
749
|
-
<div id="
|
|
750
|
-
|
|
856
|
+
<div id="tab-dom-tree" class="tab-pane">
|
|
857
|
+
<div id="dom-tree-root" class="dt-tree">
|
|
858
|
+
</div>
|
|
859
|
+
</div>
|
|
860
|
+
<div id="tab-elements" class="tab-pane active">
|
|
861
|
+
<div id="elements-root" class="elements-tree">
|
|
862
|
+
</div>
|
|
863
|
+
</div>
|
|
751
864
|
</div>
|
|
752
865
|
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
|
|
753
872
|
</div><!-- #left-panel -->
|
|
754
873
|
|
|
755
874
|
<!-- Center / iframe panel -->
|
|
@@ -757,7 +876,8 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
757
876
|
|
|
758
877
|
<!-- Floating toolbar for selected element (positioned over iframe) -->
|
|
759
878
|
<div id="selection-floater" aria-label="Selection actions">
|
|
760
|
-
<button type="button" class="sf-btn" id="sf-
|
|
879
|
+
<button type="button" class="sf-btn" id="sf-move-up" title="Move up"><i class="bi bi-arrow-up"></i></button>
|
|
880
|
+
<button type="button" class="sf-btn" id="sf-move-down" title="Move down"><i class="bi bi-arrow-down"></i></button>
|
|
761
881
|
<span class="sf-sep"></span>
|
|
762
882
|
<button type="button" class="sf-btn" id="sf-resize" disabled title="Resize (coming soon)"><i class="bi bi-arrows-angle-expand"></i></button>
|
|
763
883
|
<button type="button" class="sf-btn" id="sf-rotate" disabled title="Rotate (coming soon)"><i class="bi bi-arrow-repeat"></i></button>
|
|
@@ -784,13 +904,20 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
784
904
|
|
|
785
905
|
<!-- Right panel -->
|
|
786
906
|
<div id="right-panel">
|
|
787
|
-
|
|
907
|
+
<!-- Left-tab controls moved here -->
|
|
908
|
+
<div class="section-components-tabs">
|
|
909
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('components')">Components</div>
|
|
910
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
|
|
911
|
+
</div>
|
|
912
|
+
<div class="lp-body">
|
|
913
|
+
<div id="tab-components" class="tab-pane"></div>
|
|
914
|
+
<div id="tab-sections" class="tab-pane"></div>
|
|
915
|
+
</div>
|
|
788
916
|
<!-- Element badge (hidden until selection) -->
|
|
789
917
|
<div id="el-info" style="display:none">
|
|
790
918
|
<div id="el-info-tag"></div>
|
|
791
919
|
<div id="el-info-sel"></div>
|
|
792
920
|
</div>
|
|
793
|
-
|
|
794
921
|
<!-- \u2500\u2500 3 main tabs \u2500\u2500 -->
|
|
795
922
|
<div id="main-tabs">
|
|
796
923
|
<button class="main-tab active" onclick="switchMainTab('design')">Design</button>
|
|
@@ -872,12 +999,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
872
999
|
|
|
873
1000
|
<!-- \u2500\u2500 States pane \u2500\u2500 -->
|
|
874
1001
|
<div id="tab-states" class="rp-pane">
|
|
875
|
-
<div id="states-list">
|
|
876
|
-
<div class="states-empty">
|
|
877
|
-
<i class="bi bi-layers"></i>
|
|
878
|
-
No changes yet \u2014 edit elements on the page to see states here
|
|
879
|
-
</div>
|
|
880
|
-
</div>
|
|
1002
|
+
<div id="states-list"></div>
|
|
881
1003
|
</div><!-- #tab-states -->
|
|
882
1004
|
|
|
883
1005
|
<!-- \u2500\u2500 History pane (saved DB changesets for active variation) \u2500\u2500 -->
|
|
@@ -1125,6 +1247,7 @@ var suppressClickUntil = 0;
|
|
|
1125
1247
|
var dragAttachDoc = null;
|
|
1126
1248
|
var currentMainTab = 'design';
|
|
1127
1249
|
var currentLeftTab = 'elements';
|
|
1250
|
+
var currentSectionComponentsTab = 'components';
|
|
1128
1251
|
var dragHandleActive = false;
|
|
1129
1252
|
var domTreeCollapsed = {};
|
|
1130
1253
|
var domTreeRefreshTimer = null;
|
|
@@ -1156,6 +1279,13 @@ var stateChangesByVarId = {};
|
|
|
1156
1279
|
var appliedChangesetSnapshots = {};
|
|
1157
1280
|
/** Canonical JSON fingerprints of persisted changesets per variation (last load / finalize) */
|
|
1158
1281
|
var baselineChangesetsByVarId = {};
|
|
1282
|
+
/** Monotonic timestamp key for ordering mixed live + saved history rows. */
|
|
1283
|
+
var vveHistorySeq = 0;
|
|
1284
|
+
|
|
1285
|
+
function nextHistoryTimestamp() {
|
|
1286
|
+
vveHistorySeq += 1;
|
|
1287
|
+
return Date.now() * 1000 + vveHistorySeq;
|
|
1288
|
+
}
|
|
1159
1289
|
|
|
1160
1290
|
// \u2500\u2500 Dirty tracking (compare DB baseline + session stateChanges vs current export) \u2500\u2500
|
|
1161
1291
|
function beginSuppressIframeMutationDirty() {
|
|
@@ -1371,27 +1501,45 @@ function setDevice(device) {
|
|
|
1371
1501
|
|
|
1372
1502
|
// \u2500\u2500 Left panel tab switch \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
|
|
1373
1503
|
function switchLeftTab(tab) {
|
|
1504
|
+
if (tab !== 'elements' && tab !== 'dom-tree') return;
|
|
1374
1505
|
currentLeftTab = tab;
|
|
1375
|
-
var tabs = document.querySelectorAll('.lp-tab');
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1506
|
+
var tabs = document.querySelectorAll('.lp-tabs .lp-tab');
|
|
1507
|
+
for (var i = 0; i < tabs.length; i++) {
|
|
1508
|
+
var oc = tabs[i].getAttribute('onclick') || '';
|
|
1509
|
+
tabs[i].classList.toggle('active', oc.indexOf("switchLeftTab('" + tab + "')") >= 0);
|
|
1510
|
+
}
|
|
1511
|
+
var paneNames = ['elements', 'dom-tree'];
|
|
1512
|
+
for (var p = 0; p < paneNames.length; p++) {
|
|
1513
|
+
var pane = document.getElementById('tab-' + paneNames[p]);
|
|
1514
|
+
if (pane) pane.classList.toggle('active', paneNames[p] === tab);
|
|
1515
|
+
}
|
|
1382
1516
|
var inp = document.getElementById('comp-search');
|
|
1383
1517
|
if (tab === 'elements') {
|
|
1518
|
+
inp.placeholder = 'Search elements\u2026';
|
|
1519
|
+
renderElementsTree(inp.value);
|
|
1520
|
+
} else if (tab === 'dom-tree') {
|
|
1384
1521
|
inp.placeholder = 'Search layers\u2026';
|
|
1385
1522
|
renderDomTree(inp.value);
|
|
1386
|
-
} else if (tab === 'sections') {
|
|
1387
|
-
inp.placeholder = 'Search sections\u2026';
|
|
1388
|
-
renderSidebar(inp.value);
|
|
1389
|
-
} else {
|
|
1390
|
-
inp.placeholder = 'Search components\u2026';
|
|
1391
|
-
renderSidebar(inp.value);
|
|
1392
1523
|
}
|
|
1393
1524
|
}
|
|
1394
1525
|
|
|
1526
|
+
function switchSectionComponentsTab(tab) {
|
|
1527
|
+
if (tab !== 'components' && tab !== 'sections') return;
|
|
1528
|
+
currentSectionComponentsTab = tab;
|
|
1529
|
+
var tabs = document.querySelectorAll('.section-components-tabs .lp-tab');
|
|
1530
|
+
for (var i = 0; i < tabs.length; i++) {
|
|
1531
|
+
var oc = tabs[i].getAttribute('onclick') || '';
|
|
1532
|
+
tabs[i].classList.toggle('active', oc.indexOf("switchSectionComponentsTab('" + tab + "')") >= 0);
|
|
1533
|
+
}
|
|
1534
|
+
var compPane = document.getElementById('tab-components');
|
|
1535
|
+
var secPane = document.getElementById('tab-sections');
|
|
1536
|
+
if (compPane) compPane.classList.toggle('active', tab === 'components');
|
|
1537
|
+
if (secPane) secPane.classList.toggle('active', tab === 'sections');
|
|
1538
|
+
var inp = document.getElementById('comp-search');
|
|
1539
|
+
if (inp) inp.placeholder = tab === 'sections' ? 'Search sections\u2026' : 'Search components\u2026';
|
|
1540
|
+
renderSidebar(inp ? inp.value : '');
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1395
1543
|
// \u2500\u2500 Accordion toggle \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
|
|
1396
1544
|
function toggleAcc(name) {
|
|
1397
1545
|
var sec = document.getElementById('acc-' + name);
|
|
@@ -1514,42 +1662,20 @@ function logChange(selector, inputId, value, targetEl, originalValue) {
|
|
|
1514
1662
|
: (originalValue != null ? originalValue : '');
|
|
1515
1663
|
var entry = {
|
|
1516
1664
|
selector: selector, inputId: inputId, label: meta.label,
|
|
1517
|
-
cssProp: meta.cssProp, value: value, targetEl: targetEl, originalValue: orig
|
|
1665
|
+
cssProp: meta.cssProp, value: value, targetEl: targetEl, originalValue: orig, vveTs: nextHistoryTimestamp()
|
|
1518
1666
|
};
|
|
1519
1667
|
if (idx >= 0) { stateChanges[idx] = entry; } else { stateChanges.push(entry); }
|
|
1520
1668
|
}
|
|
1521
1669
|
if (currentMainTab === 'states') renderStatesTab();
|
|
1670
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
1522
1671
|
commitStateChangesForActiveVariation();
|
|
1523
1672
|
recomputeEditorDirty();
|
|
1524
1673
|
}
|
|
1525
1674
|
|
|
1526
1675
|
function renderStatesTab() {
|
|
1527
1676
|
var container = document.getElementById('states-list');
|
|
1528
|
-
if (!
|
|
1529
|
-
|
|
1530
|
-
return;
|
|
1531
|
-
}
|
|
1532
|
-
// Group by selector
|
|
1533
|
-
var groups = {};
|
|
1534
|
-
var order = [];
|
|
1535
|
-
stateChanges.forEach(function(c) {
|
|
1536
|
-
if (!groups[c.selector]) { groups[c.selector] = []; order.push(c.selector); }
|
|
1537
|
-
groups[c.selector].push(c);
|
|
1538
|
-
});
|
|
1539
|
-
var html = '<button id="states-clear" onclick="clearAllStates()"><i class="bi bi-trash3"></i> Clear all changes</button>';
|
|
1540
|
-
order.forEach(function(sel) {
|
|
1541
|
-
html += '<div class="state-group"><div class="state-group-sel">'+esc(sel)+'</div>';
|
|
1542
|
-
groups[sel].forEach(function(c) {
|
|
1543
|
-
var idx = stateChanges.indexOf(c);
|
|
1544
|
-
html += '<div class="state-item">' +
|
|
1545
|
-
'<span class="state-item-label">'+esc(c.label)+'</span>' +
|
|
1546
|
-
'<span class="state-item-val" title="'+esc(c.value)+'">'+esc(c.value)+'</span>' +
|
|
1547
|
-
'<button class="state-remove" title="Remove this change" onclick="removeStateChange('+idx+')">✕</button>' +
|
|
1548
|
-
'</div>';
|
|
1549
|
-
});
|
|
1550
|
-
html += '</div>';
|
|
1551
|
-
});
|
|
1552
|
-
container.innerHTML = html;
|
|
1677
|
+
if (!container) return;
|
|
1678
|
+
container.innerHTML = '';
|
|
1553
1679
|
}
|
|
1554
1680
|
|
|
1555
1681
|
// Resolve a live DOM element for a state-change entry.
|
|
@@ -1628,7 +1754,9 @@ function removeStateChange(idx) {
|
|
|
1628
1754
|
stateChanges.splice(idx, 1);
|
|
1629
1755
|
commitStateChangesForActiveVariation();
|
|
1630
1756
|
renderStatesTab();
|
|
1757
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
1631
1758
|
recomputeEditorDirty();
|
|
1759
|
+
scheduleDomTreeRefresh();
|
|
1632
1760
|
}
|
|
1633
1761
|
|
|
1634
1762
|
function clearAllStates() {
|
|
@@ -1639,7 +1767,9 @@ function clearAllStates() {
|
|
|
1639
1767
|
stateChanges = [];
|
|
1640
1768
|
commitStateChangesForActiveVariation();
|
|
1641
1769
|
renderStatesTab();
|
|
1770
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
1642
1771
|
recomputeEditorDirty();
|
|
1772
|
+
scheduleDomTreeRefresh();
|
|
1643
1773
|
}
|
|
1644
1774
|
|
|
1645
1775
|
// \u2500\u2500 History tab (saved changesets from DB for active variation) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -1812,61 +1942,169 @@ function historyEntryValuePreview(entry) {
|
|
|
1812
1942
|
return '';
|
|
1813
1943
|
}
|
|
1814
1944
|
|
|
1945
|
+
function getHistoryTimestampValue(raw, fallback) {
|
|
1946
|
+
var n = Number(raw);
|
|
1947
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
1948
|
+
return fallback;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
function historyTimestampForChangeset(entry, idx) {
|
|
1952
|
+
var base = idx + 1;
|
|
1953
|
+
if (!entry) return base;
|
|
1954
|
+
return getHistoryTimestampValue(
|
|
1955
|
+
entry.vveTs != null ? entry.vveTs : (entry.timestamp != null ? entry.timestamp : entry.ts),
|
|
1956
|
+
base,
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
function historyTimestampForStateChange(change, idx) {
|
|
1961
|
+
return getHistoryTimestampValue(change && change.vveTs, idx + 1);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
function formatHistoryTimestamp(ts) {
|
|
1965
|
+
if (!Number.isFinite(ts) || ts <= 0) return '';
|
|
1966
|
+
var ms = ts > 9999999999999 ? Math.floor(ts / 1000) : ts;
|
|
1967
|
+
var d = new Date(ms);
|
|
1968
|
+
if (isNaN(d.getTime())) return '';
|
|
1969
|
+
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
function formatHistoryRelativeTime(ts) {
|
|
1973
|
+
if (!Number.isFinite(ts) || ts <= 0) return '';
|
|
1974
|
+
var ms = ts > 9999999999999 ? Math.floor(ts / 1000) : ts;
|
|
1975
|
+
var diff = Math.max(0, Date.now() - ms);
|
|
1976
|
+
var sec = Math.floor(diff / 1000);
|
|
1977
|
+
if (sec < 5) return 'just now';
|
|
1978
|
+
if (sec < 60) return sec + ' seconds ago';
|
|
1979
|
+
var min = Math.floor(sec / 60);
|
|
1980
|
+
if (min < 60) return min + ' minute' + (min === 1 ? '' : 's') + ' ago';
|
|
1981
|
+
var hr = Math.floor(min / 60);
|
|
1982
|
+
if (hr < 24) return hr + ' hour' + (hr === 1 ? '' : 's') + ' ago';
|
|
1983
|
+
var day = Math.floor(hr / 24);
|
|
1984
|
+
return day + ' day' + (day === 1 ? '' : 's') + ' ago';
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
function getUnifiedHistoryItems() {
|
|
1988
|
+
var out = [];
|
|
1989
|
+
var v = getActiveVariationForHistory();
|
|
1990
|
+
var saved = v ? parseVariationChangesets(v) : [];
|
|
1991
|
+
for (var i = 0; i < saved.length; i++) {
|
|
1992
|
+
var e = saved[i];
|
|
1993
|
+
out.push({
|
|
1994
|
+
source: 'saved',
|
|
1995
|
+
idx: i,
|
|
1996
|
+
selector: (e && e.selector) || '(unknown)',
|
|
1997
|
+
label: historyEntryTypeLabel(e),
|
|
1998
|
+
value: historyEntryValuePreview(e),
|
|
1999
|
+
ts: historyTimestampForChangeset(e, i),
|
|
2000
|
+
tsLabel: formatHistoryTimestamp(historyTimestampForChangeset(e, i)),
|
|
2001
|
+
actor: 'Saved changeset',
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
var live = stateChanges || [];
|
|
2005
|
+
for (var j = 0; j < live.length; j++) {
|
|
2006
|
+
var c = live[j];
|
|
2007
|
+
if (!c) continue;
|
|
2008
|
+
var ts = historyTimestampForStateChange(c, j + saved.length);
|
|
2009
|
+
out.push({
|
|
2010
|
+
source: 'live',
|
|
2011
|
+
idx: j,
|
|
2012
|
+
selector: c.selector || '(unknown)',
|
|
2013
|
+
label: c.label || 'Live change',
|
|
2014
|
+
value: c.value != null ? String(c.value).slice(0, 120) : '',
|
|
2015
|
+
ts: ts,
|
|
2016
|
+
tsLabel: formatHistoryTimestamp(ts),
|
|
2017
|
+
actor: 'You',
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
out.sort(function(a, b) {
|
|
2021
|
+
if (b.ts !== a.ts) return b.ts - a.ts;
|
|
2022
|
+
if (a.source !== b.source) return a.source === 'live' ? -1 : 1;
|
|
2023
|
+
return b.idx - a.idx;
|
|
2024
|
+
});
|
|
2025
|
+
return out;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
1815
2028
|
function renderHistoryTab() {
|
|
1816
2029
|
var container = document.getElementById('history-list');
|
|
1817
2030
|
if (!container) return;
|
|
1818
|
-
var
|
|
1819
|
-
|
|
1820
|
-
if (!arr.length) {
|
|
2031
|
+
var items = getUnifiedHistoryItems();
|
|
2032
|
+
if (!items.length) {
|
|
1821
2033
|
container.innerHTML =
|
|
1822
|
-
'<div class="states-empty"><i class="bi bi-clock-history"></i>No
|
|
2034
|
+
'<div class="states-empty"><i class="bi bi-clock-history"></i>No changes yet</div>';
|
|
1823
2035
|
return;
|
|
1824
2036
|
}
|
|
1825
|
-
var groups = {};
|
|
1826
|
-
var order = [];
|
|
1827
|
-
for (var gi = 0; gi < arr.length; gi++) {
|
|
1828
|
-
var entry = arr[gi];
|
|
1829
|
-
var sel = entry.selector || '(unknown)';
|
|
1830
|
-
if (!groups[sel]) {
|
|
1831
|
-
groups[sel] = [];
|
|
1832
|
-
order.push(sel);
|
|
1833
|
-
}
|
|
1834
|
-
groups[sel].push({ entry: entry, idx: gi });
|
|
1835
|
-
}
|
|
1836
2037
|
var html =
|
|
1837
|
-
'<button type="button" id="history-clear" onclick="
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2038
|
+
'<button type="button" id="history-clear" onclick="clearAllUnifiedHistory()"><i class="bi bi-trash3"></i> Clear all changes</button>';
|
|
2039
|
+
html += '<div class="history-timeline">';
|
|
2040
|
+
for (var i = 0; i < items.length; i++) {
|
|
2041
|
+
var it = items[i];
|
|
2042
|
+
var title = 'Edit - ' + (it.label || 'Change');
|
|
2043
|
+
var avatarLabel = it.source === 'live' ? 'Y' : 'S';
|
|
2044
|
+
var timeText = formatHistoryRelativeTime(it.ts) || (it.tsLabel || '');
|
|
2045
|
+
html +=
|
|
2046
|
+
'<div class="history-item" role="button" tabindex="0" title="Jump to element in iframe" onclick="focusHistoryItem("' +
|
|
2047
|
+
esc(it.source) +
|
|
2048
|
+
'",' +
|
|
2049
|
+
it.idx +
|
|
2050
|
+
')">' +
|
|
2051
|
+
'<span class="history-dot"></span>' +
|
|
2052
|
+
'<div class="history-card">' +
|
|
2053
|
+
'<div class="history-title">' + esc(title) + '</div>' +
|
|
2054
|
+
'<div class="history-meta">' +
|
|
2055
|
+
'<span class="history-avatar">' + esc(avatarLabel) + '</span>' +
|
|
2056
|
+
'<span>' + esc(it.actor || 'Editor') + '</span>' +
|
|
2057
|
+
'</div>' +
|
|
2058
|
+
'<div class="history-time">' + esc(timeText || 'n/a') + '</div>' +
|
|
2059
|
+
'</div>' +
|
|
2060
|
+
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="removeHistoryItem("' +
|
|
2061
|
+
esc(it.source) +
|
|
2062
|
+
'",' +
|
|
2063
|
+
it.idx +
|
|
2064
|
+
', event)">✕</button>' +
|
|
2065
|
+
'</div>';
|
|
2066
|
+
}
|
|
2067
|
+
html += '</div>';
|
|
1867
2068
|
container.innerHTML = html;
|
|
1868
2069
|
}
|
|
1869
2070
|
|
|
2071
|
+
function focusHistoryItem(source, idx) {
|
|
2072
|
+
if (source === 'live') {
|
|
2073
|
+
var change = stateChanges[idx];
|
|
2074
|
+
if (!change || !change.selector) return;
|
|
2075
|
+
try {
|
|
2076
|
+
var iframe = document.getElementById('iframeId');
|
|
2077
|
+
var iframeDoc = iframe && iframe.contentDocument;
|
|
2078
|
+
if (!iframeDoc) return;
|
|
2079
|
+
var el = querySelectorResolved(iframeDoc, change.selector);
|
|
2080
|
+
if (!el) return;
|
|
2081
|
+
selectElement(el);
|
|
2082
|
+
try {
|
|
2083
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
2084
|
+
} catch(_) {
|
|
2085
|
+
el.scrollIntoView();
|
|
2086
|
+
}
|
|
2087
|
+
} catch(_) {}
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
focusHistoryChangeset(idx);
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
function removeHistoryItem(source, idx, evt) {
|
|
2094
|
+
if (source === 'live') {
|
|
2095
|
+
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
2096
|
+
removeStateChange(idx);
|
|
2097
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
2098
|
+
return;
|
|
2099
|
+
}
|
|
2100
|
+
removeHistoryChangeset(idx, evt);
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
function getLatestHistoryUndoTarget() {
|
|
2104
|
+
var list = getUnifiedHistoryItems();
|
|
2105
|
+
return list.length ? list[0] : null;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
1870
2108
|
function changesetListHasStructural(arr) {
|
|
1871
2109
|
if (!arr || !arr.length) return false;
|
|
1872
2110
|
for (var i = 0; i < arr.length; i++) {
|
|
@@ -1978,6 +2216,12 @@ function clearAllHistoryChangesets() {
|
|
|
1978
2216
|
softReloadEditorIframe();
|
|
1979
2217
|
}
|
|
1980
2218
|
|
|
2219
|
+
function clearAllUnifiedHistory() {
|
|
2220
|
+
clearAllStates();
|
|
2221
|
+
clearAllHistoryChangesets();
|
|
2222
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
2223
|
+
}
|
|
2224
|
+
|
|
1981
2225
|
// \u2500\u2500 Persisted active variation (survives iframe / full page reload) \u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1982
2226
|
/** All Visual Editor iframe keys in localStorage use this prefix \u2014 cleared on close. */
|
|
1983
2227
|
var VVE_LOCAL_STORAGE_PREFIX = 'vve:';
|
|
@@ -2243,13 +2487,7 @@ function granularAnySelectorMatches(doc, cs) {
|
|
|
2243
2487
|
|
|
2244
2488
|
/** Bust bfcache / same-URL no-op reloads so the iframe actually re-parses (loading \u2192 interactive). */
|
|
2245
2489
|
function appendIframeReloadBust(url) {
|
|
2246
|
-
|
|
2247
|
-
var stamp = Date.now();
|
|
2248
|
-
if (url.indexOf('__ve_reload=') !== -1) {
|
|
2249
|
-
return url.replace(/([&?])__ve_reload=[0-9]+/, '$1__ve_reload=' + stamp);
|
|
2250
|
-
}
|
|
2251
|
-
var sep = url.indexOf('?') !== -1 ? '&' : '?';
|
|
2252
|
-
return url + sep + '__ve_reload=' + stamp;
|
|
2490
|
+
return url;
|
|
2253
2491
|
}
|
|
2254
2492
|
|
|
2255
2493
|
// True when the iframe contentDocument belongs to the current iframe.src navigation.
|
|
@@ -2269,13 +2507,7 @@ function iframeDocMatchesNavigatedSrc(iframe, doc) {
|
|
|
2269
2507
|
try {
|
|
2270
2508
|
var base = window.location.href;
|
|
2271
2509
|
var su = new URL(src, base);
|
|
2272
|
-
if (su.searchParams && su.searchParams.has('__ve_reload')) {
|
|
2273
|
-
su.searchParams.delete('__ve_reload');
|
|
2274
|
-
}
|
|
2275
2510
|
var du = new URL(loc, base);
|
|
2276
|
-
if (du.searchParams && du.searchParams.has('__ve_reload')) {
|
|
2277
|
-
du.searchParams.delete('__ve_reload');
|
|
2278
|
-
}
|
|
2279
2511
|
// Same-origin proxy that keeps document address aligned with iframe src
|
|
2280
2512
|
if (su.origin === du.origin && su.pathname + su.search === du.pathname + du.search) {
|
|
2281
2513
|
return true;
|
|
@@ -2331,7 +2563,7 @@ function runConsistencyReconcile() {
|
|
|
2331
2563
|
var doc = iframe && iframe.contentDocument;
|
|
2332
2564
|
if (!doc || !doc.body) return;
|
|
2333
2565
|
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
2334
|
-
var cs =
|
|
2566
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
2335
2567
|
if (!cs.length || changesetsHaveBodySnapshot(cs)) return;
|
|
2336
2568
|
var granular = filterGranularChangesetEntries(cs);
|
|
2337
2569
|
var unresolved = countUnresolvedGranularSelectors(doc, granular);
|
|
@@ -2405,6 +2637,43 @@ function isIframeDomReady(iframe, doc) {
|
|
|
2405
2637
|
return true;
|
|
2406
2638
|
}
|
|
2407
2639
|
|
|
2640
|
+
function parseEditorUrlPayload(rawUrl) {
|
|
2641
|
+
if (!rawUrl) return null;
|
|
2642
|
+
try {
|
|
2643
|
+
var parsed = new URL(String(rawUrl), window.location.href);
|
|
2644
|
+
var nestedUrl = parsed.searchParams.get('url');
|
|
2645
|
+
var nestedPassword = parsed.searchParams.get('password');
|
|
2646
|
+
if (nestedUrl || nestedPassword) {
|
|
2647
|
+
return {
|
|
2648
|
+
url: nestedUrl || undefined,
|
|
2649
|
+
password: nestedPassword || undefined,
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
return {
|
|
2653
|
+
url: parsed.toString(),
|
|
2654
|
+
password:
|
|
2655
|
+
(experimentData && experimentData.editorPassword)
|
|
2656
|
+
? String(experimentData.editorPassword)
|
|
2657
|
+
: undefined,
|
|
2658
|
+
};
|
|
2659
|
+
} catch(_) {
|
|
2660
|
+
return null;
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
var lastEditorUrlPayloadKey = '';
|
|
2665
|
+
function emitEditorUrlChangedPayload(payload) {
|
|
2666
|
+
if (!payload) return;
|
|
2667
|
+
var key = String(payload.url || '') + '|' + String(payload.password || '');
|
|
2668
|
+
if (key === lastEditorUrlPayloadKey) return;
|
|
2669
|
+
lastEditorUrlPayloadKey = key;
|
|
2670
|
+
send('editor-url-changed', payload);
|
|
2671
|
+
}
|
|
2672
|
+
function emitEditorUrlChanged(rawUrl) {
|
|
2673
|
+
var payload = parseEditorUrlPayload(rawUrl);
|
|
2674
|
+
emitEditorUrlChangedPayload(payload);
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2408
2677
|
function loadPage(proxyUrl) {
|
|
2409
2678
|
showNoUrl(false);
|
|
2410
2679
|
lastLoadedProxyUrl = proxyUrl;
|
|
@@ -2414,6 +2683,7 @@ function loadPage(proxyUrl) {
|
|
|
2414
2683
|
iframe.style.display = 'block';
|
|
2415
2684
|
setIframePageLoadingUi(true);
|
|
2416
2685
|
iframe.src = appendIframeReloadBust(proxyUrl);
|
|
2686
|
+
emitEditorUrlChanged(proxyUrl);
|
|
2417
2687
|
startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
|
|
2418
2688
|
scheduleDomTreeRefresh();
|
|
2419
2689
|
}
|
|
@@ -2591,6 +2861,7 @@ function mergeGranularChainSets(baseList, overlayList) {
|
|
|
2591
2861
|
function appendSessionStructuralChainRow(varId, row) {
|
|
2592
2862
|
if (!varId || !row) return;
|
|
2593
2863
|
if (!sessionStructuralChainRowsByVarId[varId]) sessionStructuralChainRowsByVarId[varId] = [];
|
|
2864
|
+
if (row.vveTs == null) row.vveTs = nextHistoryTimestamp();
|
|
2594
2865
|
sessionStructuralChainRowsByVarId[varId].push(row);
|
|
2595
2866
|
}
|
|
2596
2867
|
|
|
@@ -2598,33 +2869,33 @@ function appendSessionStructuralChainRow(varId, row) {
|
|
|
2598
2869
|
function stateChangeToChainSet(c) {
|
|
2599
2870
|
if (!c || !c.selector) return null;
|
|
2600
2871
|
if (c.cssProp) {
|
|
2601
|
-
return { selector: c.selector, type: 'style', property: c.cssProp, value: c.value };
|
|
2872
|
+
return { selector: c.selector, type: 'style', property: c.cssProp, value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2602
2873
|
}
|
|
2603
2874
|
switch (c.inputId) {
|
|
2604
2875
|
case 'pp-text':
|
|
2605
|
-
return { selector: c.selector, type: 'content', value: c.value };
|
|
2876
|
+
return { selector: c.selector, type: 'content', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2606
2877
|
case 'pp-html':
|
|
2607
|
-
return { selector: c.selector, type: 'content', html: c.value };
|
|
2878
|
+
return { selector: c.selector, type: 'content', html: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2608
2879
|
case 'pp-cls':
|
|
2609
|
-
return { selector: c.selector, type: 'attribute', attribute: 'class', value: c.value };
|
|
2880
|
+
return { selector: c.selector, type: 'attribute', attribute: 'class', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2610
2881
|
case 'pp-id':
|
|
2611
|
-
return { selector: c.selector, type: 'attribute', attribute: 'id', value: c.value };
|
|
2882
|
+
return { selector: c.selector, type: 'attribute', attribute: 'id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2612
2883
|
case 'pp-href':
|
|
2613
|
-
return { selector: c.selector, type: 'attribute', attribute: 'href', value: c.value };
|
|
2884
|
+
return { selector: c.selector, type: 'attribute', attribute: 'href', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2614
2885
|
case 'pp-target':
|
|
2615
|
-
return { selector: c.selector, type: 'attribute', attribute: 'target', value: c.value };
|
|
2886
|
+
return { selector: c.selector, type: 'attribute', attribute: 'target', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2616
2887
|
case 'pp-src':
|
|
2617
|
-
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value };
|
|
2888
|
+
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2618
2889
|
case 'pp-alt':
|
|
2619
|
-
return { selector: c.selector, type: 'attribute', attribute: 'alt', value: c.value };
|
|
2890
|
+
return { selector: c.selector, type: 'attribute', attribute: 'alt', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2620
2891
|
case 'pp-ph':
|
|
2621
|
-
return { selector: c.selector, type: 'attribute', attribute: 'placeholder', value: c.value };
|
|
2892
|
+
return { selector: c.selector, type: 'attribute', attribute: 'placeholder', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2622
2893
|
case 'pp-css':
|
|
2623
|
-
return { selector: c.selector, type: 'attribute', attribute: 'style', value: c.value };
|
|
2894
|
+
return { selector: c.selector, type: 'attribute', attribute: 'style', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2624
2895
|
case 'pp-mob-css':
|
|
2625
|
-
return { selector: c.selector, type: 'attribute', attribute: 'data-mobile-css', value: c.value };
|
|
2896
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-mobile-css', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2626
2897
|
case 'pp-tab-css':
|
|
2627
|
-
return { selector: c.selector, type: 'attribute', attribute: 'data-tablet-css', value: c.value };
|
|
2898
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-tablet-css', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
2628
2899
|
default:
|
|
2629
2900
|
return null;
|
|
2630
2901
|
}
|
|
@@ -2912,7 +3183,7 @@ function applyActiveVariationHtml() {
|
|
|
2912
3183
|
if (!iframeDoc || !iframeDoc.body) return;
|
|
2913
3184
|
|
|
2914
3185
|
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
2915
|
-
var cs =
|
|
3186
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
2916
3187
|
refreshPersistentChangesetStyleTagForActiveVariation();
|
|
2917
3188
|
|
|
2918
3189
|
beginSuppressIframeMutationDirty();
|
|
@@ -2970,7 +3241,7 @@ function applyVariationGranularOnly(iframeDoc) {
|
|
|
2970
3241
|
if (!activeVarId || !iframeDoc || !iframeDoc.body) return;
|
|
2971
3242
|
if (varHtmlCache[activeVarId]) return;
|
|
2972
3243
|
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
2973
|
-
var cs =
|
|
3244
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
2974
3245
|
if (!cs.length || changesetsHaveBodySnapshot(cs)) return;
|
|
2975
3246
|
beginSuppressIframeMutationDirty();
|
|
2976
3247
|
try {
|
|
@@ -2989,7 +3260,7 @@ function reapplyActiveVariationGranular(iframeDoc) {
|
|
|
2989
3260
|
if (!activeVarId || !iframeDoc || !iframeDoc.body) return;
|
|
2990
3261
|
if (varHtmlCache[activeVarId]) return;
|
|
2991
3262
|
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
2992
|
-
var cs =
|
|
3263
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
2993
3264
|
if (!cs.length || changesetsHaveBodySnapshot(cs)) return;
|
|
2994
3265
|
beginSuppressIframeMutationDirty();
|
|
2995
3266
|
try {
|
|
@@ -3033,7 +3304,7 @@ function startIframeContentApplyWatcher(navGen, prevDocRef) {
|
|
|
3033
3304
|
|
|
3034
3305
|
if (doc.readyState === 'loading') {
|
|
3035
3306
|
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
3036
|
-
var cs0 =
|
|
3307
|
+
var cs0 = buildPersistedChainSetsForVariation(variation);
|
|
3037
3308
|
if (!cs0.length || changesetsHaveBodySnapshot(cs0)) return;
|
|
3038
3309
|
var granular = filterGranularChangesetEntries(cs0);
|
|
3039
3310
|
if (!granular.length) return;
|
|
@@ -3079,8 +3350,9 @@ function selectElement(el) {
|
|
|
3079
3350
|
document.getElementById('no-sel').style.display = 'none';
|
|
3080
3351
|
renderRightPanel(el);
|
|
3081
3352
|
updateSelectionToolbar();
|
|
3082
|
-
if (currentLeftTab === 'elements') {
|
|
3083
|
-
var
|
|
3353
|
+
if (currentLeftTab === 'elements' || currentLeftTab === 'dom-tree') {
|
|
3354
|
+
var treeRootId = currentLeftTab === 'elements' ? 'elements-root' : 'dom-tree-root';
|
|
3355
|
+
var dr = document.getElementById(treeRootId);
|
|
3084
3356
|
if (dr && dr.querySelector('.dt-row')) syncDomTreeSelection();
|
|
3085
3357
|
else scheduleDomTreeRefresh();
|
|
3086
3358
|
}
|
|
@@ -3343,27 +3615,32 @@ function deleteSelectedEl() {
|
|
|
3343
3615
|
}
|
|
3344
3616
|
|
|
3345
3617
|
function syncDomTreeSelection() {
|
|
3346
|
-
var
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
rows
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3618
|
+
var roots = ['dom-tree-root', 'elements-root'];
|
|
3619
|
+
for (var r = 0; r < roots.length; r++) {
|
|
3620
|
+
var root = document.getElementById(roots[r]);
|
|
3621
|
+
if (!root) continue;
|
|
3622
|
+
var rows = root.querySelectorAll('.dt-row');
|
|
3623
|
+
for (var i = 0; i < rows.length; i++) {
|
|
3624
|
+
rows[i].classList.toggle('dt-selected', !!(selectedEl && rows[i]._dtEl === selectedEl));
|
|
3625
|
+
}
|
|
3626
|
+
if (!selectedEl) continue;
|
|
3627
|
+
var found = null;
|
|
3628
|
+
for (var j = 0; j < rows.length; j++) {
|
|
3629
|
+
if (rows[j]._dtEl === selectedEl) { found = rows[j]; break; }
|
|
3630
|
+
}
|
|
3631
|
+
if (found) found.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
3356
3632
|
}
|
|
3357
|
-
if (found) found.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
3358
3633
|
}
|
|
3359
3634
|
|
|
3360
3635
|
function scheduleDomTreeRefresh() {
|
|
3361
|
-
if (currentLeftTab !== 'elements') return;
|
|
3636
|
+
if (currentLeftTab !== 'elements' && currentLeftTab !== 'dom-tree') return;
|
|
3362
3637
|
if (domTreeRefreshTimer) clearTimeout(domTreeRefreshTimer);
|
|
3363
3638
|
domTreeRefreshTimer = setTimeout(function() {
|
|
3364
3639
|
domTreeRefreshTimer = null;
|
|
3365
3640
|
var inp = document.getElementById('comp-search');
|
|
3366
|
-
|
|
3641
|
+
var q = inp ? inp.value : '';
|
|
3642
|
+
if (currentLeftTab === 'elements') renderElementsTree(q);
|
|
3643
|
+
else if (currentLeftTab === 'dom-tree') renderDomTree(q);
|
|
3367
3644
|
}, 150);
|
|
3368
3645
|
}
|
|
3369
3646
|
|
|
@@ -3386,6 +3663,129 @@ function domTreePathSegment(el) {
|
|
|
3386
3663
|
return tag + '[' + idx + ']';
|
|
3387
3664
|
}
|
|
3388
3665
|
|
|
3666
|
+
function renderElementsTree(filterRaw) {
|
|
3667
|
+
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
3668
|
+
var root = document.getElementById('elements-root');
|
|
3669
|
+
if (!root) return;
|
|
3670
|
+
var iframe = document.getElementById('iframeId');
|
|
3671
|
+
var doc = iframe && iframe.contentDocument;
|
|
3672
|
+
if (!isIframeDomReady(iframe, doc)) {
|
|
3673
|
+
root.innerHTML = '<div class="dt-muted">Load a page to see the elements.</div>';
|
|
3674
|
+
return;
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
function skippable(el) {
|
|
3678
|
+
return isDomTreeSkippableTagName(el.tagName);
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3681
|
+
function nodeIcon(tag) {
|
|
3682
|
+
tag = (tag || '').toLowerCase();
|
|
3683
|
+
if (/^h[1-6]$/.test(tag)) return 'bi bi-type-h1';
|
|
3684
|
+
if (tag === 'a') return 'bi bi-link-45deg';
|
|
3685
|
+
if (tag === 'img') return 'bi bi-image';
|
|
3686
|
+
if (tag === 'section' || tag === 'main' || tag === 'article' || tag === 'header' || tag === 'footer' || tag === 'nav') return 'bi bi-layout-three-columns';
|
|
3687
|
+
if (tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea') return 'bi bi-ui-radios';
|
|
3688
|
+
if (tag === 'ul' || tag === 'ol') return 'bi bi-list-ul';
|
|
3689
|
+
if (tag === 'li') return 'bi bi-dot';
|
|
3690
|
+
if (tag === 'svg') return 'bi bi-bezier2';
|
|
3691
|
+
if (tag === 'p' || tag === 'span') return 'bi bi-text-left';
|
|
3692
|
+
return 'bi bi-square';
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
function labelFor(el) {
|
|
3696
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
3697
|
+
return tag.toUpperCase();
|
|
3698
|
+
}
|
|
3699
|
+
|
|
3700
|
+
function isListableNode(el) {
|
|
3701
|
+
if (!el || el.nodeType !== 1) return false;
|
|
3702
|
+
if (skippable(el)) return false;
|
|
3703
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
3704
|
+
if (tag !== 'svg') {
|
|
3705
|
+
var p = el.parentElement;
|
|
3706
|
+
while (p) {
|
|
3707
|
+
if ((p.tagName || '').toLowerCase() === 'svg') return false;
|
|
3708
|
+
p = p.parentElement;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
return true;
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
var nodes = [];
|
|
3715
|
+
var i, cursor;
|
|
3716
|
+
try {
|
|
3717
|
+
cursor = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT, null);
|
|
3718
|
+
} catch(_) {
|
|
3719
|
+
cursor = null;
|
|
3720
|
+
}
|
|
3721
|
+
if (cursor) {
|
|
3722
|
+
while (cursor.nextNode()) {
|
|
3723
|
+
var node = cursor.currentNode;
|
|
3724
|
+
if (isListableNode(node)) nodes.push(node);
|
|
3725
|
+
if (nodes.length > 4000) break;
|
|
3726
|
+
}
|
|
3727
|
+
} else {
|
|
3728
|
+
function collectFlat(el) {
|
|
3729
|
+
if (!el || !el.children) return;
|
|
3730
|
+
for (var j = 0; j < el.children.length; j++) {
|
|
3731
|
+
var c = el.children[j];
|
|
3732
|
+
if (!isListableNode(c)) continue;
|
|
3733
|
+
nodes.push(c);
|
|
3734
|
+
if (nodes.length > 4000) return;
|
|
3735
|
+
collectFlat(c);
|
|
3736
|
+
if (nodes.length > 4000) return;
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
collectFlat(doc.body);
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3742
|
+
root.innerHTML = '';
|
|
3743
|
+
for (i = 0; i < nodes.length; i++) {
|
|
3744
|
+
var el = nodes[i];
|
|
3745
|
+
var lblText = labelFor(el);
|
|
3746
|
+
if (filterText && lblText.toLowerCase().indexOf(filterText) < 0) continue;
|
|
3747
|
+
|
|
3748
|
+
var row = document.createElement('div');
|
|
3749
|
+
row.className = 'dt-row';
|
|
3750
|
+
row._dtEl = el;
|
|
3751
|
+
if (el === selectedEl) row.classList.add('dt-selected');
|
|
3752
|
+
row.style.paddingLeft = '4px';
|
|
3753
|
+
|
|
3754
|
+
var spacer = document.createElement('button');
|
|
3755
|
+
spacer.type = 'button';
|
|
3756
|
+
spacer.className = 'dt-chev dt-spacer';
|
|
3757
|
+
|
|
3758
|
+
var ico = document.createElement('div');
|
|
3759
|
+
ico.className = 'dt-ico';
|
|
3760
|
+
ico.innerHTML = '<i class="' + nodeIcon(el.tagName) + '"></i>';
|
|
3761
|
+
|
|
3762
|
+
var lbl = document.createElement('div');
|
|
3763
|
+
lbl.className = 'dt-lbl';
|
|
3764
|
+
lbl.textContent = lblText;
|
|
3765
|
+
lbl.title = buildSelector(el);
|
|
3766
|
+
|
|
3767
|
+
row.appendChild(spacer);
|
|
3768
|
+
row.appendChild(ico);
|
|
3769
|
+
row.appendChild(lbl);
|
|
3770
|
+
row.onclick = (function(targetEl) {
|
|
3771
|
+
return function() { selectElementFromTree(targetEl); };
|
|
3772
|
+
})(el);
|
|
3773
|
+
row.onmouseenter = (function(targetEl) {
|
|
3774
|
+
return function() { setTreeHoverHighlight(targetEl); };
|
|
3775
|
+
})(el);
|
|
3776
|
+
root.appendChild(row);
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
if (!root.querySelector('.dt-row')) {
|
|
3780
|
+
root.innerHTML = filterText
|
|
3781
|
+
? '<div class="dt-muted">No elements match your search.</div>'
|
|
3782
|
+
: '<div class="dt-muted">No elements found.</div>';
|
|
3783
|
+
}
|
|
3784
|
+
root.onmouseleave = function() {
|
|
3785
|
+
clearTreeHoverHighlight();
|
|
3786
|
+
};
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3389
3789
|
function renderDomTree(filterRaw) {
|
|
3390
3790
|
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
3391
3791
|
var root = document.getElementById('dom-tree-root');
|
|
@@ -4124,6 +4524,20 @@ function recordReorderAfterDrag(movedEl) {
|
|
|
4124
4524
|
}
|
|
4125
4525
|
}
|
|
4126
4526
|
|
|
4527
|
+
function moveSelectedElByDirection(direction) {
|
|
4528
|
+
if (!selectedEl || !selectedEl.parentElement) return;
|
|
4529
|
+
var p = selectedEl.parentElement;
|
|
4530
|
+
var sibling = direction < 0 ? selectedEl.previousElementSibling : selectedEl.nextElementSibling;
|
|
4531
|
+
if (!sibling) return;
|
|
4532
|
+
if (direction < 0) p.insertBefore(selectedEl, sibling);
|
|
4533
|
+
else p.insertBefore(sibling, selectedEl);
|
|
4534
|
+
recordReorderAfterDrag(selectedEl);
|
|
4535
|
+
saveCurrentVariationHtml();
|
|
4536
|
+
recomputeEditorDirty();
|
|
4537
|
+
scheduleDomTreeRefresh();
|
|
4538
|
+
updateSelectionToolbar();
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4127
4541
|
function attachDragReposition() {
|
|
4128
4542
|
try {
|
|
4129
4543
|
var iframe = document.getElementById('iframeId');
|
|
@@ -4310,7 +4724,9 @@ function syncIframeInteractions(reason) {
|
|
|
4310
4724
|
scheduleConsistencyReconcile();
|
|
4311
4725
|
bindSelectionToolbarScroll();
|
|
4312
4726
|
var inp = document.getElementById('comp-search');
|
|
4313
|
-
|
|
4727
|
+
var q = inp ? inp.value : '';
|
|
4728
|
+
if (currentLeftTab === 'elements') renderElementsTree(q);
|
|
4729
|
+
else if (currentLeftTab === 'dom-tree') renderDomTree(q);
|
|
4314
4730
|
updateSelectionToolbar();
|
|
4315
4731
|
recomputeEditorDirty();
|
|
4316
4732
|
} catch(_) {}
|
|
@@ -4474,8 +4890,11 @@ function renderSidebar(filter) {
|
|
|
4474
4890
|
}
|
|
4475
4891
|
|
|
4476
4892
|
document.getElementById('comp-search').addEventListener('input', function() {
|
|
4477
|
-
if (currentLeftTab === 'elements')
|
|
4478
|
-
else
|
|
4893
|
+
if (currentLeftTab === 'elements') renderElementsTree(this.value);
|
|
4894
|
+
else if (currentLeftTab === 'dom-tree') renderDomTree(this.value);
|
|
4895
|
+
if (currentSectionComponentsTab === 'components' || currentSectionComponentsTab === 'sections') {
|
|
4896
|
+
renderSidebar(this.value);
|
|
4897
|
+
}
|
|
4479
4898
|
});
|
|
4480
4899
|
|
|
4481
4900
|
// \u2500\u2500 Save / Close \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\u2500\u2500\u2500
|
|
@@ -4541,19 +4960,11 @@ document.addEventListener('keydown', function(e) {
|
|
|
4541
4960
|
var k = (e.key || '').toLowerCase();
|
|
4542
4961
|
if (meta && !e.shiftKey && k === 'z') {
|
|
4543
4962
|
e.preventDefault();
|
|
4544
|
-
|
|
4545
|
-
Vvveb.Undo.undo();
|
|
4546
|
-
saveCurrentVariationHtml();
|
|
4547
|
-
recomputeEditorDirty();
|
|
4548
|
-
}
|
|
4963
|
+
runEditorUndo();
|
|
4549
4964
|
}
|
|
4550
4965
|
if (meta && e.shiftKey && k === 'z') {
|
|
4551
4966
|
e.preventDefault();
|
|
4552
|
-
|
|
4553
|
-
Vvveb.Undo.redo();
|
|
4554
|
-
saveCurrentVariationHtml();
|
|
4555
|
-
recomputeEditorDirty();
|
|
4556
|
-
}
|
|
4967
|
+
runEditorRedo();
|
|
4557
4968
|
}
|
|
4558
4969
|
if (meta && e.key === 's') { e.preventDefault(); handleSave(); }
|
|
4559
4970
|
if (e.key === 'Escape') {
|
|
@@ -4573,8 +4984,39 @@ document.addEventListener('keydown', function(e) {
|
|
|
4573
4984
|
if (selectedEl) deselectElement();
|
|
4574
4985
|
}
|
|
4575
4986
|
});
|
|
4576
|
-
|
|
4577
|
-
|
|
4987
|
+
function runEditorUndo() {
|
|
4988
|
+
var target = getLatestHistoryUndoTarget();
|
|
4989
|
+
if (target) {
|
|
4990
|
+
removeHistoryItem(target.source, target.idx);
|
|
4991
|
+
return;
|
|
4992
|
+
}
|
|
4993
|
+
if (!(typeof Vvveb !== 'undefined' && Vvveb.Undo)) return;
|
|
4994
|
+
Vvveb.Undo.undo();
|
|
4995
|
+
saveCurrentVariationHtml();
|
|
4996
|
+
recomputeEditorDirty();
|
|
4997
|
+
scheduleDomTreeRefresh();
|
|
4998
|
+
updateSelectionToolbar();
|
|
4999
|
+
}
|
|
5000
|
+
|
|
5001
|
+
function runEditorRedo() {
|
|
5002
|
+
if (!(typeof Vvveb !== 'undefined' && Vvveb.Undo)) return;
|
|
5003
|
+
Vvveb.Undo.redo();
|
|
5004
|
+
saveCurrentVariationHtml();
|
|
5005
|
+
recomputeEditorDirty();
|
|
5006
|
+
scheduleDomTreeRefresh();
|
|
5007
|
+
updateSelectionToolbar();
|
|
5008
|
+
}
|
|
5009
|
+
|
|
5010
|
+
document.getElementById('btn-undo').addEventListener('click', function(e) {
|
|
5011
|
+
e.preventDefault();
|
|
5012
|
+
e.stopPropagation();
|
|
5013
|
+
runEditorUndo();
|
|
5014
|
+
});
|
|
5015
|
+
document.getElementById('btn-redo').addEventListener('click', function(e) {
|
|
5016
|
+
e.preventDefault();
|
|
5017
|
+
e.stopPropagation();
|
|
5018
|
+
runEditorRedo();
|
|
5019
|
+
});
|
|
4578
5020
|
|
|
4579
5021
|
function layoutLoadingTooltip(host) {
|
|
4580
5022
|
var tip = host.querySelector('.ve-pl-tooltip');
|
|
@@ -4650,8 +5092,8 @@ function registerCROSections() {
|
|
|
4650
5092
|
|
|
4651
5093
|
window.addEventListener('load', function() {
|
|
4652
5094
|
registerCROSections();
|
|
4653
|
-
|
|
4654
|
-
|
|
5095
|
+
switchSectionComponentsTab(currentSectionComponentsTab);
|
|
5096
|
+
renderElementsTree(document.getElementById('comp-search').value);
|
|
4655
5097
|
vvvebReady = true;
|
|
4656
5098
|
bindLoadingTooltipPositioning();
|
|
4657
5099
|
|
|
@@ -4660,6 +5102,18 @@ window.addEventListener('load', function() {
|
|
|
4660
5102
|
|
|
4661
5103
|
// After each iframe load: apply variation, wire click+mutation handlers
|
|
4662
5104
|
var iframe = document.getElementById('iframeId');
|
|
5105
|
+
window.addEventListener('message', function(ev) {
|
|
5106
|
+
try {
|
|
5107
|
+
var d = ev && ev.data;
|
|
5108
|
+
if (!d || d.channel !== 'vvveb-proxy-url' || d.type !== 'editor-url-changed') return;
|
|
5109
|
+
if (!iframe || !iframe.contentWindow || ev.source !== iframe.contentWindow) return;
|
|
5110
|
+
var payload = d.payload || {};
|
|
5111
|
+
emitEditorUrlChangedPayload({
|
|
5112
|
+
url: payload.url || undefined,
|
|
5113
|
+
password: payload.password || undefined,
|
|
5114
|
+
});
|
|
5115
|
+
} catch(_) {}
|
|
5116
|
+
});
|
|
4663
5117
|
iframe.addEventListener('load', function() {
|
|
4664
5118
|
if (!iframe.src || iframe.src === 'about:blank' || iframe.src === window.location.href) return;
|
|
4665
5119
|
var doc = iframe.contentDocument;
|
|
@@ -4670,6 +5124,7 @@ window.addEventListener('load', function() {
|
|
|
4670
5124
|
}
|
|
4671
5125
|
var docUrl = '';
|
|
4672
5126
|
try { docUrl = String(doc.URL || ''); } catch(_) {}
|
|
5127
|
+
emitEditorUrlChanged(iframe.src || docUrl);
|
|
4673
5128
|
// Stale events: src may already be the proxy URL while the document is still
|
|
4674
5129
|
// about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
|
|
4675
5130
|
if (docUrl === 'about:blank') {
|
|
@@ -4704,12 +5159,22 @@ window.addEventListener('load', function() {
|
|
|
4704
5159
|
syncIframeInteractions('iframe-load');
|
|
4705
5160
|
});
|
|
4706
5161
|
|
|
4707
|
-
document.getElementById('sf-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
5162
|
+
var sfMoveUp = document.getElementById('sf-move-up');
|
|
5163
|
+
if (sfMoveUp) {
|
|
5164
|
+
sfMoveUp.addEventListener('click', function(e) {
|
|
5165
|
+
e.preventDefault();
|
|
5166
|
+
e.stopPropagation();
|
|
5167
|
+
moveSelectedElByDirection(-1);
|
|
5168
|
+
});
|
|
5169
|
+
}
|
|
5170
|
+
var sfMoveDown = document.getElementById('sf-move-down');
|
|
5171
|
+
if (sfMoveDown) {
|
|
5172
|
+
sfMoveDown.addEventListener('click', function(e) {
|
|
5173
|
+
e.preventDefault();
|
|
5174
|
+
e.stopPropagation();
|
|
5175
|
+
moveSelectedElByDirection(1);
|
|
5176
|
+
});
|
|
5177
|
+
}
|
|
4713
5178
|
document.getElementById('sf-dup').addEventListener('click', function(e) {
|
|
4714
5179
|
e.preventDefault();
|
|
4715
5180
|
e.stopPropagation();
|
|
@@ -4924,6 +5389,8 @@ function createVisualEditorMiddleware(options) {
|
|
|
4924
5389
|
const targetUrl = url.searchParams.get("url");
|
|
4925
5390
|
const password = url.searchParams.get("password") || "";
|
|
4926
5391
|
const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
|
|
5392
|
+
const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
|
|
5393
|
+
const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
|
|
4927
5394
|
const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
|
|
4928
5395
|
if (!targetUrl) {
|
|
4929
5396
|
res.statusCode = 400;
|
|
@@ -4933,13 +5400,37 @@ function createVisualEditorMiddleware(options) {
|
|
|
4933
5400
|
const parsed = new URL(targetUrl);
|
|
4934
5401
|
const origin = parsed.origin;
|
|
4935
5402
|
const method = (req.method || "GET").toUpperCase();
|
|
5403
|
+
const scraperProxyClient = useScraperProxy ? await getScraperProxyClient() : null;
|
|
5404
|
+
if (useScraperProxy && !scraperProxyClient) {
|
|
5405
|
+
res.statusCode = 500;
|
|
5406
|
+
res.setHeader("Content-Type", "application/json");
|
|
5407
|
+
res.end(
|
|
5408
|
+
JSON.stringify({
|
|
5409
|
+
error: "ScraperAPI proxy is not configured. Set SCRAPERAPI_PROXY_PASSWORD or SCRAPERAPI_API_KEY."
|
|
5410
|
+
})
|
|
5411
|
+
);
|
|
5412
|
+
return;
|
|
5413
|
+
}
|
|
5414
|
+
if (!SCRAPER_PROXY_PASSWORD) ;
|
|
5415
|
+
const upstreamFetch = (input, init = {}) => {
|
|
5416
|
+
if (!useScraperProxy || !scraperProxyClient) {
|
|
5417
|
+
const scraperUrl = new URL(SCRAPER_API_ENDPOINT);
|
|
5418
|
+
scraperUrl.searchParams.set("api_key", SCRAPER_PROXY_PASSWORD);
|
|
5419
|
+
scraperUrl.searchParams.set("url", input);
|
|
5420
|
+
return fetch(scraperUrl.toString(), init);
|
|
5421
|
+
}
|
|
5422
|
+
return scraperProxyClient.fetchFn(input, {
|
|
5423
|
+
...init,
|
|
5424
|
+
dispatcher: scraperProxyClient.dispatcher
|
|
5425
|
+
});
|
|
5426
|
+
};
|
|
4936
5427
|
const headers = {
|
|
4937
5428
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
|
4938
5429
|
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
4939
5430
|
};
|
|
4940
5431
|
let cookieHeader = "";
|
|
4941
5432
|
if (password) {
|
|
4942
|
-
const passResp = await
|
|
5433
|
+
const passResp = await upstreamFetch(`${origin}/password`, {
|
|
4943
5434
|
method: "POST",
|
|
4944
5435
|
headers: {
|
|
4945
5436
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -4986,7 +5477,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
4986
5477
|
const timeoutId = setTimeout(() => ac.abort(), upstreamTimeoutMs);
|
|
4987
5478
|
let upstream;
|
|
4988
5479
|
try {
|
|
4989
|
-
upstream = await
|
|
5480
|
+
upstream = await upstreamFetch(targetUrl, {
|
|
4990
5481
|
method,
|
|
4991
5482
|
headers: fetchHeaders,
|
|
4992
5483
|
body: requestBody ? Buffer.from(requestBody) : null,
|
|
@@ -4996,11 +5487,27 @@ function createVisualEditorMiddleware(options) {
|
|
|
4996
5487
|
} catch (fetchErr) {
|
|
4997
5488
|
clearTimeout(timeoutId);
|
|
4998
5489
|
const aborted = fetchErr?.name === "AbortError";
|
|
5490
|
+
const fetchCause = fetchErr?.cause;
|
|
4999
5491
|
res.statusCode = aborted ? 504 : 502;
|
|
5000
5492
|
res.setHeader("Content-Type", "application/json");
|
|
5001
5493
|
res.end(
|
|
5002
5494
|
JSON.stringify({
|
|
5003
|
-
error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed"
|
|
5495
|
+
error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed",
|
|
5496
|
+
phase: useScraperProxy ? "scraperapi-proxy-fetch" : "scraperapi-simple-fetch",
|
|
5497
|
+
fetchMode: useScraperProxy ? "proxy" : "simple",
|
|
5498
|
+
scraperapi: {
|
|
5499
|
+
host: SCRAPER_PROXY_HOST,
|
|
5500
|
+
port: SCRAPER_PROXY_PORT,
|
|
5501
|
+
username: SCRAPER_PROXY_USERNAME,
|
|
5502
|
+
endpoint: SCRAPER_API_ENDPOINT,
|
|
5503
|
+
hasProxyPassword: Boolean(SCRAPER_PROXY_PASSWORD),
|
|
5504
|
+
requestTlsRejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
|
|
5505
|
+
},
|
|
5506
|
+
cause: fetchCause && typeof fetchCause === "object" ? {
|
|
5507
|
+
name: fetchCause.name,
|
|
5508
|
+
code: fetchCause.code,
|
|
5509
|
+
message: fetchCause.message
|
|
5510
|
+
} : fetchCause ? String(fetchCause) : null
|
|
5004
5511
|
})
|
|
5005
5512
|
);
|
|
5006
5513
|
return;
|
|
@@ -5031,7 +5538,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
5031
5538
|
}
|
|
5032
5539
|
html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
|
|
5033
5540
|
const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5034
|
-
const proxyBase = `/api/conversion-proxy?
|
|
5541
|
+
const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
|
|
5035
5542
|
html = html.replace(
|
|
5036
5543
|
new RegExp(`(href|action)="${escapedOrigin}(/[^"]*)"`, "g"),
|
|
5037
5544
|
(match, attr, urlPath) => {
|
|
@@ -5042,6 +5549,12 @@ function createVisualEditorMiddleware(options) {
|
|
|
5042
5549
|
return `${attr}="${proxyBase}${encodeURIComponent(origin + urlPath)}"`;
|
|
5043
5550
|
}
|
|
5044
5551
|
);
|
|
5552
|
+
html = html.replace(
|
|
5553
|
+
/data-link="\/(?!\/)([^"]*)"/g,
|
|
5554
|
+
(_match, pathPart) => `data-link="/api/conversion-proxy?password=${encodeURIComponent(password)}&url=${encodeURIComponent(
|
|
5555
|
+
`${origin}/${pathPart}`
|
|
5556
|
+
)}"`
|
|
5557
|
+
);
|
|
5045
5558
|
if (html.includes("</head>")) {
|
|
5046
5559
|
html = html.replace(
|
|
5047
5560
|
"</head>",
|
|
@@ -5063,10 +5576,18 @@ var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
|
5063
5576
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
5064
5577
|
var PROXY_PASSWORD=${JSON.stringify(password)};
|
|
5065
5578
|
var STRICT_OBSERVER_FREEZE=${JSON.stringify(strictObserverFreezeForRequest)};
|
|
5579
|
+
var PARENT_URL_CHANNEL="vvveb-proxy-url";
|
|
5066
5580
|
window.__CONVERSION_EDITOR_ACTIVE__=true;
|
|
5581
|
+
function getEditorUrlPayload(){try{var u=new URL(window.location.href);var nested=u.searchParams.get("url");return{url:nested||u.toString(),password:u.searchParams.get("password")||undefined};}catch(_){return null;}}
|
|
5582
|
+
function notifyEditorUrlChanged(){try{var payload=getEditorUrlPayload();if(!payload)return;if(window.parent){window.parent.postMessage({channel:PARENT_URL_CHANNEL,type:"editor-url-changed",payload:payload},"*");}}catch(_){}}
|
|
5583
|
+
try{notifyEditorUrlChanged();}catch(_){}
|
|
5584
|
+
try{if(window.history&&typeof window.history.pushState==="function"){var nativePushState=window.history.pushState;window.history.pushState=function(){var ret=nativePushState.apply(window.history,arguments);setTimeout(notifyEditorUrlChanged,0);return ret;};}}catch(_){}
|
|
5585
|
+
try{if(window.history&&typeof window.history.replaceState==="function"){var nativeReplaceState=window.history.replaceState;window.history.replaceState=function(){var ret=nativeReplaceState.apply(window.history,arguments);setTimeout(notifyEditorUrlChanged,0);return ret;};}}catch(_){}
|
|
5586
|
+
try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
5587
|
+
try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
|
|
5067
5588
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
5068
5589
|
function toAbsolute(raw){if(isSkippable(raw))return raw;try{var base=raw.startsWith("/")||raw.startsWith("//")?TARGET_ORIGIN:TARGET_PAGE_URL;return new URL(raw,base).toString();}catch(_){return raw;}}
|
|
5069
|
-
function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?
|
|
5590
|
+
function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
|
|
5070
5591
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
5071
5592
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
5072
5593
|
function safeNavigate(raw,mode){var abs=toAbsolute(raw);var prox=toProxy(raw);if(!prox){try{console.warn("[conversion-proxy] redirect blocked",{mode:mode,requested:raw,resolved:abs,origin:TARGET_ORIGIN});}catch(_){}return false;}try{console.info("[conversion-proxy] redirect intercepted",{mode:mode,requested:raw,resolved:abs,proxied:prox});if(mode==="replace"&&nativeReplace){nativeReplace(prox);return true;}if(nativeAssign){nativeAssign(prox);return true;}window.location.href=prox;return true;}catch(err){try{console.warn("[conversion-proxy] redirect interception failed",{mode:mode,requested:raw,resolved:abs,proxied:prox,error:err&&err.message?err.message:String(err)});}catch(_){}return false;}}
|
|
@@ -5147,9 +5668,9 @@ if(window.fetch){
|
|
|
5147
5668
|
}
|
|
5148
5669
|
if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype&&window.XMLHttpRequest.prototype.open){var _open=window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open=function(method,url){try{var u=resolveUrl(String(url));if(u&&isNestedMalformedProxy(u)){arguments[1]=EMPTY_JSON_DATA;}else{arguments[1]=toAbsoluteOriginUrl(url);}}catch(_){}return _open.apply(this,arguments);};}
|
|
5149
5670
|
if(window.navigator&&typeof window.navigator.sendBeacon==="function"){var _beacon=window.navigator.sendBeacon.bind(window.navigator);window.navigator.sendBeacon=function(url,data){try{if(skipNestedProxyNetwork(String(url)))return true;}catch(_){}return _beacon(url,data);};}
|
|
5150
|
-
function withReloadBust(urlRaw){try{var u=resolveUrl(String(urlRaw||""));if(!u)return null;var p=u.pathname||"";var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;if(!isRootProxyPath)return null;
|
|
5151
|
-
document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(
|
|
5152
|
-
document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||
|
|
5671
|
+
function withReloadBust(urlRaw){try{var u=resolveUrl(String(urlRaw||""));if(!u)return null;var p=u.pathname||"";var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;if(!isRootProxyPath)return null;return u.toString();}catch(_){return null;}}
|
|
5672
|
+
document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(a){var href=a.getAttribute("href")||a.href||"";var hasModifier=!!(ev.metaKey||ev.ctrlKey||ev.shiftKey||ev.altKey);var targetAttr=(a.getAttribute("target")||"").toLowerCase();var isNewTab=targetAttr==="_blank";var isDownload=!!a.getAttribute("download");if(hasModifier||isNewTab||isDownload)return;var prox=toProxy(href);if(!prox)return;a.setAttribute("href",prox);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(href,"assign");return;}var summary=t.closest("summary[data-link]");if(summary&&summary.getAttribute){var raw=summary.getAttribute("data-link")||"";if(raw){var prox2=toProxy(raw);if(prox2){summary.setAttribute("data-link",prox2);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(raw,"assign");}}}}catch(_){}},true);
|
|
5673
|
+
document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||window.location.href;var prox=toProxy(act);if(prox)f.setAttribute("action",prox);}catch(_){}},true);
|
|
5153
5674
|
if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.serviceWorker.register==="function"){window.navigator.serviceWorker.register=function(){return Promise.resolve({scope:"disabled-in-editor-proxy"});};}
|
|
5154
5675
|
}catch(_){}})();</script>`;
|
|
5155
5676
|
if (html.includes("</head>")) {
|