@accelerated-agency/visual-editor 0.4.4 → 0.4.5
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/vite.cjs +440 -22
- package/dist/vite.js +440 -22
- package/package.json +1 -1
package/dist/vite.cjs
CHANGED
|
@@ -280,8 +280,97 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
280
280
|
.tb-viewport #dev-label{font-size:14px;font-weight:500;color:##404040;min-width:auto;background:none;border:none;padding:0;overflow:visible;white-space:nowrap;text-overflow:clip;border-radius:0;max-width:none}
|
|
281
281
|
.tb-viewport i{font-size:9px;color:##404040}
|
|
282
282
|
/* Device toggle buttons */
|
|
283
|
+
.tb-dev-wrap{position:relative;display:flex;align-items:center}
|
|
283
284
|
.tb-dev-btns{display:flex;align-items:center;gap:1px;padding:8px 4px;background:#F0F0F0;border-radius:7px; height: 30px;width: 116px;}
|
|
284
285
|
.tb-dev-3btns{display:flex;align-items:center;gap:2px;padding:8px 4px;background:#F0F0F0;border-radius:7px; height: 30px;width: 100px;}
|
|
286
|
+
.tb-dev-menu{
|
|
287
|
+
position:absolute;top:calc(100% + 8px);right:0;z-index:12040;display:none;
|
|
288
|
+
width:264px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px 4px;
|
|
289
|
+
box-shadow:0 12px 28px rgba(2,6,23,.18);color:#27272a
|
|
290
|
+
}
|
|
291
|
+
.tb-dev-menu.open{display:block}
|
|
292
|
+
.tb-dev-menu .hd{font-size:12px;font-weight:600;color:#3f3f46;margin-bottom:10px}
|
|
293
|
+
.tb-dev-menu .row{display:flex;align-items:center;gap:8px;}
|
|
294
|
+
.tb-dev-menu .row.height-width-row .row{
|
|
295
|
+
flex-direction: column;
|
|
296
|
+
align-items: flex-start;
|
|
297
|
+
}
|
|
298
|
+
.tb-dev-menu .row.height-width-row label{
|
|
299
|
+
color: var(--content-subtle, #737373);
|
|
300
|
+
font-size: 12px;
|
|
301
|
+
font-style: normal;
|
|
302
|
+
font-weight: 500;
|
|
303
|
+
line-height: 14px; /* 116.667% */
|
|
304
|
+
}
|
|
305
|
+
.tb-dev-menu > .row{
|
|
306
|
+
padding: 4px 12px;
|
|
307
|
+
}
|
|
308
|
+
.tb-dev-menu label{ flex-shrink: 0;
|
|
309
|
+
overflow: hidden;
|
|
310
|
+
color: var(--base-surface, #646465);
|
|
311
|
+
font-size: var(--font-size-sm, 14px);
|
|
312
|
+
font-style: normal;
|
|
313
|
+
font-weight: 500;
|
|
314
|
+
line-height: var(--font-leading-4, 16px);
|
|
315
|
+
white-space: nowrap;
|
|
316
|
+
min-width: fit-content;}
|
|
317
|
+
.tb-dev-menu input{
|
|
318
|
+
box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
319
|
+
width:100%;height:30px;border-radius:6px;
|
|
320
|
+
padding:0 8px;
|
|
321
|
+
font-size:12px;
|
|
322
|
+
color:#18181b;
|
|
323
|
+
background:#fff;
|
|
324
|
+
outline:none;
|
|
325
|
+
color:#404040;
|
|
326
|
+
border-color:transparent;
|
|
327
|
+
}
|
|
328
|
+
.tb-dev-menu input#dev-zoom-level{
|
|
329
|
+
max-width: fit-content;
|
|
330
|
+
margin-left: auto;
|
|
331
|
+
}
|
|
332
|
+
.tb-dev-menu input:focus{
|
|
333
|
+
border-color:#1A1A1A;
|
|
334
|
+
box-shadow:0 0 0 2px rgba(99,102,241,.14)
|
|
335
|
+
}
|
|
336
|
+
.tb-dev-menu .row-split > *{flex:1}
|
|
337
|
+
.tb-dev-menu .panel-toggle label{width:100%}
|
|
338
|
+
.tb-dev-menu .panel-toggle-label{
|
|
339
|
+
overflow:hidden;
|
|
340
|
+
color:var(--content-subtle, #737373);
|
|
341
|
+
text-overflow:ellipsis;
|
|
342
|
+
font-size:var(--font-size-sm, 14px);
|
|
343
|
+
font-style:normal;
|
|
344
|
+
font-weight:500;
|
|
345
|
+
line-height:var(--font-leading-4, 16px);
|
|
346
|
+
white-space:nowrap;
|
|
347
|
+
cursor:pointer;
|
|
348
|
+
}
|
|
349
|
+
.tb-dev-menu .vp-presets{
|
|
350
|
+
margin-top:8px;padding-top:8px;border-top:1px dashed #ececf0;
|
|
351
|
+
display:flex;flex-direction:column;gap:2px
|
|
352
|
+
}
|
|
353
|
+
.tb-dev-menu .vp-preset-btn{
|
|
354
|
+
border:none;background:transparent;text-align:left;cursor:pointer;
|
|
355
|
+
border-radius:6px;
|
|
356
|
+
padding:8px 12px;
|
|
357
|
+
color: var(--content-subtle, #737373);
|
|
358
|
+
text-overflow: ellipsis;
|
|
359
|
+
font-size: var(--font-size-sm, 14px);
|
|
360
|
+
font-style: normal;
|
|
361
|
+
font-weight: 500;
|
|
362
|
+
line-height: var(--font-leading-4, 16px);
|
|
363
|
+
}
|
|
364
|
+
.tb-dev-menu .vp-preset-btn:hover,.tb-dev-menu .vp-preset-btn.active{background:#f4f4f5}
|
|
365
|
+
.tb-dev-menu .ft{
|
|
366
|
+
margin-top:10px;padding-top:8px;border-top:1px solid #ececf0;
|
|
367
|
+
display:flex;justify-content:flex-end
|
|
368
|
+
}
|
|
369
|
+
.tb-dev-menu .apply-btn{
|
|
370
|
+
border:1px solid #d4d4d8;background:#f8fafc;color:#111827;border-radius:6px;
|
|
371
|
+
height:30px;padding:0 10px;font-size:12px;font-weight:600;cursor:pointer
|
|
372
|
+
}
|
|
373
|
+
.tb-dev-menu .apply-btn:hover{background:#eef2ff;border-color:#a5b4fc}
|
|
285
374
|
/* Dark icon buttons */
|
|
286
375
|
.tb-dk-btn{width:28px;height:28px;background:transparent;border:none;border-radius:5px;cursor:pointer;color:#71717a;display:flex;align-items:center;justify-content:center;font-size:13px;transition:all .12s;flex-shrink:0}
|
|
287
376
|
.tb-dk-btn:hover{color:#e4e4e7;background:rgba(255,255,255,.07)}
|
|
@@ -440,7 +529,12 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
440
529
|
/* \u2500\u2500 Device frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
441
530
|
#device-frame{
|
|
442
531
|
width:100%;min-height:100%;display:flex;align-items:stretch;
|
|
443
|
-
justify-content:center;
|
|
532
|
+
justify-content:center;transform-origin:top center;
|
|
533
|
+
transition:max-width .3s ease,width .2s ease,height .2s ease
|
|
534
|
+
}
|
|
535
|
+
#device-frame.desktop{
|
|
536
|
+
max-width:1440px;
|
|
537
|
+
box-shadow:0 0 0 1px var(--border),0 4px 24px rgba(0,0,0,.08)
|
|
444
538
|
}
|
|
445
539
|
#device-frame.tablet{
|
|
446
540
|
max-width:768px;
|
|
@@ -841,10 +935,8 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
841
935
|
</head>
|
|
842
936
|
<body class="mode-editor">
|
|
843
937
|
<div id="app">
|
|
844
|
-
|
|
845
938
|
<!-- \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->
|
|
846
939
|
<div id="toolbar">
|
|
847
|
-
|
|
848
940
|
<!-- Left: Logo + Breadcrumb -->
|
|
849
941
|
<div class="tb-left">
|
|
850
942
|
<span class="tb-logo">\u2733</span>
|
|
@@ -862,11 +954,45 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
862
954
|
<span id="dev-label">1440px</span>
|
|
863
955
|
<i class="bi bi-chevron-down"></i>
|
|
864
956
|
</div>
|
|
865
|
-
<div class="tb-dev-
|
|
866
|
-
<
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
957
|
+
<div class="tb-dev-wrap">
|
|
958
|
+
<div class="tb-dev-btns">
|
|
959
|
+
<button class="tb-dk-btn active" id="dev-desktop" onclick="setDevice('desktop')" title="Desktop \u2014 1440x1024"><i class="bi bi-display"></i></button>
|
|
960
|
+
<button class="tb-dk-btn" id="dev-tablet" onclick="setDevice('tablet')" title="Tablet \u2014 768x1024"><i class="bi bi-tablet"></i></button>
|
|
961
|
+
<button class="tb-dk-btn" id="dev-mobile" onclick="setDevice('mobile')" title="Mobile \u2014 390x844"><i class="bi bi-phone"></i></button>
|
|
962
|
+
<button class="tb-dk-btn" id="dev-more-btn" title="More options"><i class="bi bi-three-dots"></i></button>
|
|
963
|
+
</div>
|
|
964
|
+
<div id="dev-more-menu" class="tb-dev-menu" aria-hidden="true">
|
|
965
|
+
<div class="row row-zoom">
|
|
966
|
+
<label for="dev-zoom-level">Zoom</label>
|
|
967
|
+
<input id="dev-zoom-level" type="number" min="25" max="200" step="5" value="100" />
|
|
968
|
+
</div>
|
|
969
|
+
<div class="row row-split row-width height-width-row">
|
|
970
|
+
<div class="row" style="margin:0">
|
|
971
|
+
<label for="dev-custom-width">Width</label>
|
|
972
|
+
<input id="dev-custom-width" type="number" min="240" max="3840" step="1" value="1440" />
|
|
973
|
+
</div>
|
|
974
|
+
<div class="row row-height" style="margin:0">
|
|
975
|
+
<label for="dev-custom-height">Height</label>
|
|
976
|
+
<input id="dev-custom-height" type="number" min="320" max="3840" step="1" value="1024" />
|
|
977
|
+
</div>
|
|
978
|
+
</div>
|
|
979
|
+
<div class="row panel-toggle">
|
|
980
|
+
<label id="left-panel-toggle-label" class="panel-toggle-label">Collapse left panel</label>
|
|
981
|
+
</div>
|
|
982
|
+
|
|
983
|
+
<div class="vp-presets" id="dev-preset-list" aria-label="Device presets">
|
|
984
|
+
<button type="button" class="vp-preset-btn" data-preset="desktop">Desktop</button>
|
|
985
|
+
<button type="button" class="vp-preset-btn" data-preset="mobile">iPhone 13</button>
|
|
986
|
+
<button type="button" class="vp-preset-btn" data-preset="galaxy-s22">Galaxy S22</button>
|
|
987
|
+
<button type="button" class="vp-preset-btn" data-preset="tablet">iPad</button>
|
|
988
|
+
<button type="button" class="vp-preset-btn" data-preset="galaxy-j1">Galaxy J1</button>
|
|
989
|
+
<button type="button" class="vp-preset-btn" data-preset="iphone-7">iPhone 7</button>
|
|
990
|
+
<button type="button" class="vp-preset-btn" data-preset="responsive">Responsive</button>
|
|
991
|
+
</div>
|
|
992
|
+
<div class="ft">
|
|
993
|
+
<button type="button" class="apply-btn" id="dev-apply-btn">Apply</button>
|
|
994
|
+
</div>
|
|
995
|
+
</div>
|
|
870
996
|
</div>
|
|
871
997
|
<button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
|
|
872
998
|
<button class="tb-dk-btn" id="btn-redo" title="Redo (\u2318\u21E7Z)" style="display:none"><i class="bi bi-arrow-clockwise"></i></button>
|
|
@@ -1003,7 +1129,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1003
1129
|
</div>
|
|
1004
1130
|
|
|
1005
1131
|
<!-- Device frame containing the editing iframe -->
|
|
1006
|
-
<div id="device-frame">
|
|
1132
|
+
<div id="device-frame" class="desktop">
|
|
1007
1133
|
<iframe id="iframeId" name="iframeId" allowfullscreen></iframe>
|
|
1008
1134
|
</div>
|
|
1009
1135
|
|
|
@@ -1373,6 +1499,11 @@ var isDirty = false;
|
|
|
1373
1499
|
var vvvebReady = false;
|
|
1374
1500
|
var currentMode = 'editor';
|
|
1375
1501
|
var currentDevice = 'desktop';
|
|
1502
|
+
var leftPanelCollapsed = false;
|
|
1503
|
+
var viewportPreset = 'desktop';
|
|
1504
|
+
var viewportWidth = 1440;
|
|
1505
|
+
var viewportHeight = 1024;
|
|
1506
|
+
var viewportZoom = 1;
|
|
1376
1507
|
var selectedEl = null;
|
|
1377
1508
|
/** Stable selector fingerprint for resilient selection recovery after DOM churn. */
|
|
1378
1509
|
var selectedElFingerprint = '';
|
|
@@ -1625,15 +1756,202 @@ function setMode(mode) {
|
|
|
1625
1756
|
}
|
|
1626
1757
|
|
|
1627
1758
|
// \u2500\u2500 Device 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\u2500\u2500\u2500
|
|
1628
|
-
var
|
|
1759
|
+
var DEVICE_PRESETS = {
|
|
1760
|
+
desktop: { label: 'Desktop', width: 1440, height: 1024, device: 'desktop' },
|
|
1761
|
+
tablet: { label: 'iPad', width: 768, height: 1024, device: 'tablet' },
|
|
1762
|
+
mobile: { label: 'iPhone 13', width: 390, height: 844, device: 'mobile' },
|
|
1763
|
+
'galaxy-s22': { label: 'Galaxy S22', width: 360, height: 780, device: 'mobile' },
|
|
1764
|
+
'iphone-7': { label: 'iPhone 7', width: 375, height: 667, device: 'mobile' },
|
|
1765
|
+
'galaxy-j1': { label: 'Galaxy J1', width: 360, height: 640, device: 'mobile' },
|
|
1766
|
+
responsive: { label: 'Responsive', width: 1280, height: 800, device: 'desktop' },
|
|
1767
|
+
};
|
|
1768
|
+
|
|
1769
|
+
function clampViewportNumber(v, fallback, min, max) {
|
|
1770
|
+
var n = parseInt(v, 10);
|
|
1771
|
+
if (!Number.isFinite(n)) return fallback;
|
|
1772
|
+
return Math.max(min, Math.min(max, n));
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
function getViewportFitZoom() {
|
|
1776
|
+
var panel = document.getElementById('iframe-panel');
|
|
1777
|
+
var available = panel ? Math.max(260, panel.clientWidth - 24) : viewportWidth;
|
|
1778
|
+
if (!viewportWidth || viewportWidth <= 0) return 1;
|
|
1779
|
+
return Math.min(1, available / viewportWidth);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
function getAppliedViewportZoom() {
|
|
1783
|
+
var z = Number(viewportZoom);
|
|
1784
|
+
if (!Number.isFinite(z) || z <= 0) z = 1;
|
|
1785
|
+
z = Math.max(0.25, Math.min(2, z));
|
|
1786
|
+
return Math.min(z, getViewportFitZoom());
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
function updateViewportLabel() {
|
|
1790
|
+
var lbl = document.getElementById('dev-label');
|
|
1791
|
+
if (!lbl) return;
|
|
1792
|
+
var zoomPct = Math.round(getAppliedViewportZoom() * 100);
|
|
1793
|
+
lbl.textContent = viewportWidth + 'x' + viewportHeight + ' \xB7 ' + zoomPct + '%';
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
function syncViewportMenuControls() {
|
|
1797
|
+
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
1798
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
1799
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
1800
|
+
var zoomInp = document.getElementById('dev-zoom-level');
|
|
1801
|
+
if (presetButtons && presetButtons.length) {
|
|
1802
|
+
for (var i = 0; i < presetButtons.length; i++) {
|
|
1803
|
+
var key = presetButtons[i].getAttribute('data-preset') || '';
|
|
1804
|
+
presetButtons[i].classList.toggle('active', key === viewportPreset);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
if (widthInp) widthInp.value = String(viewportWidth);
|
|
1808
|
+
if (heightInp) heightInp.value = String(viewportHeight);
|
|
1809
|
+
if (zoomInp) zoomInp.value = String(Math.round(getAppliedViewportZoom() * 100));
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
function applyViewportFrame() {
|
|
1813
|
+
var frame = document.getElementById('device-frame');
|
|
1814
|
+
var iframe = document.getElementById('iframeId');
|
|
1815
|
+
if (!frame) return;
|
|
1816
|
+
frame.className = currentDevice;
|
|
1817
|
+
frame.style.width = viewportWidth + 'px';
|
|
1818
|
+
frame.style.height = viewportHeight + 'px';
|
|
1819
|
+
frame.style.maxWidth = 'none';
|
|
1820
|
+
frame.style.zoom = String(getAppliedViewportZoom());
|
|
1821
|
+
if (iframe) {
|
|
1822
|
+
iframe.style.height = viewportHeight + 'px';
|
|
1823
|
+
iframe.style.minHeight = viewportHeight + 'px';
|
|
1824
|
+
}
|
|
1825
|
+
updateViewportLabel();
|
|
1826
|
+
syncViewportMenuControls();
|
|
1827
|
+
if (selectedEl && currentMode === 'editor') requestAnimationFrame(function() { positionSelectionToolbar(); });
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
function setViewportPreset(presetKey) {
|
|
1831
|
+
var preset = DEVICE_PRESETS[presetKey];
|
|
1832
|
+
if (!preset) return;
|
|
1833
|
+
viewportPreset = presetKey;
|
|
1834
|
+
viewportWidth = preset.width;
|
|
1835
|
+
viewportHeight = preset.height;
|
|
1836
|
+
currentDevice = preset.device || 'desktop';
|
|
1837
|
+
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1838
|
+
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1839
|
+
});
|
|
1840
|
+
applyViewportFrame();
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1629
1843
|
function setDevice(device) {
|
|
1844
|
+
viewportPreset = device;
|
|
1630
1845
|
currentDevice = device;
|
|
1631
|
-
var
|
|
1632
|
-
|
|
1846
|
+
var preset = DEVICE_PRESETS[device] || DEVICE_PRESETS.desktop;
|
|
1847
|
+
viewportWidth = preset.width;
|
|
1848
|
+
viewportHeight = preset.height;
|
|
1633
1849
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1634
1850
|
document.getElementById('dev-' + d).classList.toggle('active', d === device);
|
|
1635
1851
|
});
|
|
1636
|
-
|
|
1852
|
+
applyViewportFrame();
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
function setViewportCustomFromInputs() {
|
|
1856
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
1857
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
1858
|
+
var zoomInp = document.getElementById('dev-zoom-level');
|
|
1859
|
+
viewportWidth = clampViewportNumber(widthInp ? widthInp.value : '', viewportWidth, 240, 3840);
|
|
1860
|
+
viewportHeight = clampViewportNumber(heightInp ? heightInp.value : '', viewportHeight, 320, 3840);
|
|
1861
|
+
var z = clampViewportNumber(zoomInp ? zoomInp.value : '', Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
1862
|
+
viewportZoom = z / 100;
|
|
1863
|
+
viewportPreset = 'custom';
|
|
1864
|
+
currentDevice = viewportWidth <= 480 ? 'mobile' : (viewportWidth <= 1024 ? 'tablet' : 'desktop');
|
|
1865
|
+
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1866
|
+
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1867
|
+
});
|
|
1868
|
+
applyViewportFrame();
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
function closeViewportMenu() {
|
|
1872
|
+
var menu = document.getElementById('dev-more-menu');
|
|
1873
|
+
if (!menu) return;
|
|
1874
|
+
menu.classList.remove('open');
|
|
1875
|
+
menu.setAttribute('aria-hidden', 'true');
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
function toggleViewportMenu() {
|
|
1879
|
+
var menu = document.getElementById('dev-more-menu');
|
|
1880
|
+
if (!menu) return;
|
|
1881
|
+
var shouldOpen = !menu.classList.contains('open');
|
|
1882
|
+
menu.classList.toggle('open', shouldOpen);
|
|
1883
|
+
menu.setAttribute('aria-hidden', shouldOpen ? 'false' : 'true');
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
function bindViewportControls() {
|
|
1887
|
+
var btn = document.getElementById('dev-more-btn');
|
|
1888
|
+
var menu = document.getElementById('dev-more-menu');
|
|
1889
|
+
var leftPanelToggleLabel = document.getElementById('left-panel-toggle-label');
|
|
1890
|
+
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
1891
|
+
var applyBtn = document.getElementById('dev-apply-btn');
|
|
1892
|
+
var zoomInp = document.getElementById('dev-zoom-level');
|
|
1893
|
+
var viewportBtn = document.querySelector('.tb-viewport');
|
|
1894
|
+
function updateLeftPanelToggleLabel() {
|
|
1895
|
+
if (!leftPanelToggleLabel) return;
|
|
1896
|
+
leftPanelToggleLabel.textContent = leftPanelCollapsed ? 'Expand left panel' : 'Collapse left panel';
|
|
1897
|
+
}
|
|
1898
|
+
function setLeftPanelCollapsed(collapsed) {
|
|
1899
|
+
var panel = document.getElementById('left-panel');
|
|
1900
|
+
leftPanelCollapsed = !!collapsed;
|
|
1901
|
+
if (panel) panel.style.display = leftPanelCollapsed ? 'none' : '';
|
|
1902
|
+
updateLeftPanelToggleLabel();
|
|
1903
|
+
applyViewportFrame();
|
|
1904
|
+
}
|
|
1905
|
+
if (leftPanelToggleLabel) {
|
|
1906
|
+
leftPanelToggleLabel.addEventListener('click', function(e) {
|
|
1907
|
+
e.preventDefault();
|
|
1908
|
+
e.stopPropagation();
|
|
1909
|
+
setLeftPanelCollapsed(!leftPanelCollapsed);
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
if (btn) btn.addEventListener('click', function(e) {
|
|
1913
|
+
e.preventDefault();
|
|
1914
|
+
e.stopPropagation();
|
|
1915
|
+
toggleViewportMenu();
|
|
1916
|
+
});
|
|
1917
|
+
if (viewportBtn) viewportBtn.addEventListener('click', function(e) {
|
|
1918
|
+
e.preventDefault();
|
|
1919
|
+
e.stopPropagation();
|
|
1920
|
+
toggleViewportMenu();
|
|
1921
|
+
});
|
|
1922
|
+
if (applyBtn) applyBtn.addEventListener('click', function(e) {
|
|
1923
|
+
e.preventDefault();
|
|
1924
|
+
setViewportCustomFromInputs();
|
|
1925
|
+
closeViewportMenu();
|
|
1926
|
+
});
|
|
1927
|
+
if (zoomInp) {
|
|
1928
|
+
zoomInp.addEventListener('change', function() {
|
|
1929
|
+
var z = clampViewportNumber(zoomInp.value, Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
1930
|
+
viewportZoom = z / 100;
|
|
1931
|
+
applyViewportFrame();
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
if (presetButtons && presetButtons.length) {
|
|
1935
|
+
for (var i = 0; i < presetButtons.length; i++) {
|
|
1936
|
+
presetButtons[i].addEventListener('click', function(e) {
|
|
1937
|
+
e.preventDefault();
|
|
1938
|
+
var key = this.getAttribute('data-preset');
|
|
1939
|
+
if (!key) return;
|
|
1940
|
+
setViewportPreset(key);
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
document.addEventListener('click', function(e) {
|
|
1945
|
+
if (!menu || !menu.classList.contains('open')) return;
|
|
1946
|
+
if (menu.contains(e.target) || (btn && btn.contains(e.target)) || (viewportBtn && viewportBtn.contains(e.target))) return;
|
|
1947
|
+
closeViewportMenu();
|
|
1948
|
+
});
|
|
1949
|
+
document.addEventListener('keydown', function(e) {
|
|
1950
|
+
if (e.key === 'Escape') closeViewportMenu();
|
|
1951
|
+
});
|
|
1952
|
+
window.addEventListener('resize', function() { applyViewportFrame(); });
|
|
1953
|
+
updateLeftPanelToggleLabel();
|
|
1954
|
+
applyViewportFrame();
|
|
1637
1955
|
}
|
|
1638
1956
|
|
|
1639
1957
|
// \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
|
|
@@ -1795,9 +2113,60 @@ function getOriginalValue(inputId, el) {
|
|
|
1795
2113
|
}
|
|
1796
2114
|
}
|
|
1797
2115
|
|
|
2116
|
+
var PX_DEFAULT_INPUT_IDS = {
|
|
2117
|
+
'pp-mt': true, 'pp-mr': true, 'pp-mb': true, 'pp-ml': true,
|
|
2118
|
+
'pp-pt': true, 'pp-pr': true, 'pp-pb': true, 'pp-pl': true,
|
|
2119
|
+
};
|
|
2120
|
+
|
|
2121
|
+
var PX_DEFAULT_CSS_PROPS = {
|
|
2122
|
+
'margin-top': true, 'margin-right': true, 'margin-bottom': true, 'margin-left': true,
|
|
2123
|
+
'padding-top': true, 'padding-right': true, 'padding-bottom': true, 'padding-left': true,
|
|
2124
|
+
};
|
|
2125
|
+
|
|
2126
|
+
function normalizeCssValueForProperty(prop, value) {
|
|
2127
|
+
var p = prop == null ? '' : String(prop).trim();
|
|
2128
|
+
var pKebab = p
|
|
2129
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
2130
|
+
.replace(/_/g, '-')
|
|
2131
|
+
.replace(/!important/gi, '')
|
|
2132
|
+
.replace(/[^a-zA-Z-]/g, '')
|
|
2133
|
+
.toLowerCase();
|
|
2134
|
+
var raw = value == null ? '' : String(value).trim();
|
|
2135
|
+
var rawClean = raw.replace(/[\u200B\u200C\u200D\uFEFF]/g, '').trim();
|
|
2136
|
+
var numericCandidate = rawClean.replace(/[, ]+/g, '');
|
|
2137
|
+
var isSpacingProp = /^(?:margin|padding)(?:-(?:top|right|bottom|left))?$/.test(pKebab);
|
|
2138
|
+
if (!pKebab || !rawClean) return rawClean;
|
|
2139
|
+
var numericValue = Number(numericCandidate);
|
|
2140
|
+
var shouldAddPx =
|
|
2141
|
+
isSpacingProp &&
|
|
2142
|
+
numericCandidate !== '' &&
|
|
2143
|
+
Number.isFinite(numericValue) &&
|
|
2144
|
+
/^[-+]?(?:[0-9]+(?:[.][0-9]+)?|[.][0-9]+)$/.test(numericCandidate);
|
|
2145
|
+
var out = shouldAddPx ? numericCandidate + 'px' : rawClean;
|
|
2146
|
+
return out;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
function normalizeChainSetRowUnits(row) {
|
|
2150
|
+
if (!row) return row;
|
|
2151
|
+
if (normalizeChangesetType(row) === 'style') {
|
|
2152
|
+
row.value = normalizeCssValueForProperty(row.property || row.cssProp, row.value);
|
|
2153
|
+
}
|
|
2154
|
+
return row;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
function normalizeLoggedValue(inputId, value) {
|
|
2158
|
+
var raw = value == null ? '' : String(value).trim();
|
|
2159
|
+
if (!raw) return raw;
|
|
2160
|
+
if (PX_DEFAULT_INPUT_IDS[inputId] && /^-?d+(?:.d+)?$/.test(raw)) {
|
|
2161
|
+
return raw + 'px';
|
|
2162
|
+
}
|
|
2163
|
+
return raw;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
1798
2166
|
function logChange(selector, inputId, value, targetEl, originalValue) {
|
|
1799
2167
|
var meta = PROP_META[inputId];
|
|
1800
2168
|
if (!meta) return;
|
|
2169
|
+
value = normalizeLoggedValue(inputId, value);
|
|
1801
2170
|
var key = selector + '||' + inputId;
|
|
1802
2171
|
// Skip trivially empty / reset values \u2014 remove from log if present
|
|
1803
2172
|
if (value === '' || value === 'none' || value === 'auto' || value === 'normal') {
|
|
@@ -2496,9 +2865,24 @@ function pickActiveVariationIdForLoad(data, variationsArr, prevMemoryId, allowPr
|
|
|
2496
2865
|
return fallback;
|
|
2497
2866
|
}
|
|
2498
2867
|
|
|
2868
|
+
function updateExperimentNameLabel(data) {
|
|
2869
|
+
var el = document.getElementById('tb-exp-name');
|
|
2870
|
+
if (!el) return;
|
|
2871
|
+
var name = '';
|
|
2872
|
+
try {
|
|
2873
|
+
name = data && data.name != null ? String(data.name).trim() : '';
|
|
2874
|
+
} catch(_) {
|
|
2875
|
+
name = '';
|
|
2876
|
+
}
|
|
2877
|
+
if (!name) name = 'Visual Editor';
|
|
2878
|
+
el.textContent = name;
|
|
2879
|
+
el.title = name;
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2499
2882
|
// \u2500\u2500 Experiment loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
2500
2883
|
function handleLoadExperiment(data) {
|
|
2501
2884
|
clearPendingGranularChangesets();
|
|
2885
|
+
updateExperimentNameLabel(data);
|
|
2502
2886
|
var prevKey = experimentData
|
|
2503
2887
|
? String(experimentData.experimentId || '') + '|' + String(experimentData.pageUrl || '')
|
|
2504
2888
|
: '';
|
|
@@ -3140,7 +3524,13 @@ function removeSessionStructuralRowByTimestamp(varId, ts) {
|
|
|
3140
3524
|
function stateChangeToChainSet(c) {
|
|
3141
3525
|
if (!c || !c.selector) return null;
|
|
3142
3526
|
if (c.cssProp) {
|
|
3143
|
-
return {
|
|
3527
|
+
return {
|
|
3528
|
+
selector: c.selector,
|
|
3529
|
+
type: 'style',
|
|
3530
|
+
property: c.cssProp,
|
|
3531
|
+
value: normalizeCssValueForProperty(c.cssProp, c.value),
|
|
3532
|
+
vveTs: c.vveTs || nextHistoryTimestamp()
|
|
3533
|
+
};
|
|
3144
3534
|
}
|
|
3145
3535
|
switch (c.inputId) {
|
|
3146
3536
|
case 'pp-text':
|
|
@@ -3312,7 +3702,7 @@ function buildPersistentStyleRulesForActiveVariation() {
|
|
|
3312
3702
|
if (value == null || value === '') return;
|
|
3313
3703
|
var sel = sanitizeSelectorForMatch(String(selector)) || String(selector);
|
|
3314
3704
|
var pr = String(prop).trim();
|
|
3315
|
-
var val =
|
|
3705
|
+
var val = normalizeCssValueForProperty(pr, value);
|
|
3316
3706
|
if (!sel || !pr || !val) return;
|
|
3317
3707
|
var k = sel + '__vve_sep__' + pr;
|
|
3318
3708
|
if (!map[k]) order.push(k);
|
|
@@ -3350,7 +3740,8 @@ function buildPersistentStyleRulesForActiveVariation() {
|
|
|
3350
3740
|
var lines = [];
|
|
3351
3741
|
for (var oi = 0; oi < order.length; oi++) {
|
|
3352
3742
|
var row = map[order[oi]];
|
|
3353
|
-
|
|
3743
|
+
var outVal = normalizeCssValueForProperty(row.property, row.value);
|
|
3744
|
+
lines.push(row.selector + ' { ' + row.property + ': ' + outVal + ' !important; }');
|
|
3354
3745
|
}
|
|
3355
3746
|
return lines.join('\\n');
|
|
3356
3747
|
}
|
|
@@ -3501,7 +3892,9 @@ function buildPersistedChainSetsForVariation(v) {
|
|
|
3501
3892
|
var row = stateChangeToChainSet(sourceStateChanges[si]);
|
|
3502
3893
|
if (row) overlay.push(row);
|
|
3503
3894
|
}
|
|
3504
|
-
|
|
3895
|
+
var merged = mergeGranularChainSets(mergeGranularChainSets(base, sessionExtra), overlay);
|
|
3896
|
+
for (var mi = 0; mi < merged.length; mi++) normalizeChainSetRowUnits(merged[mi]);
|
|
3897
|
+
return merged;
|
|
3505
3898
|
}
|
|
3506
3899
|
|
|
3507
3900
|
/**
|
|
@@ -5403,6 +5796,7 @@ function registerCROSections() {
|
|
|
5403
5796
|
|
|
5404
5797
|
window.addEventListener('load', function() {
|
|
5405
5798
|
registerCROSections();
|
|
5799
|
+
bindViewportControls();
|
|
5406
5800
|
switchSectionComponentsTab(currentSectionComponentsTab);
|
|
5407
5801
|
renderElementsTree(document.getElementById('comp-search').value);
|
|
5408
5802
|
vvvebReady = true;
|
|
@@ -6110,8 +6504,32 @@ ${runtimePreflightScript}
|
|
|
6110
6504
|
var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
6111
6505
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
6112
6506
|
var EMPTY_JSON_DATA="data:application/json;charset=utf-8,%7B%7D";
|
|
6113
|
-
|
|
6114
|
-
|
|
6507
|
+
var _proxyCtx=(function(){try{return new URL(window.location.href);}catch(_){return null;}})();
|
|
6508
|
+
var PROXY_ROOT="/api/conversion-proxy";
|
|
6509
|
+
var PROXY_PASSWORD=_proxyCtx?_proxyCtx.searchParams.get("password")||"":"";
|
|
6510
|
+
var PROXY_BASE_URL=_proxyCtx?_proxyCtx.searchParams.get("conversionProxyBaseUrl")||"":"";
|
|
6511
|
+
var PROXY_TRACKING_MARKERS=_proxyCtx?_proxyCtx.searchParams.get("trackingMarkers")||"":"";
|
|
6512
|
+
var PROXY_STRICT_FREEZE=_proxyCtx?_proxyCtx.searchParams.get("strictObserverFreeze")||"":"";
|
|
6513
|
+
var PROXY_UPSTREAM_MODE=_proxyCtx?_proxyCtx.searchParams.get("proxy")||"":"";
|
|
6514
|
+
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
6515
|
+
function toProxyNetworkUrl(raw){
|
|
6516
|
+
if(isSkippable(raw))return raw;
|
|
6517
|
+
try{
|
|
6518
|
+
var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;
|
|
6519
|
+
var abs=new URL(raw,base);
|
|
6520
|
+
if(abs.origin!==TARGET_ORIGIN)return raw;
|
|
6521
|
+
var prox=new URL(PROXY_ROOT,window.location.origin);
|
|
6522
|
+
prox.searchParams.set("password",PROXY_PASSWORD||"");
|
|
6523
|
+
prox.searchParams.set("url",abs.toString());
|
|
6524
|
+
if(PROXY_BASE_URL)prox.searchParams.set("conversionProxyBaseUrl",PROXY_BASE_URL);
|
|
6525
|
+
if(PROXY_TRACKING_MARKERS)prox.searchParams.set("trackingMarkers",PROXY_TRACKING_MARKERS);
|
|
6526
|
+
if(PROXY_STRICT_FREEZE)prox.searchParams.set("strictObserverFreeze",PROXY_STRICT_FREEZE);
|
|
6527
|
+
if(PROXY_UPSTREAM_MODE)prox.searchParams.set("proxy",PROXY_UPSTREAM_MODE);
|
|
6528
|
+
return prox.toString();
|
|
6529
|
+
}catch(_){
|
|
6530
|
+
return raw;
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6115
6533
|
function resolveUrl(s){try{return new URL(s,window.location.href);}catch(_){return null;}}
|
|
6116
6534
|
function isNestedMalformedProxy(u){if(!u)return false;var p=u.pathname||"";if(p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0)return false;return p.indexOf("api/conversion-proxy")!==-1;}
|
|
6117
6535
|
function skipNestedProxyNetwork(s){var u=typeof s==="string"?resolveUrl(s):null;return u&&isNestedMalformedProxy(u);}
|
|
@@ -6124,9 +6542,9 @@ if(window.fetch){
|
|
|
6124
6542
|
var rawUrl=typeof input==="string"?input:(input&&input.url?String(input.url):"");
|
|
6125
6543
|
if(rawUrl&&skipNestedProxyNetwork(rawUrl))return emptyJsonFetchResponse();
|
|
6126
6544
|
if(typeof input==="string"){
|
|
6127
|
-
input=
|
|
6545
|
+
input=toProxyNetworkUrl(input);
|
|
6128
6546
|
}else if(input&&input.url){
|
|
6129
|
-
var next=
|
|
6547
|
+
var next=toProxyNetworkUrl(input.url);
|
|
6130
6548
|
if(next!==input.url){input=new Request(next,input);}
|
|
6131
6549
|
}
|
|
6132
6550
|
afterUrl=typeof input==="string"?input:(input&&input.url?String(input.url):"");
|
|
@@ -6160,7 +6578,7 @@ if(window.fetch){
|
|
|
6160
6578
|
});
|
|
6161
6579
|
};
|
|
6162
6580
|
}
|
|
6163
|
-
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]=
|
|
6581
|
+
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]=toProxyNetworkUrl(url);}}catch(_){}return _open.apply(this,arguments);};}
|
|
6164
6582
|
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);};}
|
|
6165
6583
|
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;}}
|
|
6166
6584
|
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);
|
package/dist/vite.js
CHANGED
|
@@ -272,8 +272,97 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
272
272
|
.tb-viewport #dev-label{font-size:14px;font-weight:500;color:##404040;min-width:auto;background:none;border:none;padding:0;overflow:visible;white-space:nowrap;text-overflow:clip;border-radius:0;max-width:none}
|
|
273
273
|
.tb-viewport i{font-size:9px;color:##404040}
|
|
274
274
|
/* Device toggle buttons */
|
|
275
|
+
.tb-dev-wrap{position:relative;display:flex;align-items:center}
|
|
275
276
|
.tb-dev-btns{display:flex;align-items:center;gap:1px;padding:8px 4px;background:#F0F0F0;border-radius:7px; height: 30px;width: 116px;}
|
|
276
277
|
.tb-dev-3btns{display:flex;align-items:center;gap:2px;padding:8px 4px;background:#F0F0F0;border-radius:7px; height: 30px;width: 100px;}
|
|
278
|
+
.tb-dev-menu{
|
|
279
|
+
position:absolute;top:calc(100% + 8px);right:0;z-index:12040;display:none;
|
|
280
|
+
width:264px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px 4px;
|
|
281
|
+
box-shadow:0 12px 28px rgba(2,6,23,.18);color:#27272a
|
|
282
|
+
}
|
|
283
|
+
.tb-dev-menu.open{display:block}
|
|
284
|
+
.tb-dev-menu .hd{font-size:12px;font-weight:600;color:#3f3f46;margin-bottom:10px}
|
|
285
|
+
.tb-dev-menu .row{display:flex;align-items:center;gap:8px;}
|
|
286
|
+
.tb-dev-menu .row.height-width-row .row{
|
|
287
|
+
flex-direction: column;
|
|
288
|
+
align-items: flex-start;
|
|
289
|
+
}
|
|
290
|
+
.tb-dev-menu .row.height-width-row label{
|
|
291
|
+
color: var(--content-subtle, #737373);
|
|
292
|
+
font-size: 12px;
|
|
293
|
+
font-style: normal;
|
|
294
|
+
font-weight: 500;
|
|
295
|
+
line-height: 14px; /* 116.667% */
|
|
296
|
+
}
|
|
297
|
+
.tb-dev-menu > .row{
|
|
298
|
+
padding: 4px 12px;
|
|
299
|
+
}
|
|
300
|
+
.tb-dev-menu label{ flex-shrink: 0;
|
|
301
|
+
overflow: hidden;
|
|
302
|
+
color: var(--base-surface, #646465);
|
|
303
|
+
font-size: var(--font-size-sm, 14px);
|
|
304
|
+
font-style: normal;
|
|
305
|
+
font-weight: 500;
|
|
306
|
+
line-height: var(--font-leading-4, 16px);
|
|
307
|
+
white-space: nowrap;
|
|
308
|
+
min-width: fit-content;}
|
|
309
|
+
.tb-dev-menu input{
|
|
310
|
+
box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
311
|
+
width:100%;height:30px;border-radius:6px;
|
|
312
|
+
padding:0 8px;
|
|
313
|
+
font-size:12px;
|
|
314
|
+
color:#18181b;
|
|
315
|
+
background:#fff;
|
|
316
|
+
outline:none;
|
|
317
|
+
color:#404040;
|
|
318
|
+
border-color:transparent;
|
|
319
|
+
}
|
|
320
|
+
.tb-dev-menu input#dev-zoom-level{
|
|
321
|
+
max-width: fit-content;
|
|
322
|
+
margin-left: auto;
|
|
323
|
+
}
|
|
324
|
+
.tb-dev-menu input:focus{
|
|
325
|
+
border-color:#1A1A1A;
|
|
326
|
+
box-shadow:0 0 0 2px rgba(99,102,241,.14)
|
|
327
|
+
}
|
|
328
|
+
.tb-dev-menu .row-split > *{flex:1}
|
|
329
|
+
.tb-dev-menu .panel-toggle label{width:100%}
|
|
330
|
+
.tb-dev-menu .panel-toggle-label{
|
|
331
|
+
overflow:hidden;
|
|
332
|
+
color:var(--content-subtle, #737373);
|
|
333
|
+
text-overflow:ellipsis;
|
|
334
|
+
font-size:var(--font-size-sm, 14px);
|
|
335
|
+
font-style:normal;
|
|
336
|
+
font-weight:500;
|
|
337
|
+
line-height:var(--font-leading-4, 16px);
|
|
338
|
+
white-space:nowrap;
|
|
339
|
+
cursor:pointer;
|
|
340
|
+
}
|
|
341
|
+
.tb-dev-menu .vp-presets{
|
|
342
|
+
margin-top:8px;padding-top:8px;border-top:1px dashed #ececf0;
|
|
343
|
+
display:flex;flex-direction:column;gap:2px
|
|
344
|
+
}
|
|
345
|
+
.tb-dev-menu .vp-preset-btn{
|
|
346
|
+
border:none;background:transparent;text-align:left;cursor:pointer;
|
|
347
|
+
border-radius:6px;
|
|
348
|
+
padding:8px 12px;
|
|
349
|
+
color: var(--content-subtle, #737373);
|
|
350
|
+
text-overflow: ellipsis;
|
|
351
|
+
font-size: var(--font-size-sm, 14px);
|
|
352
|
+
font-style: normal;
|
|
353
|
+
font-weight: 500;
|
|
354
|
+
line-height: var(--font-leading-4, 16px);
|
|
355
|
+
}
|
|
356
|
+
.tb-dev-menu .vp-preset-btn:hover,.tb-dev-menu .vp-preset-btn.active{background:#f4f4f5}
|
|
357
|
+
.tb-dev-menu .ft{
|
|
358
|
+
margin-top:10px;padding-top:8px;border-top:1px solid #ececf0;
|
|
359
|
+
display:flex;justify-content:flex-end
|
|
360
|
+
}
|
|
361
|
+
.tb-dev-menu .apply-btn{
|
|
362
|
+
border:1px solid #d4d4d8;background:#f8fafc;color:#111827;border-radius:6px;
|
|
363
|
+
height:30px;padding:0 10px;font-size:12px;font-weight:600;cursor:pointer
|
|
364
|
+
}
|
|
365
|
+
.tb-dev-menu .apply-btn:hover{background:#eef2ff;border-color:#a5b4fc}
|
|
277
366
|
/* Dark icon buttons */
|
|
278
367
|
.tb-dk-btn{width:28px;height:28px;background:transparent;border:none;border-radius:5px;cursor:pointer;color:#71717a;display:flex;align-items:center;justify-content:center;font-size:13px;transition:all .12s;flex-shrink:0}
|
|
279
368
|
.tb-dk-btn:hover{color:#e4e4e7;background:rgba(255,255,255,.07)}
|
|
@@ -432,7 +521,12 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
|
|
|
432
521
|
/* \u2500\u2500 Device frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
433
522
|
#device-frame{
|
|
434
523
|
width:100%;min-height:100%;display:flex;align-items:stretch;
|
|
435
|
-
justify-content:center;
|
|
524
|
+
justify-content:center;transform-origin:top center;
|
|
525
|
+
transition:max-width .3s ease,width .2s ease,height .2s ease
|
|
526
|
+
}
|
|
527
|
+
#device-frame.desktop{
|
|
528
|
+
max-width:1440px;
|
|
529
|
+
box-shadow:0 0 0 1px var(--border),0 4px 24px rgba(0,0,0,.08)
|
|
436
530
|
}
|
|
437
531
|
#device-frame.tablet{
|
|
438
532
|
max-width:768px;
|
|
@@ -833,10 +927,8 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
833
927
|
</head>
|
|
834
928
|
<body class="mode-editor">
|
|
835
929
|
<div id="app">
|
|
836
|
-
|
|
837
930
|
<!-- \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->
|
|
838
931
|
<div id="toolbar">
|
|
839
|
-
|
|
840
932
|
<!-- Left: Logo + Breadcrumb -->
|
|
841
933
|
<div class="tb-left">
|
|
842
934
|
<span class="tb-logo">\u2733</span>
|
|
@@ -854,11 +946,45 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
854
946
|
<span id="dev-label">1440px</span>
|
|
855
947
|
<i class="bi bi-chevron-down"></i>
|
|
856
948
|
</div>
|
|
857
|
-
<div class="tb-dev-
|
|
858
|
-
<
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
949
|
+
<div class="tb-dev-wrap">
|
|
950
|
+
<div class="tb-dev-btns">
|
|
951
|
+
<button class="tb-dk-btn active" id="dev-desktop" onclick="setDevice('desktop')" title="Desktop \u2014 1440x1024"><i class="bi bi-display"></i></button>
|
|
952
|
+
<button class="tb-dk-btn" id="dev-tablet" onclick="setDevice('tablet')" title="Tablet \u2014 768x1024"><i class="bi bi-tablet"></i></button>
|
|
953
|
+
<button class="tb-dk-btn" id="dev-mobile" onclick="setDevice('mobile')" title="Mobile \u2014 390x844"><i class="bi bi-phone"></i></button>
|
|
954
|
+
<button class="tb-dk-btn" id="dev-more-btn" title="More options"><i class="bi bi-three-dots"></i></button>
|
|
955
|
+
</div>
|
|
956
|
+
<div id="dev-more-menu" class="tb-dev-menu" aria-hidden="true">
|
|
957
|
+
<div class="row row-zoom">
|
|
958
|
+
<label for="dev-zoom-level">Zoom</label>
|
|
959
|
+
<input id="dev-zoom-level" type="number" min="25" max="200" step="5" value="100" />
|
|
960
|
+
</div>
|
|
961
|
+
<div class="row row-split row-width height-width-row">
|
|
962
|
+
<div class="row" style="margin:0">
|
|
963
|
+
<label for="dev-custom-width">Width</label>
|
|
964
|
+
<input id="dev-custom-width" type="number" min="240" max="3840" step="1" value="1440" />
|
|
965
|
+
</div>
|
|
966
|
+
<div class="row row-height" style="margin:0">
|
|
967
|
+
<label for="dev-custom-height">Height</label>
|
|
968
|
+
<input id="dev-custom-height" type="number" min="320" max="3840" step="1" value="1024" />
|
|
969
|
+
</div>
|
|
970
|
+
</div>
|
|
971
|
+
<div class="row panel-toggle">
|
|
972
|
+
<label id="left-panel-toggle-label" class="panel-toggle-label">Collapse left panel</label>
|
|
973
|
+
</div>
|
|
974
|
+
|
|
975
|
+
<div class="vp-presets" id="dev-preset-list" aria-label="Device presets">
|
|
976
|
+
<button type="button" class="vp-preset-btn" data-preset="desktop">Desktop</button>
|
|
977
|
+
<button type="button" class="vp-preset-btn" data-preset="mobile">iPhone 13</button>
|
|
978
|
+
<button type="button" class="vp-preset-btn" data-preset="galaxy-s22">Galaxy S22</button>
|
|
979
|
+
<button type="button" class="vp-preset-btn" data-preset="tablet">iPad</button>
|
|
980
|
+
<button type="button" class="vp-preset-btn" data-preset="galaxy-j1">Galaxy J1</button>
|
|
981
|
+
<button type="button" class="vp-preset-btn" data-preset="iphone-7">iPhone 7</button>
|
|
982
|
+
<button type="button" class="vp-preset-btn" data-preset="responsive">Responsive</button>
|
|
983
|
+
</div>
|
|
984
|
+
<div class="ft">
|
|
985
|
+
<button type="button" class="apply-btn" id="dev-apply-btn">Apply</button>
|
|
986
|
+
</div>
|
|
987
|
+
</div>
|
|
862
988
|
</div>
|
|
863
989
|
<button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
|
|
864
990
|
<button class="tb-dk-btn" id="btn-redo" title="Redo (\u2318\u21E7Z)" style="display:none"><i class="bi bi-arrow-clockwise"></i></button>
|
|
@@ -995,7 +1121,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
995
1121
|
</div>
|
|
996
1122
|
|
|
997
1123
|
<!-- Device frame containing the editing iframe -->
|
|
998
|
-
<div id="device-frame">
|
|
1124
|
+
<div id="device-frame" class="desktop">
|
|
999
1125
|
<iframe id="iframeId" name="iframeId" allowfullscreen></iframe>
|
|
1000
1126
|
</div>
|
|
1001
1127
|
|
|
@@ -1365,6 +1491,11 @@ var isDirty = false;
|
|
|
1365
1491
|
var vvvebReady = false;
|
|
1366
1492
|
var currentMode = 'editor';
|
|
1367
1493
|
var currentDevice = 'desktop';
|
|
1494
|
+
var leftPanelCollapsed = false;
|
|
1495
|
+
var viewportPreset = 'desktop';
|
|
1496
|
+
var viewportWidth = 1440;
|
|
1497
|
+
var viewportHeight = 1024;
|
|
1498
|
+
var viewportZoom = 1;
|
|
1368
1499
|
var selectedEl = null;
|
|
1369
1500
|
/** Stable selector fingerprint for resilient selection recovery after DOM churn. */
|
|
1370
1501
|
var selectedElFingerprint = '';
|
|
@@ -1617,15 +1748,202 @@ function setMode(mode) {
|
|
|
1617
1748
|
}
|
|
1618
1749
|
|
|
1619
1750
|
// \u2500\u2500 Device 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\u2500\u2500\u2500
|
|
1620
|
-
var
|
|
1751
|
+
var DEVICE_PRESETS = {
|
|
1752
|
+
desktop: { label: 'Desktop', width: 1440, height: 1024, device: 'desktop' },
|
|
1753
|
+
tablet: { label: 'iPad', width: 768, height: 1024, device: 'tablet' },
|
|
1754
|
+
mobile: { label: 'iPhone 13', width: 390, height: 844, device: 'mobile' },
|
|
1755
|
+
'galaxy-s22': { label: 'Galaxy S22', width: 360, height: 780, device: 'mobile' },
|
|
1756
|
+
'iphone-7': { label: 'iPhone 7', width: 375, height: 667, device: 'mobile' },
|
|
1757
|
+
'galaxy-j1': { label: 'Galaxy J1', width: 360, height: 640, device: 'mobile' },
|
|
1758
|
+
responsive: { label: 'Responsive', width: 1280, height: 800, device: 'desktop' },
|
|
1759
|
+
};
|
|
1760
|
+
|
|
1761
|
+
function clampViewportNumber(v, fallback, min, max) {
|
|
1762
|
+
var n = parseInt(v, 10);
|
|
1763
|
+
if (!Number.isFinite(n)) return fallback;
|
|
1764
|
+
return Math.max(min, Math.min(max, n));
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
function getViewportFitZoom() {
|
|
1768
|
+
var panel = document.getElementById('iframe-panel');
|
|
1769
|
+
var available = panel ? Math.max(260, panel.clientWidth - 24) : viewportWidth;
|
|
1770
|
+
if (!viewportWidth || viewportWidth <= 0) return 1;
|
|
1771
|
+
return Math.min(1, available / viewportWidth);
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
function getAppliedViewportZoom() {
|
|
1775
|
+
var z = Number(viewportZoom);
|
|
1776
|
+
if (!Number.isFinite(z) || z <= 0) z = 1;
|
|
1777
|
+
z = Math.max(0.25, Math.min(2, z));
|
|
1778
|
+
return Math.min(z, getViewportFitZoom());
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
function updateViewportLabel() {
|
|
1782
|
+
var lbl = document.getElementById('dev-label');
|
|
1783
|
+
if (!lbl) return;
|
|
1784
|
+
var zoomPct = Math.round(getAppliedViewportZoom() * 100);
|
|
1785
|
+
lbl.textContent = viewportWidth + 'x' + viewportHeight + ' \xB7 ' + zoomPct + '%';
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
function syncViewportMenuControls() {
|
|
1789
|
+
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
1790
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
1791
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
1792
|
+
var zoomInp = document.getElementById('dev-zoom-level');
|
|
1793
|
+
if (presetButtons && presetButtons.length) {
|
|
1794
|
+
for (var i = 0; i < presetButtons.length; i++) {
|
|
1795
|
+
var key = presetButtons[i].getAttribute('data-preset') || '';
|
|
1796
|
+
presetButtons[i].classList.toggle('active', key === viewportPreset);
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
if (widthInp) widthInp.value = String(viewportWidth);
|
|
1800
|
+
if (heightInp) heightInp.value = String(viewportHeight);
|
|
1801
|
+
if (zoomInp) zoomInp.value = String(Math.round(getAppliedViewportZoom() * 100));
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
function applyViewportFrame() {
|
|
1805
|
+
var frame = document.getElementById('device-frame');
|
|
1806
|
+
var iframe = document.getElementById('iframeId');
|
|
1807
|
+
if (!frame) return;
|
|
1808
|
+
frame.className = currentDevice;
|
|
1809
|
+
frame.style.width = viewportWidth + 'px';
|
|
1810
|
+
frame.style.height = viewportHeight + 'px';
|
|
1811
|
+
frame.style.maxWidth = 'none';
|
|
1812
|
+
frame.style.zoom = String(getAppliedViewportZoom());
|
|
1813
|
+
if (iframe) {
|
|
1814
|
+
iframe.style.height = viewportHeight + 'px';
|
|
1815
|
+
iframe.style.minHeight = viewportHeight + 'px';
|
|
1816
|
+
}
|
|
1817
|
+
updateViewportLabel();
|
|
1818
|
+
syncViewportMenuControls();
|
|
1819
|
+
if (selectedEl && currentMode === 'editor') requestAnimationFrame(function() { positionSelectionToolbar(); });
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
function setViewportPreset(presetKey) {
|
|
1823
|
+
var preset = DEVICE_PRESETS[presetKey];
|
|
1824
|
+
if (!preset) return;
|
|
1825
|
+
viewportPreset = presetKey;
|
|
1826
|
+
viewportWidth = preset.width;
|
|
1827
|
+
viewportHeight = preset.height;
|
|
1828
|
+
currentDevice = preset.device || 'desktop';
|
|
1829
|
+
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1830
|
+
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1831
|
+
});
|
|
1832
|
+
applyViewportFrame();
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1621
1835
|
function setDevice(device) {
|
|
1836
|
+
viewportPreset = device;
|
|
1622
1837
|
currentDevice = device;
|
|
1623
|
-
var
|
|
1624
|
-
|
|
1838
|
+
var preset = DEVICE_PRESETS[device] || DEVICE_PRESETS.desktop;
|
|
1839
|
+
viewportWidth = preset.width;
|
|
1840
|
+
viewportHeight = preset.height;
|
|
1625
1841
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1626
1842
|
document.getElementById('dev-' + d).classList.toggle('active', d === device);
|
|
1627
1843
|
});
|
|
1628
|
-
|
|
1844
|
+
applyViewportFrame();
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
function setViewportCustomFromInputs() {
|
|
1848
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
1849
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
1850
|
+
var zoomInp = document.getElementById('dev-zoom-level');
|
|
1851
|
+
viewportWidth = clampViewportNumber(widthInp ? widthInp.value : '', viewportWidth, 240, 3840);
|
|
1852
|
+
viewportHeight = clampViewportNumber(heightInp ? heightInp.value : '', viewportHeight, 320, 3840);
|
|
1853
|
+
var z = clampViewportNumber(zoomInp ? zoomInp.value : '', Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
1854
|
+
viewportZoom = z / 100;
|
|
1855
|
+
viewportPreset = 'custom';
|
|
1856
|
+
currentDevice = viewportWidth <= 480 ? 'mobile' : (viewportWidth <= 1024 ? 'tablet' : 'desktop');
|
|
1857
|
+
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1858
|
+
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1859
|
+
});
|
|
1860
|
+
applyViewportFrame();
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
function closeViewportMenu() {
|
|
1864
|
+
var menu = document.getElementById('dev-more-menu');
|
|
1865
|
+
if (!menu) return;
|
|
1866
|
+
menu.classList.remove('open');
|
|
1867
|
+
menu.setAttribute('aria-hidden', 'true');
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
function toggleViewportMenu() {
|
|
1871
|
+
var menu = document.getElementById('dev-more-menu');
|
|
1872
|
+
if (!menu) return;
|
|
1873
|
+
var shouldOpen = !menu.classList.contains('open');
|
|
1874
|
+
menu.classList.toggle('open', shouldOpen);
|
|
1875
|
+
menu.setAttribute('aria-hidden', shouldOpen ? 'false' : 'true');
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
function bindViewportControls() {
|
|
1879
|
+
var btn = document.getElementById('dev-more-btn');
|
|
1880
|
+
var menu = document.getElementById('dev-more-menu');
|
|
1881
|
+
var leftPanelToggleLabel = document.getElementById('left-panel-toggle-label');
|
|
1882
|
+
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
1883
|
+
var applyBtn = document.getElementById('dev-apply-btn');
|
|
1884
|
+
var zoomInp = document.getElementById('dev-zoom-level');
|
|
1885
|
+
var viewportBtn = document.querySelector('.tb-viewport');
|
|
1886
|
+
function updateLeftPanelToggleLabel() {
|
|
1887
|
+
if (!leftPanelToggleLabel) return;
|
|
1888
|
+
leftPanelToggleLabel.textContent = leftPanelCollapsed ? 'Expand left panel' : 'Collapse left panel';
|
|
1889
|
+
}
|
|
1890
|
+
function setLeftPanelCollapsed(collapsed) {
|
|
1891
|
+
var panel = document.getElementById('left-panel');
|
|
1892
|
+
leftPanelCollapsed = !!collapsed;
|
|
1893
|
+
if (panel) panel.style.display = leftPanelCollapsed ? 'none' : '';
|
|
1894
|
+
updateLeftPanelToggleLabel();
|
|
1895
|
+
applyViewportFrame();
|
|
1896
|
+
}
|
|
1897
|
+
if (leftPanelToggleLabel) {
|
|
1898
|
+
leftPanelToggleLabel.addEventListener('click', function(e) {
|
|
1899
|
+
e.preventDefault();
|
|
1900
|
+
e.stopPropagation();
|
|
1901
|
+
setLeftPanelCollapsed(!leftPanelCollapsed);
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
if (btn) btn.addEventListener('click', function(e) {
|
|
1905
|
+
e.preventDefault();
|
|
1906
|
+
e.stopPropagation();
|
|
1907
|
+
toggleViewportMenu();
|
|
1908
|
+
});
|
|
1909
|
+
if (viewportBtn) viewportBtn.addEventListener('click', function(e) {
|
|
1910
|
+
e.preventDefault();
|
|
1911
|
+
e.stopPropagation();
|
|
1912
|
+
toggleViewportMenu();
|
|
1913
|
+
});
|
|
1914
|
+
if (applyBtn) applyBtn.addEventListener('click', function(e) {
|
|
1915
|
+
e.preventDefault();
|
|
1916
|
+
setViewportCustomFromInputs();
|
|
1917
|
+
closeViewportMenu();
|
|
1918
|
+
});
|
|
1919
|
+
if (zoomInp) {
|
|
1920
|
+
zoomInp.addEventListener('change', function() {
|
|
1921
|
+
var z = clampViewportNumber(zoomInp.value, Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
1922
|
+
viewportZoom = z / 100;
|
|
1923
|
+
applyViewportFrame();
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
if (presetButtons && presetButtons.length) {
|
|
1927
|
+
for (var i = 0; i < presetButtons.length; i++) {
|
|
1928
|
+
presetButtons[i].addEventListener('click', function(e) {
|
|
1929
|
+
e.preventDefault();
|
|
1930
|
+
var key = this.getAttribute('data-preset');
|
|
1931
|
+
if (!key) return;
|
|
1932
|
+
setViewportPreset(key);
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
document.addEventListener('click', function(e) {
|
|
1937
|
+
if (!menu || !menu.classList.contains('open')) return;
|
|
1938
|
+
if (menu.contains(e.target) || (btn && btn.contains(e.target)) || (viewportBtn && viewportBtn.contains(e.target))) return;
|
|
1939
|
+
closeViewportMenu();
|
|
1940
|
+
});
|
|
1941
|
+
document.addEventListener('keydown', function(e) {
|
|
1942
|
+
if (e.key === 'Escape') closeViewportMenu();
|
|
1943
|
+
});
|
|
1944
|
+
window.addEventListener('resize', function() { applyViewportFrame(); });
|
|
1945
|
+
updateLeftPanelToggleLabel();
|
|
1946
|
+
applyViewportFrame();
|
|
1629
1947
|
}
|
|
1630
1948
|
|
|
1631
1949
|
// \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
|
|
@@ -1787,9 +2105,60 @@ function getOriginalValue(inputId, el) {
|
|
|
1787
2105
|
}
|
|
1788
2106
|
}
|
|
1789
2107
|
|
|
2108
|
+
var PX_DEFAULT_INPUT_IDS = {
|
|
2109
|
+
'pp-mt': true, 'pp-mr': true, 'pp-mb': true, 'pp-ml': true,
|
|
2110
|
+
'pp-pt': true, 'pp-pr': true, 'pp-pb': true, 'pp-pl': true,
|
|
2111
|
+
};
|
|
2112
|
+
|
|
2113
|
+
var PX_DEFAULT_CSS_PROPS = {
|
|
2114
|
+
'margin-top': true, 'margin-right': true, 'margin-bottom': true, 'margin-left': true,
|
|
2115
|
+
'padding-top': true, 'padding-right': true, 'padding-bottom': true, 'padding-left': true,
|
|
2116
|
+
};
|
|
2117
|
+
|
|
2118
|
+
function normalizeCssValueForProperty(prop, value) {
|
|
2119
|
+
var p = prop == null ? '' : String(prop).trim();
|
|
2120
|
+
var pKebab = p
|
|
2121
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
2122
|
+
.replace(/_/g, '-')
|
|
2123
|
+
.replace(/!important/gi, '')
|
|
2124
|
+
.replace(/[^a-zA-Z-]/g, '')
|
|
2125
|
+
.toLowerCase();
|
|
2126
|
+
var raw = value == null ? '' : String(value).trim();
|
|
2127
|
+
var rawClean = raw.replace(/[\u200B\u200C\u200D\uFEFF]/g, '').trim();
|
|
2128
|
+
var numericCandidate = rawClean.replace(/[, ]+/g, '');
|
|
2129
|
+
var isSpacingProp = /^(?:margin|padding)(?:-(?:top|right|bottom|left))?$/.test(pKebab);
|
|
2130
|
+
if (!pKebab || !rawClean) return rawClean;
|
|
2131
|
+
var numericValue = Number(numericCandidate);
|
|
2132
|
+
var shouldAddPx =
|
|
2133
|
+
isSpacingProp &&
|
|
2134
|
+
numericCandidate !== '' &&
|
|
2135
|
+
Number.isFinite(numericValue) &&
|
|
2136
|
+
/^[-+]?(?:[0-9]+(?:[.][0-9]+)?|[.][0-9]+)$/.test(numericCandidate);
|
|
2137
|
+
var out = shouldAddPx ? numericCandidate + 'px' : rawClean;
|
|
2138
|
+
return out;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
function normalizeChainSetRowUnits(row) {
|
|
2142
|
+
if (!row) return row;
|
|
2143
|
+
if (normalizeChangesetType(row) === 'style') {
|
|
2144
|
+
row.value = normalizeCssValueForProperty(row.property || row.cssProp, row.value);
|
|
2145
|
+
}
|
|
2146
|
+
return row;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
function normalizeLoggedValue(inputId, value) {
|
|
2150
|
+
var raw = value == null ? '' : String(value).trim();
|
|
2151
|
+
if (!raw) return raw;
|
|
2152
|
+
if (PX_DEFAULT_INPUT_IDS[inputId] && /^-?d+(?:.d+)?$/.test(raw)) {
|
|
2153
|
+
return raw + 'px';
|
|
2154
|
+
}
|
|
2155
|
+
return raw;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
1790
2158
|
function logChange(selector, inputId, value, targetEl, originalValue) {
|
|
1791
2159
|
var meta = PROP_META[inputId];
|
|
1792
2160
|
if (!meta) return;
|
|
2161
|
+
value = normalizeLoggedValue(inputId, value);
|
|
1793
2162
|
var key = selector + '||' + inputId;
|
|
1794
2163
|
// Skip trivially empty / reset values \u2014 remove from log if present
|
|
1795
2164
|
if (value === '' || value === 'none' || value === 'auto' || value === 'normal') {
|
|
@@ -2488,9 +2857,24 @@ function pickActiveVariationIdForLoad(data, variationsArr, prevMemoryId, allowPr
|
|
|
2488
2857
|
return fallback;
|
|
2489
2858
|
}
|
|
2490
2859
|
|
|
2860
|
+
function updateExperimentNameLabel(data) {
|
|
2861
|
+
var el = document.getElementById('tb-exp-name');
|
|
2862
|
+
if (!el) return;
|
|
2863
|
+
var name = '';
|
|
2864
|
+
try {
|
|
2865
|
+
name = data && data.name != null ? String(data.name).trim() : '';
|
|
2866
|
+
} catch(_) {
|
|
2867
|
+
name = '';
|
|
2868
|
+
}
|
|
2869
|
+
if (!name) name = 'Visual Editor';
|
|
2870
|
+
el.textContent = name;
|
|
2871
|
+
el.title = name;
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2491
2874
|
// \u2500\u2500 Experiment loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
2492
2875
|
function handleLoadExperiment(data) {
|
|
2493
2876
|
clearPendingGranularChangesets();
|
|
2877
|
+
updateExperimentNameLabel(data);
|
|
2494
2878
|
var prevKey = experimentData
|
|
2495
2879
|
? String(experimentData.experimentId || '') + '|' + String(experimentData.pageUrl || '')
|
|
2496
2880
|
: '';
|
|
@@ -3132,7 +3516,13 @@ function removeSessionStructuralRowByTimestamp(varId, ts) {
|
|
|
3132
3516
|
function stateChangeToChainSet(c) {
|
|
3133
3517
|
if (!c || !c.selector) return null;
|
|
3134
3518
|
if (c.cssProp) {
|
|
3135
|
-
return {
|
|
3519
|
+
return {
|
|
3520
|
+
selector: c.selector,
|
|
3521
|
+
type: 'style',
|
|
3522
|
+
property: c.cssProp,
|
|
3523
|
+
value: normalizeCssValueForProperty(c.cssProp, c.value),
|
|
3524
|
+
vveTs: c.vveTs || nextHistoryTimestamp()
|
|
3525
|
+
};
|
|
3136
3526
|
}
|
|
3137
3527
|
switch (c.inputId) {
|
|
3138
3528
|
case 'pp-text':
|
|
@@ -3304,7 +3694,7 @@ function buildPersistentStyleRulesForActiveVariation() {
|
|
|
3304
3694
|
if (value == null || value === '') return;
|
|
3305
3695
|
var sel = sanitizeSelectorForMatch(String(selector)) || String(selector);
|
|
3306
3696
|
var pr = String(prop).trim();
|
|
3307
|
-
var val =
|
|
3697
|
+
var val = normalizeCssValueForProperty(pr, value);
|
|
3308
3698
|
if (!sel || !pr || !val) return;
|
|
3309
3699
|
var k = sel + '__vve_sep__' + pr;
|
|
3310
3700
|
if (!map[k]) order.push(k);
|
|
@@ -3342,7 +3732,8 @@ function buildPersistentStyleRulesForActiveVariation() {
|
|
|
3342
3732
|
var lines = [];
|
|
3343
3733
|
for (var oi = 0; oi < order.length; oi++) {
|
|
3344
3734
|
var row = map[order[oi]];
|
|
3345
|
-
|
|
3735
|
+
var outVal = normalizeCssValueForProperty(row.property, row.value);
|
|
3736
|
+
lines.push(row.selector + ' { ' + row.property + ': ' + outVal + ' !important; }');
|
|
3346
3737
|
}
|
|
3347
3738
|
return lines.join('\\n');
|
|
3348
3739
|
}
|
|
@@ -3493,7 +3884,9 @@ function buildPersistedChainSetsForVariation(v) {
|
|
|
3493
3884
|
var row = stateChangeToChainSet(sourceStateChanges[si]);
|
|
3494
3885
|
if (row) overlay.push(row);
|
|
3495
3886
|
}
|
|
3496
|
-
|
|
3887
|
+
var merged = mergeGranularChainSets(mergeGranularChainSets(base, sessionExtra), overlay);
|
|
3888
|
+
for (var mi = 0; mi < merged.length; mi++) normalizeChainSetRowUnits(merged[mi]);
|
|
3889
|
+
return merged;
|
|
3497
3890
|
}
|
|
3498
3891
|
|
|
3499
3892
|
/**
|
|
@@ -5395,6 +5788,7 @@ function registerCROSections() {
|
|
|
5395
5788
|
|
|
5396
5789
|
window.addEventListener('load', function() {
|
|
5397
5790
|
registerCROSections();
|
|
5791
|
+
bindViewportControls();
|
|
5398
5792
|
switchSectionComponentsTab(currentSectionComponentsTab);
|
|
5399
5793
|
renderElementsTree(document.getElementById('comp-search').value);
|
|
5400
5794
|
vvvebReady = true;
|
|
@@ -6102,8 +6496,32 @@ ${runtimePreflightScript}
|
|
|
6102
6496
|
var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
6103
6497
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
6104
6498
|
var EMPTY_JSON_DATA="data:application/json;charset=utf-8,%7B%7D";
|
|
6105
|
-
|
|
6106
|
-
|
|
6499
|
+
var _proxyCtx=(function(){try{return new URL(window.location.href);}catch(_){return null;}})();
|
|
6500
|
+
var PROXY_ROOT="/api/conversion-proxy";
|
|
6501
|
+
var PROXY_PASSWORD=_proxyCtx?_proxyCtx.searchParams.get("password")||"":"";
|
|
6502
|
+
var PROXY_BASE_URL=_proxyCtx?_proxyCtx.searchParams.get("conversionProxyBaseUrl")||"":"";
|
|
6503
|
+
var PROXY_TRACKING_MARKERS=_proxyCtx?_proxyCtx.searchParams.get("trackingMarkers")||"":"";
|
|
6504
|
+
var PROXY_STRICT_FREEZE=_proxyCtx?_proxyCtx.searchParams.get("strictObserverFreeze")||"":"";
|
|
6505
|
+
var PROXY_UPSTREAM_MODE=_proxyCtx?_proxyCtx.searchParams.get("proxy")||"":"";
|
|
6506
|
+
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
6507
|
+
function toProxyNetworkUrl(raw){
|
|
6508
|
+
if(isSkippable(raw))return raw;
|
|
6509
|
+
try{
|
|
6510
|
+
var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;
|
|
6511
|
+
var abs=new URL(raw,base);
|
|
6512
|
+
if(abs.origin!==TARGET_ORIGIN)return raw;
|
|
6513
|
+
var prox=new URL(PROXY_ROOT,window.location.origin);
|
|
6514
|
+
prox.searchParams.set("password",PROXY_PASSWORD||"");
|
|
6515
|
+
prox.searchParams.set("url",abs.toString());
|
|
6516
|
+
if(PROXY_BASE_URL)prox.searchParams.set("conversionProxyBaseUrl",PROXY_BASE_URL);
|
|
6517
|
+
if(PROXY_TRACKING_MARKERS)prox.searchParams.set("trackingMarkers",PROXY_TRACKING_MARKERS);
|
|
6518
|
+
if(PROXY_STRICT_FREEZE)prox.searchParams.set("strictObserverFreeze",PROXY_STRICT_FREEZE);
|
|
6519
|
+
if(PROXY_UPSTREAM_MODE)prox.searchParams.set("proxy",PROXY_UPSTREAM_MODE);
|
|
6520
|
+
return prox.toString();
|
|
6521
|
+
}catch(_){
|
|
6522
|
+
return raw;
|
|
6523
|
+
}
|
|
6524
|
+
}
|
|
6107
6525
|
function resolveUrl(s){try{return new URL(s,window.location.href);}catch(_){return null;}}
|
|
6108
6526
|
function isNestedMalformedProxy(u){if(!u)return false;var p=u.pathname||"";if(p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0)return false;return p.indexOf("api/conversion-proxy")!==-1;}
|
|
6109
6527
|
function skipNestedProxyNetwork(s){var u=typeof s==="string"?resolveUrl(s):null;return u&&isNestedMalformedProxy(u);}
|
|
@@ -6116,9 +6534,9 @@ if(window.fetch){
|
|
|
6116
6534
|
var rawUrl=typeof input==="string"?input:(input&&input.url?String(input.url):"");
|
|
6117
6535
|
if(rawUrl&&skipNestedProxyNetwork(rawUrl))return emptyJsonFetchResponse();
|
|
6118
6536
|
if(typeof input==="string"){
|
|
6119
|
-
input=
|
|
6537
|
+
input=toProxyNetworkUrl(input);
|
|
6120
6538
|
}else if(input&&input.url){
|
|
6121
|
-
var next=
|
|
6539
|
+
var next=toProxyNetworkUrl(input.url);
|
|
6122
6540
|
if(next!==input.url){input=new Request(next,input);}
|
|
6123
6541
|
}
|
|
6124
6542
|
afterUrl=typeof input==="string"?input:(input&&input.url?String(input.url):"");
|
|
@@ -6152,7 +6570,7 @@ if(window.fetch){
|
|
|
6152
6570
|
});
|
|
6153
6571
|
};
|
|
6154
6572
|
}
|
|
6155
|
-
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]=
|
|
6573
|
+
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]=toProxyNetworkUrl(url);}}catch(_){}return _open.apply(this,arguments);};}
|
|
6156
6574
|
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);};}
|
|
6157
6575
|
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;}}
|
|
6158
6576
|
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);
|