@accelerated-agency/visual-editor 0.5.9 → 0.6.1
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 +366 -50
- package/dist/vite.js +366 -50
- package/package.json +1 -1
package/dist/vite.cjs
CHANGED
|
@@ -1039,24 +1039,16 @@ button.var-tab.active{
|
|
|
1039
1039
|
.lp-body #tab-dom-tree, .lp-body #tab-elements{
|
|
1040
1040
|
padding-top:4px;
|
|
1041
1041
|
}
|
|
1042
|
-
.lp-body #
|
|
1043
|
-
|
|
1044
|
-
font-style: normal;
|
|
1045
|
-
font-weight: 500;
|
|
1046
|
-
line-height: 14px;
|
|
1047
|
-
letter-spacing: -0.1px;
|
|
1048
|
-
}
|
|
1049
|
-
.lp-body #tab-elements #elements-root > .dt-row{
|
|
1050
|
-
padding-left: 16px!important;
|
|
1051
|
-
}
|
|
1052
|
-
.lp-body #dom-tree-root .dt-lbl{
|
|
1042
|
+
.lp-body #dom-tree-root .dt-lbl,
|
|
1043
|
+
.lp-body #elements-root .dt-lbl{
|
|
1053
1044
|
color: var(--content-subtle, #737373);
|
|
1054
1045
|
font-style: normal;
|
|
1055
1046
|
font-weight: 400;
|
|
1056
|
-
line-height: var(--font-leading-3, 12px);
|
|
1047
|
+
line-height: var(--font-leading-3, 12px);
|
|
1057
1048
|
letter-spacing: -0.1px;
|
|
1058
1049
|
}
|
|
1059
|
-
.lp-body #dom-tree-root .dt-lbl .dt-tag
|
|
1050
|
+
.lp-body #dom-tree-root .dt-lbl .dt-tag,
|
|
1051
|
+
.lp-body #elements-root .dt-lbl .dt-tag{
|
|
1060
1052
|
color: var(--content-strong, #171717);
|
|
1061
1053
|
font-family: "JetBrains Mono";
|
|
1062
1054
|
font-size: 12px;
|
|
@@ -1070,7 +1062,6 @@ padding:3px 6px;
|
|
|
1070
1062
|
display:inline-block;
|
|
1071
1063
|
margin-right:4px;
|
|
1072
1064
|
}
|
|
1073
|
-
.lp-body #tab-elements .dt-row .dt-chev.dt-spacer{display:none;}
|
|
1074
1065
|
.lp-body #tab-dom-tree .dt-row .dt-ico{display:none;}
|
|
1075
1066
|
.lp-body, .section-components-body{flex:1;overflow-y:auto}
|
|
1076
1067
|
.lp-body::-webkit-scrollbar, .section-components-body::-webkit-scrollbar{width:3px}
|
|
@@ -3159,6 +3150,7 @@ var PROP_META = {
|
|
|
3159
3150
|
'pp-value': {label:'Value', cssProp:null},
|
|
3160
3151
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
3161
3152
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
3153
|
+
'pp-select-options': {label:'Options', cssProp:null},
|
|
3162
3154
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
3163
3155
|
'pp-tab-css': {label:'Tablet CSS', cssProp:null},
|
|
3164
3156
|
};
|
|
@@ -3175,6 +3167,7 @@ function getOriginalValue(inputId, el) {
|
|
|
3175
3167
|
switch (inputId) {
|
|
3176
3168
|
case 'pp-text': return el.innerText || '';
|
|
3177
3169
|
case 'pp-html': return el.innerHTML || '';
|
|
3170
|
+
case 'pp-select-options': return getSelectOptionsText(el);
|
|
3178
3171
|
case 'pp-cls': return el.className || '';
|
|
3179
3172
|
case 'pp-id': return el.id || '';
|
|
3180
3173
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
@@ -3324,6 +3317,7 @@ function revertChangeOnDom(change) {
|
|
|
3324
3317
|
switch (change.inputId) {
|
|
3325
3318
|
case 'pp-text': el.innerText = orig; break;
|
|
3326
3319
|
case 'pp-html': el.innerHTML = orig; break;
|
|
3320
|
+
case 'pp-select-options': applySelectOptionsFromText(el, orig); break;
|
|
3327
3321
|
case 'pp-cls': el.className = orig; break;
|
|
3328
3322
|
case 'pp-id': el.id = orig; break;
|
|
3329
3323
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
@@ -4982,6 +4976,8 @@ function stateChangeToChainSet(c) {
|
|
|
4982
4976
|
return { selector: c.selector, type: 'content', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4983
4977
|
case 'pp-html':
|
|
4984
4978
|
return { selector: c.selector, type: 'content', html: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4979
|
+
case 'pp-select-options':
|
|
4980
|
+
return { selector: c.selector, type: 'content', html: selectOptionsTextToHtml(c.value), vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4985
4981
|
case 'pp-cls':
|
|
4986
4982
|
return { selector: c.selector, type: 'attribute', attribute: 'class', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4987
4983
|
case 'pp-id':
|
|
@@ -5595,6 +5591,10 @@ function setTreeHoverHighlight(el) {
|
|
|
5595
5591
|
}
|
|
5596
5592
|
|
|
5597
5593
|
function isTreeHoverOnlyClassMutation(mutation) {
|
|
5594
|
+
return isEditorChromeOnlyClassMutation(mutation);
|
|
5595
|
+
}
|
|
5596
|
+
|
|
5597
|
+
function isEditorChromeOnlyClassMutation(mutation) {
|
|
5598
5598
|
if (!mutation || mutation.type !== 'attributes' || mutation.attributeName !== 'class') return false;
|
|
5599
5599
|
var oldClass = String(mutation.oldValue || '');
|
|
5600
5600
|
var target = mutation.target;
|
|
@@ -5602,7 +5602,12 @@ function isTreeHoverOnlyClassMutation(mutation) {
|
|
|
5602
5602
|
try {
|
|
5603
5603
|
nextClass = target && typeof target.className === 'string' ? target.className : '';
|
|
5604
5604
|
} catch(_) {}
|
|
5605
|
-
|
|
5605
|
+
var combined = oldClass + ' ' + nextClass;
|
|
5606
|
+
return (
|
|
5607
|
+
combined.indexOf('vve-tree-hover') >= 0 ||
|
|
5608
|
+
combined.indexOf('vve-selected') >= 0 ||
|
|
5609
|
+
combined.indexOf('vve-dragging') >= 0
|
|
5610
|
+
);
|
|
5606
5611
|
}
|
|
5607
5612
|
|
|
5608
5613
|
function setDragHandleActive(on) {
|
|
@@ -5652,7 +5657,13 @@ function positionSelectionToolbar() {
|
|
|
5652
5657
|
if (!bar || !liveSelected || !iframe || !iframe.contentWindow || !panel) return;
|
|
5653
5658
|
if (selectedEl !== liveSelected) {
|
|
5654
5659
|
selectedEl = liveSelected;
|
|
5655
|
-
|
|
5660
|
+
if (!document.activeElement || (
|
|
5661
|
+
document.activeElement.id !== 'pp-html' &&
|
|
5662
|
+
document.activeElement.id !== 'pp-text' &&
|
|
5663
|
+
document.activeElement.id !== 'pp-select-options'
|
|
5664
|
+
)) {
|
|
5665
|
+
renderRightPanel(liveSelected);
|
|
5666
|
+
}
|
|
5656
5667
|
syncDomTreeSelection();
|
|
5657
5668
|
}
|
|
5658
5669
|
var elR = getIframeElementVisualRect(selectedEl);
|
|
@@ -6186,31 +6197,156 @@ function renderElementsTree(filterRaw) {
|
|
|
6186
6197
|
return;
|
|
6187
6198
|
}
|
|
6188
6199
|
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6200
|
+
function nodeIcon(tag) {
|
|
6201
|
+
tag = (tag || '').toLowerCase();
|
|
6202
|
+
|
|
6203
|
+
// Headings
|
|
6204
|
+
if (/^h[1-6]$/.test(tag)) return 'bi bi-type-h1';
|
|
6205
|
+
|
|
6206
|
+
// Document & metadata
|
|
6207
|
+
if (tag === 'html') return 'bi bi-filetype-html';
|
|
6208
|
+
if (tag === 'head') return 'bi bi-file-earmark-code';
|
|
6209
|
+
if (tag === 'body') return 'bi bi-file-earmark-richtext';
|
|
6210
|
+
if (tag === 'title') return 'bi bi-card-heading';
|
|
6211
|
+
if (tag === 'meta') return 'bi bi-info-circle';
|
|
6212
|
+
if (tag === 'link') return 'bi bi-link';
|
|
6213
|
+
if (tag === 'style') return 'bi bi-filetype-css';
|
|
6214
|
+
if (tag === 'script') return 'bi bi-filetype-js';
|
|
6215
|
+
if (tag === 'noscript') return 'bi bi-slash-circle';
|
|
6216
|
+
if (tag === 'base') return 'bi bi-house-gear';
|
|
6217
|
+
|
|
6218
|
+
// Sectioning & layout
|
|
6219
|
+
if (tag === 'section' || tag === 'main' || tag === 'article' ||
|
|
6220
|
+
tag === 'header' || tag === 'footer' || tag === 'nav' || tag === 'aside')
|
|
6221
|
+
return 'bi bi-layout-three-columns';
|
|
6222
|
+
if (tag === 'div') return 'bi bi-square';
|
|
6223
|
+
if (tag === 'address') return 'bi bi-geo-alt';
|
|
6224
|
+
|
|
6225
|
+
// Text content
|
|
6226
|
+
if (tag === 'p' || tag === 'span') return 'bi bi-text-left';
|
|
6227
|
+
if (tag === 'blockquote' || tag === 'q') return 'bi bi-blockquote-left';
|
|
6228
|
+
if (tag === 'pre') return 'bi bi-code-square';
|
|
6229
|
+
if (tag === 'code') return 'bi bi-code-slash';
|
|
6230
|
+
if (tag === 'kbd') return 'bi bi-keyboard';
|
|
6231
|
+
if (tag === 'samp') return 'bi bi-terminal';
|
|
6232
|
+
if (tag === 'var') return 'bi bi-braces';
|
|
6233
|
+
if (tag === 'cite') return 'bi bi-quote';
|
|
6234
|
+
if (tag === 'abbr') return 'bi bi-fonts';
|
|
6235
|
+
if (tag === 'time') return 'bi bi-clock';
|
|
6236
|
+
if (tag === 'mark') return 'bi bi-highlighter';
|
|
6237
|
+
if (tag === 'small') return 'bi bi-type';
|
|
6238
|
+
if (tag === 'sub') return 'bi bi-subscript';
|
|
6239
|
+
if (tag === 'sup') return 'bi bi-superscript';
|
|
6240
|
+
if (tag === 'br') return 'bi bi-arrow-return-left';
|
|
6241
|
+
if (tag === 'wbr') return 'bi bi-distribute-horizontal';
|
|
6242
|
+
|
|
6243
|
+
// Inline formatting
|
|
6244
|
+
if (tag === 'strong' || tag === 'b') return 'bi bi-type-bold';
|
|
6245
|
+
if (tag === 'em' || tag === 'i') return 'bi bi-type-italic';
|
|
6246
|
+
if (tag === 'u' || tag === 'ins') return 'bi bi-type-underline';
|
|
6247
|
+
if (tag === 's' || tag === 'del' || tag === 'strike') return 'bi bi-type-strikethrough';
|
|
6248
|
+
|
|
6249
|
+
// Lists
|
|
6250
|
+
if (tag === 'ul') return 'bi bi-list-ul';
|
|
6251
|
+
if (tag === 'ol') return 'bi bi-list-ol';
|
|
6252
|
+
if (tag === 'li') return 'bi bi-dot';
|
|
6253
|
+
if (tag === 'dl') return 'bi bi-card-list';
|
|
6254
|
+
if (tag === 'dt') return 'bi bi-tag';
|
|
6255
|
+
if (tag === 'dd') return 'bi bi-text-indent-left';
|
|
6256
|
+
|
|
6257
|
+
// Links & navigation
|
|
6258
|
+
if (tag === 'a') return 'bi bi-link-45deg';
|
|
6259
|
+
|
|
6260
|
+
// Media
|
|
6261
|
+
if (tag === 'img') return 'bi bi-image';
|
|
6262
|
+
if (tag === 'picture') return 'bi bi-images';
|
|
6263
|
+
if (tag === 'figure') return 'bi bi-card-image';
|
|
6264
|
+
if (tag === 'figcaption') return 'bi bi-card-text';
|
|
6265
|
+
if (tag === 'video') return 'bi bi-camera-video';
|
|
6266
|
+
if (tag === 'audio') return 'bi bi-music-note-beamed';
|
|
6267
|
+
if (tag === 'source') return 'bi bi-cloud-arrow-down';
|
|
6268
|
+
if (tag === 'track') return 'bi bi-badge-cc';
|
|
6269
|
+
if (tag === 'iframe') return 'bi bi-window';
|
|
6270
|
+
if (tag === 'embed' || tag === 'object') return 'bi bi-box-arrow-in-down';
|
|
6271
|
+
if (tag === 'param') return 'bi bi-sliders';
|
|
6272
|
+
if (tag === 'canvas') return 'bi bi-easel';
|
|
6273
|
+
if (tag === 'map') return 'bi bi-map';
|
|
6274
|
+
if (tag === 'area') return 'bi bi-bounding-box';
|
|
6275
|
+
|
|
6276
|
+
// Vector / math
|
|
6277
|
+
if (tag === 'svg') return 'bi bi-bezier2';
|
|
6278
|
+
if (tag === 'path') return 'bi bi-bezier';
|
|
6279
|
+
if (tag === 'circle') return 'bi bi-circle';
|
|
6280
|
+
if (tag === 'rect') return 'bi bi-square';
|
|
6281
|
+
if (tag === 'line') return 'bi bi-slash-lg';
|
|
6282
|
+
if (tag === 'polygon') return 'bi bi-pentagon';
|
|
6283
|
+
if (tag === 'polyline') return 'bi bi-share';
|
|
6284
|
+
if (tag === 'ellipse') return 'bi bi-circle-half';
|
|
6285
|
+
if (tag === 'g') return 'bi bi-collection';
|
|
6286
|
+
if (tag === 'use') return 'bi bi-arrow-repeat';
|
|
6287
|
+
if (tag === 'defs') return 'bi bi-bookmark';
|
|
6288
|
+
if (tag === 'symbol') return 'bi bi-star';
|
|
6289
|
+
if (tag === 'text') return 'bi bi-fonts';
|
|
6290
|
+
if (tag === 'math') return 'bi bi-calculator';
|
|
6291
|
+
|
|
6292
|
+
// Forms
|
|
6293
|
+
if (tag === 'form') return 'bi bi-file-earmark-check';
|
|
6294
|
+
if (tag === 'fieldset') return 'bi bi-bounding-box-circles';
|
|
6295
|
+
if (tag === 'legend') return 'bi bi-tag-fill';
|
|
6296
|
+
if (tag === 'label') return 'bi bi-tag';
|
|
6297
|
+
if (tag === 'input') return 'bi bi-input-cursor-text';
|
|
6298
|
+
if (tag === 'button') return 'bi bi-ui-radios';
|
|
6299
|
+
if (tag === 'select') return 'bi bi-menu-button';
|
|
6300
|
+
if (tag === 'option') return 'bi bi-check2-square';
|
|
6301
|
+
if (tag === 'optgroup') return 'bi bi-list-nested';
|
|
6302
|
+
if (tag === 'textarea') return 'bi bi-textarea-resize';
|
|
6303
|
+
if (tag === 'datalist') return 'bi bi-list-columns';
|
|
6304
|
+
if (tag === 'output') return 'bi bi-box-arrow-right';
|
|
6305
|
+
if (tag === 'progress') return 'bi bi-bar-chart-line';
|
|
6306
|
+
if (tag === 'meter') return 'bi bi-speedometer2';
|
|
6307
|
+
|
|
6308
|
+
// Tables
|
|
6309
|
+
if (tag === 'table') return 'bi bi-table';
|
|
6310
|
+
if (tag === 'caption') return 'bi bi-card-heading';
|
|
6311
|
+
if (tag === 'thead') return 'bi bi-layout-text-window';
|
|
6312
|
+
if (tag === 'tbody') return 'bi bi-layout-text-sidebar';
|
|
6313
|
+
if (tag === 'tfoot') return 'bi bi-layout-text-window-reverse';
|
|
6314
|
+
if (tag === 'tr') return 'bi bi-grip-horizontal';
|
|
6315
|
+
if (tag === 'th') return 'bi bi-grid-3x3-gap-fill';
|
|
6316
|
+
if (tag === 'td') return 'bi bi-grid-3x3-gap';
|
|
6317
|
+
if (tag === 'col') return 'bi bi-layout-three-columns';
|
|
6318
|
+
if (tag === 'colgroup') return 'bi bi-columns-gap';
|
|
6319
|
+
|
|
6320
|
+
// Interactive / disclosure
|
|
6321
|
+
if (tag === 'details') return 'bi bi-caret-down-square';
|
|
6322
|
+
if (tag === 'summary') return 'bi bi-card-text';
|
|
6323
|
+
if (tag === 'dialog') return 'bi bi-chat-square-text';
|
|
6324
|
+
if (tag === 'menu') return 'bi bi-list';
|
|
6325
|
+
|
|
6326
|
+
// Web components / templating
|
|
6327
|
+
if (tag === 'template') return 'bi bi-file-earmark-code';
|
|
6328
|
+
if (tag === 'slot') return 'bi bi-box-seam';
|
|
6329
|
+
|
|
6330
|
+
// Ruby annotation
|
|
6331
|
+
if (tag === 'ruby' || tag === 'rt' || tag === 'rp' || tag === 'rb')
|
|
6332
|
+
return 'bi bi-translate';
|
|
6333
|
+
if (tag === 'bdi' || tag === 'bdo') return 'bi bi-arrow-left-right';
|
|
6334
|
+
|
|
6335
|
+
// Misc
|
|
6336
|
+
if (tag === 'hr') return 'bi bi-hr';
|
|
6337
|
+
if (tag === '#text' || tag === 'text-node') return 'bi bi-cursor-text';
|
|
6338
|
+
if (tag === '#comment') return 'bi bi-chat-left-text';
|
|
6339
|
+
|
|
6340
|
+
return 'bi bi-square';
|
|
6341
|
+
}
|
|
6202
6342
|
|
|
6203
|
-
function labelFor(el) {
|
|
6204
|
-
var tag = (el.tagName || '').toLowerCase();
|
|
6205
|
-
return tag.toUpperCase();
|
|
6206
|
-
}
|
|
6207
6343
|
|
|
6208
6344
|
var nodes = collectEditorInsertedElements(doc);
|
|
6209
6345
|
|
|
6210
6346
|
root.innerHTML = '';
|
|
6211
6347
|
for (var i = 0; i < nodes.length; i++) {
|
|
6212
6348
|
var el = nodes[i];
|
|
6213
|
-
var lblText =
|
|
6349
|
+
var lblText = domTreeLabelFor(el);
|
|
6214
6350
|
if (filterText && lblText.toLowerCase().indexOf(filterText) < 0) continue;
|
|
6215
6351
|
|
|
6216
6352
|
var row = document.createElement('div');
|
|
@@ -6229,7 +6365,7 @@ function renderElementsTree(filterRaw) {
|
|
|
6229
6365
|
|
|
6230
6366
|
var lbl = document.createElement('div');
|
|
6231
6367
|
lbl.className = 'dt-lbl';
|
|
6232
|
-
lbl
|
|
6368
|
+
setDomTreeLabelContent(lbl, el);
|
|
6233
6369
|
lbl.title = buildSelector(el);
|
|
6234
6370
|
|
|
6235
6371
|
row.appendChild(spacer);
|
|
@@ -6254,11 +6390,35 @@ function renderElementsTree(filterRaw) {
|
|
|
6254
6390
|
};
|
|
6255
6391
|
}
|
|
6256
6392
|
|
|
6393
|
+
function domTreeLabelClassExcluded(className) {
|
|
6394
|
+
var c = String(className || '');
|
|
6395
|
+
return !c || c === 'vve-selected' || c === 'vve-tree-hover' || c.indexOf('vve-') === 0;
|
|
6396
|
+
}
|
|
6397
|
+
|
|
6398
|
+
function domTreeLabelClassString(el) {
|
|
6399
|
+
if (!el) return '';
|
|
6400
|
+
try {
|
|
6401
|
+
if (el.classList && el.classList.length) {
|
|
6402
|
+
var out = [];
|
|
6403
|
+
for (var i = 0; i < el.classList.length; i++) {
|
|
6404
|
+
var cls = el.classList[i];
|
|
6405
|
+
if (!domTreeLabelClassExcluded(cls)) out.push(cls);
|
|
6406
|
+
}
|
|
6407
|
+
return out.join(' ');
|
|
6408
|
+
}
|
|
6409
|
+
} catch(_) {}
|
|
6410
|
+
var cn = el.className;
|
|
6411
|
+
if (cn && typeof cn === 'object' && cn.baseVal != null) cn = String(cn.baseVal);
|
|
6412
|
+
return typeof cn === 'string' ? cn : '';
|
|
6413
|
+
}
|
|
6414
|
+
|
|
6257
6415
|
function domTreeLabelSuffix(el) {
|
|
6258
6416
|
if (el.id != null && el.id !== '') return '#' + String(el.id).slice(0, 40);
|
|
6259
|
-
var cn = el.
|
|
6417
|
+
var cn = domTreeLabelClassString(el).trim();
|
|
6260
6418
|
if (cn) {
|
|
6261
|
-
var parts = cn.split(/s+/).filter(function(x) {
|
|
6419
|
+
var parts = cn.split(/s+/).filter(function(x) {
|
|
6420
|
+
return x && !domTreeLabelClassExcluded(x);
|
|
6421
|
+
}).slice(0, 2).join('.');
|
|
6262
6422
|
if (parts) return '.' + parts.slice(0, 56);
|
|
6263
6423
|
}
|
|
6264
6424
|
return '';
|
|
@@ -6446,11 +6606,64 @@ function isFormControlElement(el) {
|
|
|
6446
6606
|
function shouldShowInnerContentFields(el) {
|
|
6447
6607
|
if (!el || el.nodeType !== 1) return false;
|
|
6448
6608
|
var tag = (el.tagName || '').toLowerCase();
|
|
6449
|
-
if (tag === 'input' || tag === 'textarea' || tag === 'video') return false;
|
|
6609
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select' || tag === 'video') return false;
|
|
6450
6610
|
if (isEmbeddedVideoIframe(el)) return false;
|
|
6451
6611
|
return true;
|
|
6452
6612
|
}
|
|
6453
6613
|
|
|
6614
|
+
function getSelectOptionsText(el) {
|
|
6615
|
+
if (!el || el.nodeType !== 1) return '';
|
|
6616
|
+
try {
|
|
6617
|
+
var opts = el.querySelectorAll('option');
|
|
6618
|
+
var lines = [];
|
|
6619
|
+
for (var i = 0; i < opts.length; i++) {
|
|
6620
|
+
lines.push(opts[i].textContent || '');
|
|
6621
|
+
}
|
|
6622
|
+
return lines.join('\\n');
|
|
6623
|
+
} catch(_) {
|
|
6624
|
+
return '';
|
|
6625
|
+
}
|
|
6626
|
+
}
|
|
6627
|
+
|
|
6628
|
+
function selectOptionsTextToHtml(text) {
|
|
6629
|
+
var lines = String(text == null ? '' : text).split('\\n');
|
|
6630
|
+
var parts = [];
|
|
6631
|
+
for (var i = 0; i < lines.length; i++) {
|
|
6632
|
+
var label = lines[i];
|
|
6633
|
+
if (!label && i === lines.length - 1 && lines.length > 1) continue;
|
|
6634
|
+
parts.push('<option>' + esc(label) + '</option>');
|
|
6635
|
+
}
|
|
6636
|
+
if (!parts.length) parts.push('<option>Option 1</option>');
|
|
6637
|
+
return parts.join('');
|
|
6638
|
+
}
|
|
6639
|
+
|
|
6640
|
+
function applySelectOptionsFromText(el, text) {
|
|
6641
|
+
if (!el || el.nodeType !== 1) return;
|
|
6642
|
+
beginSuppressIframeMutationDirty();
|
|
6643
|
+
try {
|
|
6644
|
+
var prevValue = '';
|
|
6645
|
+
try { prevValue = el.value || ''; } catch(_) {}
|
|
6646
|
+
var doc = el.ownerDocument;
|
|
6647
|
+
while (el.firstChild) el.removeChild(el.firstChild);
|
|
6648
|
+
var lines = String(text == null ? '' : text).split('\\n');
|
|
6649
|
+
if (!lines.length || (lines.length === 1 && !String(lines[0] || '').trim())) {
|
|
6650
|
+
lines = ['Option 1', 'Option 2'];
|
|
6651
|
+
}
|
|
6652
|
+
for (var i = 0; i < lines.length; i++) {
|
|
6653
|
+
var label = lines[i];
|
|
6654
|
+
if (!label && i === lines.length - 1) continue;
|
|
6655
|
+
var opt = doc.createElement('option');
|
|
6656
|
+
opt.textContent = label;
|
|
6657
|
+
el.appendChild(opt);
|
|
6658
|
+
}
|
|
6659
|
+
if (prevValue) {
|
|
6660
|
+
try { el.value = prevValue; } catch(_) {}
|
|
6661
|
+
}
|
|
6662
|
+
} finally {
|
|
6663
|
+
endSuppressIframeMutationDirty();
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
|
|
6454
6667
|
function elementHasHtmlChildren(el) {
|
|
6455
6668
|
if (!el || el.nodeType !== 1) return false;
|
|
6456
6669
|
try {
|
|
@@ -7109,6 +7322,12 @@ function renderRightPanel(el, options) {
|
|
|
7109
7322
|
subLbl('Placeholder') +
|
|
7110
7323
|
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
7111
7324
|
}
|
|
7325
|
+
if (tag === 'select') {
|
|
7326
|
+
contentHtml +=
|
|
7327
|
+
subLbl('Options') +
|
|
7328
|
+
'<div style="font-size:11px;color:var(--text-3);margin:-4px 0 8px">One option label per line</div>' +
|
|
7329
|
+
'<textarea class="pr-inp" id="pp-select-options" style="width:100%;min-height:80px;font-family:var(--font-mono);font-size:11px">'+esc(getSelectOptionsText(el))+'</textarea>';
|
|
7330
|
+
}
|
|
7112
7331
|
if (shouldShowInnerContentFields(el)) {
|
|
7113
7332
|
if (elementHasHtmlChildren(el)) {
|
|
7114
7333
|
contentHtml +=
|
|
@@ -7216,18 +7435,49 @@ function renderRightPanel(el, options) {
|
|
|
7216
7435
|
function wireContentFieldSync(el, sel) {
|
|
7217
7436
|
var textInp = document.getElementById('pp-text');
|
|
7218
7437
|
var htmlInp = document.getElementById('pp-html');
|
|
7438
|
+
var selectOptsInp = document.getElementById('pp-select-options');
|
|
7219
7439
|
var syncing = false;
|
|
7220
|
-
|
|
7440
|
+
var htmlApplyTimer = null;
|
|
7441
|
+
var selectApplyTimer = null;
|
|
7442
|
+
|
|
7443
|
+
function applyHtmlToElement(htmlValue) {
|
|
7444
|
+
beginSuppressIframeMutationDirty();
|
|
7445
|
+
try {
|
|
7446
|
+
el.innerHTML = htmlValue;
|
|
7447
|
+
} finally {
|
|
7448
|
+
endSuppressIframeMutationDirty();
|
|
7449
|
+
}
|
|
7450
|
+
}
|
|
7451
|
+
|
|
7452
|
+
function applyContentChange(changedId, immediate) {
|
|
7221
7453
|
if (syncing) return;
|
|
7454
|
+
if (changedId === 'pp-html' && !immediate) {
|
|
7455
|
+
if (htmlApplyTimer) clearTimeout(htmlApplyTimer);
|
|
7456
|
+
htmlApplyTimer = setTimeout(function() { applyContentChange('pp-html', true); }, 250);
|
|
7457
|
+
return;
|
|
7458
|
+
}
|
|
7459
|
+
if (changedId === 'pp-select-options' && !immediate) {
|
|
7460
|
+
if (selectApplyTimer) clearTimeout(selectApplyTimer);
|
|
7461
|
+
selectApplyTimer = setTimeout(function() { applyContentChange('pp-select-options', true); }, 250);
|
|
7462
|
+
return;
|
|
7463
|
+
}
|
|
7222
7464
|
syncing = true;
|
|
7223
7465
|
try {
|
|
7224
7466
|
var orig = getOriginalValue(changedId, el);
|
|
7225
7467
|
if (changedId === 'pp-text') {
|
|
7226
|
-
|
|
7468
|
+
beginSuppressIframeMutationDirty();
|
|
7469
|
+
try {
|
|
7470
|
+
el.innerText = textInp.value;
|
|
7471
|
+
} finally {
|
|
7472
|
+
endSuppressIframeMutationDirty();
|
|
7473
|
+
}
|
|
7227
7474
|
if (htmlInp) htmlInp.value = el.innerHTML;
|
|
7228
7475
|
logChange(sel, 'pp-text', textInp.value, el, orig);
|
|
7476
|
+
} else if (changedId === 'pp-select-options') {
|
|
7477
|
+
applySelectOptionsFromText(el, selectOptsInp.value);
|
|
7478
|
+
logChange(sel, 'pp-select-options', selectOptsInp.value, el, orig);
|
|
7229
7479
|
} else {
|
|
7230
|
-
|
|
7480
|
+
applyHtmlToElement(htmlInp.value);
|
|
7231
7481
|
if (textInp) textInp.value = el.innerText;
|
|
7232
7482
|
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
7233
7483
|
}
|
|
@@ -7240,8 +7490,12 @@ function wireContentFieldSync(el, sel) {
|
|
|
7240
7490
|
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
7241
7491
|
}
|
|
7242
7492
|
if (htmlInp) {
|
|
7243
|
-
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
7244
|
-
htmlInp.addEventListener('change', function() { applyContentChange('pp-html'); });
|
|
7493
|
+
htmlInp.addEventListener('input', function() { applyContentChange('pp-html', false); });
|
|
7494
|
+
htmlInp.addEventListener('change', function() { applyContentChange('pp-html', true); });
|
|
7495
|
+
}
|
|
7496
|
+
if (selectOptsInp) {
|
|
7497
|
+
selectOptsInp.addEventListener('input', function() { applyContentChange('pp-select-options', false); });
|
|
7498
|
+
selectOptsInp.addEventListener('change', function() { applyContentChange('pp-select-options', true); });
|
|
7245
7499
|
}
|
|
7246
7500
|
}
|
|
7247
7501
|
|
|
@@ -7732,14 +7986,21 @@ function attachChangeObserver() {
|
|
|
7732
7986
|
changeObserverDoc = null;
|
|
7733
7987
|
}
|
|
7734
7988
|
changeObserver = new MutationObserver(function(mutations) {
|
|
7989
|
+
if (suppressIframeMutationDirty > 0) return;
|
|
7735
7990
|
var hasMeaningfulMutation = false;
|
|
7736
7991
|
for (var mi = 0; mi < mutations.length; mi++) {
|
|
7737
|
-
if (!
|
|
7992
|
+
if (!isEditorChromeOnlyClassMutation(mutations[mi])) {
|
|
7738
7993
|
hasMeaningfulMutation = true;
|
|
7739
7994
|
break;
|
|
7740
7995
|
}
|
|
7741
7996
|
}
|
|
7742
7997
|
if (!hasMeaningfulMutation) return;
|
|
7998
|
+
var activeId = '';
|
|
7999
|
+
try { activeId = document.activeElement && document.activeElement.id ? String(document.activeElement.id) : ''; } catch(_) {}
|
|
8000
|
+
if (activeId === 'pp-html' || activeId === 'pp-text' || activeId === 'pp-select-options') {
|
|
8001
|
+
scheduleDomTreeRefresh();
|
|
8002
|
+
return;
|
|
8003
|
+
}
|
|
7743
8004
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
7744
8005
|
// Host scripts can replace selected nodes every few frames (e.g. A/B tool observers).
|
|
7745
8006
|
// Keep selection sticky by re-resolving from fingerprint.
|
|
@@ -8235,7 +8496,9 @@ window.addEventListener('load', function() {
|
|
|
8235
8496
|
return;
|
|
8236
8497
|
}
|
|
8237
8498
|
hideIframeLoadError();
|
|
8238
|
-
|
|
8499
|
+
var iframeLiveUrl = '';
|
|
8500
|
+
try { iframeLiveUrl = String(iframe.contentWindow.location.href || ''); } catch(_) {}
|
|
8501
|
+
emitEditorUrlChanged(iframeLiveUrl || docUrl || iframe.src || '');
|
|
8239
8502
|
// Stale events: src may already be the proxy URL while the document is still
|
|
8240
8503
|
// about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
|
|
8241
8504
|
if (docUrl === 'about:blank') {
|
|
@@ -8620,6 +8883,11 @@ function createVisualEditorMiddleware(options) {
|
|
|
8620
8883
|
}
|
|
8621
8884
|
if (chunks.length > 0) requestBody = Buffer.concat(chunks);
|
|
8622
8885
|
}
|
|
8886
|
+
const secFetchMode = (req.headers?.["sec-fetch-mode"] || "").toLowerCase();
|
|
8887
|
+
const secFetchDest = (req.headers?.["sec-fetch-dest"] || "").toLowerCase();
|
|
8888
|
+
const isLikelyDocumentNavigation = secFetchMode === "navigate" || secFetchDest === "iframe" || secFetchDest === "document" || secFetchDest === "nested-document" || secFetchDest === "frame";
|
|
8889
|
+
const isLikelyFetchOrXHR = secFetchDest === "empty" && (secFetchMode === "cors" || secFetchMode === "same-origin" || secFetchMode === "no-cors");
|
|
8890
|
+
const passthroughUpstreamRedirects = (method === "GET" || method === "HEAD") && (isLikelyDocumentNavigation || !isLikelyFetchOrXHR);
|
|
8623
8891
|
const upstreamTimeoutMs = 12e4;
|
|
8624
8892
|
const ac = new AbortController();
|
|
8625
8893
|
const timeoutId = setTimeout(() => ac.abort(), upstreamTimeoutMs);
|
|
@@ -8629,7 +8897,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
8629
8897
|
method,
|
|
8630
8898
|
headers: fetchHeaders,
|
|
8631
8899
|
body: requestBody ? Buffer.from(requestBody) : null,
|
|
8632
|
-
redirect: "follow",
|
|
8900
|
+
redirect: passthroughUpstreamRedirects ? "manual" : "follow",
|
|
8633
8901
|
signal: ac.signal
|
|
8634
8902
|
});
|
|
8635
8903
|
} catch (fetchErr) {
|
|
@@ -8653,12 +8921,43 @@ function createVisualEditorMiddleware(options) {
|
|
|
8653
8921
|
return;
|
|
8654
8922
|
}
|
|
8655
8923
|
clearTimeout(timeoutId);
|
|
8924
|
+
if (passthroughUpstreamRedirects && upstream.status >= 300 && upstream.status < 400) {
|
|
8925
|
+
const locationHeader = upstream.headers.get("location") || upstream.headers.get("Location");
|
|
8926
|
+
if (locationHeader) {
|
|
8927
|
+
try {
|
|
8928
|
+
const redirectTarget = new URL(locationHeader, targetUrl);
|
|
8929
|
+
if (redirectTarget.origin === origin) {
|
|
8930
|
+
const proxyRedirect = new URL(proxyRootForRequest, "http://localhost");
|
|
8931
|
+
proxyRedirect.searchParams.set("password", password);
|
|
8932
|
+
proxyRedirect.searchParams.set("url", redirectTarget.toString());
|
|
8933
|
+
url.searchParams.forEach((value, key) => {
|
|
8934
|
+
if (key === "url" || key === "password") return;
|
|
8935
|
+
proxyRedirect.searchParams.set(key, value);
|
|
8936
|
+
});
|
|
8937
|
+
res.statusCode = upstream.status === 303 ? 303 : 302;
|
|
8938
|
+
res.setHeader("Location", `${proxyRedirect.pathname}${proxyRedirect.search}`);
|
|
8939
|
+
res.setHeader("Cache-Control", "no-store");
|
|
8940
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
8941
|
+
setFrameHeaders(req, res);
|
|
8942
|
+
res.end();
|
|
8943
|
+
return;
|
|
8944
|
+
}
|
|
8945
|
+
res.statusCode = 502;
|
|
8946
|
+
res.setHeader("Content-Type", "application/json");
|
|
8947
|
+
res.end(
|
|
8948
|
+
JSON.stringify({
|
|
8949
|
+
error: "Cross-origin redirect blocked in editor preview",
|
|
8950
|
+
location: redirectTarget.toString(),
|
|
8951
|
+
from: targetUrl
|
|
8952
|
+
})
|
|
8953
|
+
);
|
|
8954
|
+
return;
|
|
8955
|
+
} catch (_) {
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8958
|
+
}
|
|
8656
8959
|
const responseContentType = upstream.headers.get("content-type") || "";
|
|
8657
8960
|
const isHtmlResponse = responseContentType.includes("text/html");
|
|
8658
|
-
const secFetchMode = (req.headers?.["sec-fetch-mode"] || "").toLowerCase();
|
|
8659
|
-
const secFetchDest = (req.headers?.["sec-fetch-dest"] || "").toLowerCase();
|
|
8660
|
-
const isLikelyDocumentNavigation = secFetchMode === "navigate" || secFetchDest === "iframe" || secFetchDest === "document" || secFetchDest === "nested-document" || secFetchDest === "frame";
|
|
8661
|
-
const isLikelyFetchOrXHR = secFetchDest === "empty" && (secFetchMode === "cors" || secFetchMode === "same-origin" || secFetchMode === "no-cors");
|
|
8662
8961
|
const shouldInjectHtmlBridge = isHtmlResponse && (isLikelyDocumentNavigation || !isLikelyFetchOrXHR);
|
|
8663
8962
|
if (!isHtmlResponse || !shouldInjectHtmlBridge) {
|
|
8664
8963
|
const binary = Buffer.from(await upstream.arrayBuffer());
|
|
@@ -8712,6 +9011,18 @@ ${iframeAlwaysShowCssGuardScript}
|
|
|
8712
9011
|
/<meta[^>]+name=["']?\s*content-security-policy\s*["']?[^>]*>/gi,
|
|
8713
9012
|
""
|
|
8714
9013
|
);
|
|
9014
|
+
html = html.replace(
|
|
9015
|
+
/(<meta[^>]+http-equiv=["']?refresh["']?[^>]*content=["'][^"']*url=)([^"';]+)(["'][^>]*>)/gi,
|
|
9016
|
+
(match, prefix, urlPart, suffix) => {
|
|
9017
|
+
try {
|
|
9018
|
+
const abs = new URL(String(urlPart).trim(), origin).toString();
|
|
9019
|
+
if (new URL(abs).origin !== origin) return match;
|
|
9020
|
+
return `${prefix}${proxyBase}${encodeURIComponent(abs)}${suffix}`;
|
|
9021
|
+
} catch {
|
|
9022
|
+
return match;
|
|
9023
|
+
}
|
|
9024
|
+
}
|
|
9025
|
+
);
|
|
8715
9026
|
const runtimePreflightScript = `<script>(function(){try{
|
|
8716
9027
|
var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
8717
9028
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
@@ -8918,6 +9229,8 @@ try{if(window.history&&typeof window.history.pushState==="function"){var nativeP
|
|
|
8918
9229
|
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(_){}
|
|
8919
9230
|
try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
8920
9231
|
try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
|
|
9232
|
+
try{window.addEventListener("pageshow",notifyEditorUrlChanged,true);}catch(_){}
|
|
9233
|
+
try{window.addEventListener("load",function(){setTimeout(notifyEditorUrlChanged,0);},true);}catch(_){}
|
|
8921
9234
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
8922
9235
|
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;}}
|
|
8923
9236
|
function toProxy(raw){
|
|
@@ -8946,6 +9259,9 @@ function toProxy(raw){
|
|
|
8946
9259
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
8947
9260
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
8948
9261
|
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;}}
|
|
9262
|
+
function interceptMetaRefresh(){try{var metas=document.querySelectorAll('meta[http-equiv="refresh" i],meta[http-equiv="Refresh"]');for(var i=0;i<metas.length;i++){var content=metas[i].getAttribute("content")||"";var m=content.match(/url=(.+)$/i);if(!m)continue;var raw=m[1].trim().replace(/^['"]|['"]$/g,"");if(safeNavigate(raw,"replace"))metas[i].parentNode&&metas[i].parentNode.removeChild(metas[i]);}}catch(_){}}
|
|
9263
|
+
try{interceptMetaRefresh();}catch(_){}
|
|
9264
|
+
try{document.addEventListener("DOMContentLoaded",interceptMetaRefresh,true);}catch(_){}
|
|
8949
9265
|
try{if(nativeAssign){window.location.assign=function(url){return safeNavigate(url,"assign");};}}catch(_){}
|
|
8950
9266
|
try{if(nativeReplace){window.location.replace=function(url){return safeNavigate(url,"replace");};}}catch(_){}
|
|
8951
9267
|
try{var hrefDesc=Object.getOwnPropertyDescriptor(Location.prototype,"href");if(hrefDesc&&hrefDesc.configurable&&hrefDesc.get&&hrefDesc.set){Object.defineProperty(Location.prototype,"href",{configurable:true,enumerable:hrefDesc.enumerable,get:function(){return hrefDesc.get.call(this);},set:function(v){safeNavigate(v,"assign");}});}}catch(_){}
|
package/dist/vite.js
CHANGED
|
@@ -1031,24 +1031,16 @@ button.var-tab.active{
|
|
|
1031
1031
|
.lp-body #tab-dom-tree, .lp-body #tab-elements{
|
|
1032
1032
|
padding-top:4px;
|
|
1033
1033
|
}
|
|
1034
|
-
.lp-body #
|
|
1035
|
-
|
|
1036
|
-
font-style: normal;
|
|
1037
|
-
font-weight: 500;
|
|
1038
|
-
line-height: 14px;
|
|
1039
|
-
letter-spacing: -0.1px;
|
|
1040
|
-
}
|
|
1041
|
-
.lp-body #tab-elements #elements-root > .dt-row{
|
|
1042
|
-
padding-left: 16px!important;
|
|
1043
|
-
}
|
|
1044
|
-
.lp-body #dom-tree-root .dt-lbl{
|
|
1034
|
+
.lp-body #dom-tree-root .dt-lbl,
|
|
1035
|
+
.lp-body #elements-root .dt-lbl{
|
|
1045
1036
|
color: var(--content-subtle, #737373);
|
|
1046
1037
|
font-style: normal;
|
|
1047
1038
|
font-weight: 400;
|
|
1048
|
-
line-height: var(--font-leading-3, 12px);
|
|
1039
|
+
line-height: var(--font-leading-3, 12px);
|
|
1049
1040
|
letter-spacing: -0.1px;
|
|
1050
1041
|
}
|
|
1051
|
-
.lp-body #dom-tree-root .dt-lbl .dt-tag
|
|
1042
|
+
.lp-body #dom-tree-root .dt-lbl .dt-tag,
|
|
1043
|
+
.lp-body #elements-root .dt-lbl .dt-tag{
|
|
1052
1044
|
color: var(--content-strong, #171717);
|
|
1053
1045
|
font-family: "JetBrains Mono";
|
|
1054
1046
|
font-size: 12px;
|
|
@@ -1062,7 +1054,6 @@ padding:3px 6px;
|
|
|
1062
1054
|
display:inline-block;
|
|
1063
1055
|
margin-right:4px;
|
|
1064
1056
|
}
|
|
1065
|
-
.lp-body #tab-elements .dt-row .dt-chev.dt-spacer{display:none;}
|
|
1066
1057
|
.lp-body #tab-dom-tree .dt-row .dt-ico{display:none;}
|
|
1067
1058
|
.lp-body, .section-components-body{flex:1;overflow-y:auto}
|
|
1068
1059
|
.lp-body::-webkit-scrollbar, .section-components-body::-webkit-scrollbar{width:3px}
|
|
@@ -3151,6 +3142,7 @@ var PROP_META = {
|
|
|
3151
3142
|
'pp-value': {label:'Value', cssProp:null},
|
|
3152
3143
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
3153
3144
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
3145
|
+
'pp-select-options': {label:'Options', cssProp:null},
|
|
3154
3146
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
3155
3147
|
'pp-tab-css': {label:'Tablet CSS', cssProp:null},
|
|
3156
3148
|
};
|
|
@@ -3167,6 +3159,7 @@ function getOriginalValue(inputId, el) {
|
|
|
3167
3159
|
switch (inputId) {
|
|
3168
3160
|
case 'pp-text': return el.innerText || '';
|
|
3169
3161
|
case 'pp-html': return el.innerHTML || '';
|
|
3162
|
+
case 'pp-select-options': return getSelectOptionsText(el);
|
|
3170
3163
|
case 'pp-cls': return el.className || '';
|
|
3171
3164
|
case 'pp-id': return el.id || '';
|
|
3172
3165
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
@@ -3316,6 +3309,7 @@ function revertChangeOnDom(change) {
|
|
|
3316
3309
|
switch (change.inputId) {
|
|
3317
3310
|
case 'pp-text': el.innerText = orig; break;
|
|
3318
3311
|
case 'pp-html': el.innerHTML = orig; break;
|
|
3312
|
+
case 'pp-select-options': applySelectOptionsFromText(el, orig); break;
|
|
3319
3313
|
case 'pp-cls': el.className = orig; break;
|
|
3320
3314
|
case 'pp-id': el.id = orig; break;
|
|
3321
3315
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
@@ -4974,6 +4968,8 @@ function stateChangeToChainSet(c) {
|
|
|
4974
4968
|
return { selector: c.selector, type: 'content', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4975
4969
|
case 'pp-html':
|
|
4976
4970
|
return { selector: c.selector, type: 'content', html: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4971
|
+
case 'pp-select-options':
|
|
4972
|
+
return { selector: c.selector, type: 'content', html: selectOptionsTextToHtml(c.value), vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4977
4973
|
case 'pp-cls':
|
|
4978
4974
|
return { selector: c.selector, type: 'attribute', attribute: 'class', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4979
4975
|
case 'pp-id':
|
|
@@ -5587,6 +5583,10 @@ function setTreeHoverHighlight(el) {
|
|
|
5587
5583
|
}
|
|
5588
5584
|
|
|
5589
5585
|
function isTreeHoverOnlyClassMutation(mutation) {
|
|
5586
|
+
return isEditorChromeOnlyClassMutation(mutation);
|
|
5587
|
+
}
|
|
5588
|
+
|
|
5589
|
+
function isEditorChromeOnlyClassMutation(mutation) {
|
|
5590
5590
|
if (!mutation || mutation.type !== 'attributes' || mutation.attributeName !== 'class') return false;
|
|
5591
5591
|
var oldClass = String(mutation.oldValue || '');
|
|
5592
5592
|
var target = mutation.target;
|
|
@@ -5594,7 +5594,12 @@ function isTreeHoverOnlyClassMutation(mutation) {
|
|
|
5594
5594
|
try {
|
|
5595
5595
|
nextClass = target && typeof target.className === 'string' ? target.className : '';
|
|
5596
5596
|
} catch(_) {}
|
|
5597
|
-
|
|
5597
|
+
var combined = oldClass + ' ' + nextClass;
|
|
5598
|
+
return (
|
|
5599
|
+
combined.indexOf('vve-tree-hover') >= 0 ||
|
|
5600
|
+
combined.indexOf('vve-selected') >= 0 ||
|
|
5601
|
+
combined.indexOf('vve-dragging') >= 0
|
|
5602
|
+
);
|
|
5598
5603
|
}
|
|
5599
5604
|
|
|
5600
5605
|
function setDragHandleActive(on) {
|
|
@@ -5644,7 +5649,13 @@ function positionSelectionToolbar() {
|
|
|
5644
5649
|
if (!bar || !liveSelected || !iframe || !iframe.contentWindow || !panel) return;
|
|
5645
5650
|
if (selectedEl !== liveSelected) {
|
|
5646
5651
|
selectedEl = liveSelected;
|
|
5647
|
-
|
|
5652
|
+
if (!document.activeElement || (
|
|
5653
|
+
document.activeElement.id !== 'pp-html' &&
|
|
5654
|
+
document.activeElement.id !== 'pp-text' &&
|
|
5655
|
+
document.activeElement.id !== 'pp-select-options'
|
|
5656
|
+
)) {
|
|
5657
|
+
renderRightPanel(liveSelected);
|
|
5658
|
+
}
|
|
5648
5659
|
syncDomTreeSelection();
|
|
5649
5660
|
}
|
|
5650
5661
|
var elR = getIframeElementVisualRect(selectedEl);
|
|
@@ -6178,31 +6189,156 @@ function renderElementsTree(filterRaw) {
|
|
|
6178
6189
|
return;
|
|
6179
6190
|
}
|
|
6180
6191
|
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6192
|
+
function nodeIcon(tag) {
|
|
6193
|
+
tag = (tag || '').toLowerCase();
|
|
6194
|
+
|
|
6195
|
+
// Headings
|
|
6196
|
+
if (/^h[1-6]$/.test(tag)) return 'bi bi-type-h1';
|
|
6197
|
+
|
|
6198
|
+
// Document & metadata
|
|
6199
|
+
if (tag === 'html') return 'bi bi-filetype-html';
|
|
6200
|
+
if (tag === 'head') return 'bi bi-file-earmark-code';
|
|
6201
|
+
if (tag === 'body') return 'bi bi-file-earmark-richtext';
|
|
6202
|
+
if (tag === 'title') return 'bi bi-card-heading';
|
|
6203
|
+
if (tag === 'meta') return 'bi bi-info-circle';
|
|
6204
|
+
if (tag === 'link') return 'bi bi-link';
|
|
6205
|
+
if (tag === 'style') return 'bi bi-filetype-css';
|
|
6206
|
+
if (tag === 'script') return 'bi bi-filetype-js';
|
|
6207
|
+
if (tag === 'noscript') return 'bi bi-slash-circle';
|
|
6208
|
+
if (tag === 'base') return 'bi bi-house-gear';
|
|
6209
|
+
|
|
6210
|
+
// Sectioning & layout
|
|
6211
|
+
if (tag === 'section' || tag === 'main' || tag === 'article' ||
|
|
6212
|
+
tag === 'header' || tag === 'footer' || tag === 'nav' || tag === 'aside')
|
|
6213
|
+
return 'bi bi-layout-three-columns';
|
|
6214
|
+
if (tag === 'div') return 'bi bi-square';
|
|
6215
|
+
if (tag === 'address') return 'bi bi-geo-alt';
|
|
6216
|
+
|
|
6217
|
+
// Text content
|
|
6218
|
+
if (tag === 'p' || tag === 'span') return 'bi bi-text-left';
|
|
6219
|
+
if (tag === 'blockquote' || tag === 'q') return 'bi bi-blockquote-left';
|
|
6220
|
+
if (tag === 'pre') return 'bi bi-code-square';
|
|
6221
|
+
if (tag === 'code') return 'bi bi-code-slash';
|
|
6222
|
+
if (tag === 'kbd') return 'bi bi-keyboard';
|
|
6223
|
+
if (tag === 'samp') return 'bi bi-terminal';
|
|
6224
|
+
if (tag === 'var') return 'bi bi-braces';
|
|
6225
|
+
if (tag === 'cite') return 'bi bi-quote';
|
|
6226
|
+
if (tag === 'abbr') return 'bi bi-fonts';
|
|
6227
|
+
if (tag === 'time') return 'bi bi-clock';
|
|
6228
|
+
if (tag === 'mark') return 'bi bi-highlighter';
|
|
6229
|
+
if (tag === 'small') return 'bi bi-type';
|
|
6230
|
+
if (tag === 'sub') return 'bi bi-subscript';
|
|
6231
|
+
if (tag === 'sup') return 'bi bi-superscript';
|
|
6232
|
+
if (tag === 'br') return 'bi bi-arrow-return-left';
|
|
6233
|
+
if (tag === 'wbr') return 'bi bi-distribute-horizontal';
|
|
6234
|
+
|
|
6235
|
+
// Inline formatting
|
|
6236
|
+
if (tag === 'strong' || tag === 'b') return 'bi bi-type-bold';
|
|
6237
|
+
if (tag === 'em' || tag === 'i') return 'bi bi-type-italic';
|
|
6238
|
+
if (tag === 'u' || tag === 'ins') return 'bi bi-type-underline';
|
|
6239
|
+
if (tag === 's' || tag === 'del' || tag === 'strike') return 'bi bi-type-strikethrough';
|
|
6240
|
+
|
|
6241
|
+
// Lists
|
|
6242
|
+
if (tag === 'ul') return 'bi bi-list-ul';
|
|
6243
|
+
if (tag === 'ol') return 'bi bi-list-ol';
|
|
6244
|
+
if (tag === 'li') return 'bi bi-dot';
|
|
6245
|
+
if (tag === 'dl') return 'bi bi-card-list';
|
|
6246
|
+
if (tag === 'dt') return 'bi bi-tag';
|
|
6247
|
+
if (tag === 'dd') return 'bi bi-text-indent-left';
|
|
6248
|
+
|
|
6249
|
+
// Links & navigation
|
|
6250
|
+
if (tag === 'a') return 'bi bi-link-45deg';
|
|
6251
|
+
|
|
6252
|
+
// Media
|
|
6253
|
+
if (tag === 'img') return 'bi bi-image';
|
|
6254
|
+
if (tag === 'picture') return 'bi bi-images';
|
|
6255
|
+
if (tag === 'figure') return 'bi bi-card-image';
|
|
6256
|
+
if (tag === 'figcaption') return 'bi bi-card-text';
|
|
6257
|
+
if (tag === 'video') return 'bi bi-camera-video';
|
|
6258
|
+
if (tag === 'audio') return 'bi bi-music-note-beamed';
|
|
6259
|
+
if (tag === 'source') return 'bi bi-cloud-arrow-down';
|
|
6260
|
+
if (tag === 'track') return 'bi bi-badge-cc';
|
|
6261
|
+
if (tag === 'iframe') return 'bi bi-window';
|
|
6262
|
+
if (tag === 'embed' || tag === 'object') return 'bi bi-box-arrow-in-down';
|
|
6263
|
+
if (tag === 'param') return 'bi bi-sliders';
|
|
6264
|
+
if (tag === 'canvas') return 'bi bi-easel';
|
|
6265
|
+
if (tag === 'map') return 'bi bi-map';
|
|
6266
|
+
if (tag === 'area') return 'bi bi-bounding-box';
|
|
6267
|
+
|
|
6268
|
+
// Vector / math
|
|
6269
|
+
if (tag === 'svg') return 'bi bi-bezier2';
|
|
6270
|
+
if (tag === 'path') return 'bi bi-bezier';
|
|
6271
|
+
if (tag === 'circle') return 'bi bi-circle';
|
|
6272
|
+
if (tag === 'rect') return 'bi bi-square';
|
|
6273
|
+
if (tag === 'line') return 'bi bi-slash-lg';
|
|
6274
|
+
if (tag === 'polygon') return 'bi bi-pentagon';
|
|
6275
|
+
if (tag === 'polyline') return 'bi bi-share';
|
|
6276
|
+
if (tag === 'ellipse') return 'bi bi-circle-half';
|
|
6277
|
+
if (tag === 'g') return 'bi bi-collection';
|
|
6278
|
+
if (tag === 'use') return 'bi bi-arrow-repeat';
|
|
6279
|
+
if (tag === 'defs') return 'bi bi-bookmark';
|
|
6280
|
+
if (tag === 'symbol') return 'bi bi-star';
|
|
6281
|
+
if (tag === 'text') return 'bi bi-fonts';
|
|
6282
|
+
if (tag === 'math') return 'bi bi-calculator';
|
|
6283
|
+
|
|
6284
|
+
// Forms
|
|
6285
|
+
if (tag === 'form') return 'bi bi-file-earmark-check';
|
|
6286
|
+
if (tag === 'fieldset') return 'bi bi-bounding-box-circles';
|
|
6287
|
+
if (tag === 'legend') return 'bi bi-tag-fill';
|
|
6288
|
+
if (tag === 'label') return 'bi bi-tag';
|
|
6289
|
+
if (tag === 'input') return 'bi bi-input-cursor-text';
|
|
6290
|
+
if (tag === 'button') return 'bi bi-ui-radios';
|
|
6291
|
+
if (tag === 'select') return 'bi bi-menu-button';
|
|
6292
|
+
if (tag === 'option') return 'bi bi-check2-square';
|
|
6293
|
+
if (tag === 'optgroup') return 'bi bi-list-nested';
|
|
6294
|
+
if (tag === 'textarea') return 'bi bi-textarea-resize';
|
|
6295
|
+
if (tag === 'datalist') return 'bi bi-list-columns';
|
|
6296
|
+
if (tag === 'output') return 'bi bi-box-arrow-right';
|
|
6297
|
+
if (tag === 'progress') return 'bi bi-bar-chart-line';
|
|
6298
|
+
if (tag === 'meter') return 'bi bi-speedometer2';
|
|
6299
|
+
|
|
6300
|
+
// Tables
|
|
6301
|
+
if (tag === 'table') return 'bi bi-table';
|
|
6302
|
+
if (tag === 'caption') return 'bi bi-card-heading';
|
|
6303
|
+
if (tag === 'thead') return 'bi bi-layout-text-window';
|
|
6304
|
+
if (tag === 'tbody') return 'bi bi-layout-text-sidebar';
|
|
6305
|
+
if (tag === 'tfoot') return 'bi bi-layout-text-window-reverse';
|
|
6306
|
+
if (tag === 'tr') return 'bi bi-grip-horizontal';
|
|
6307
|
+
if (tag === 'th') return 'bi bi-grid-3x3-gap-fill';
|
|
6308
|
+
if (tag === 'td') return 'bi bi-grid-3x3-gap';
|
|
6309
|
+
if (tag === 'col') return 'bi bi-layout-three-columns';
|
|
6310
|
+
if (tag === 'colgroup') return 'bi bi-columns-gap';
|
|
6311
|
+
|
|
6312
|
+
// Interactive / disclosure
|
|
6313
|
+
if (tag === 'details') return 'bi bi-caret-down-square';
|
|
6314
|
+
if (tag === 'summary') return 'bi bi-card-text';
|
|
6315
|
+
if (tag === 'dialog') return 'bi bi-chat-square-text';
|
|
6316
|
+
if (tag === 'menu') return 'bi bi-list';
|
|
6317
|
+
|
|
6318
|
+
// Web components / templating
|
|
6319
|
+
if (tag === 'template') return 'bi bi-file-earmark-code';
|
|
6320
|
+
if (tag === 'slot') return 'bi bi-box-seam';
|
|
6321
|
+
|
|
6322
|
+
// Ruby annotation
|
|
6323
|
+
if (tag === 'ruby' || tag === 'rt' || tag === 'rp' || tag === 'rb')
|
|
6324
|
+
return 'bi bi-translate';
|
|
6325
|
+
if (tag === 'bdi' || tag === 'bdo') return 'bi bi-arrow-left-right';
|
|
6326
|
+
|
|
6327
|
+
// Misc
|
|
6328
|
+
if (tag === 'hr') return 'bi bi-hr';
|
|
6329
|
+
if (tag === '#text' || tag === 'text-node') return 'bi bi-cursor-text';
|
|
6330
|
+
if (tag === '#comment') return 'bi bi-chat-left-text';
|
|
6331
|
+
|
|
6332
|
+
return 'bi bi-square';
|
|
6333
|
+
}
|
|
6194
6334
|
|
|
6195
|
-
function labelFor(el) {
|
|
6196
|
-
var tag = (el.tagName || '').toLowerCase();
|
|
6197
|
-
return tag.toUpperCase();
|
|
6198
|
-
}
|
|
6199
6335
|
|
|
6200
6336
|
var nodes = collectEditorInsertedElements(doc);
|
|
6201
6337
|
|
|
6202
6338
|
root.innerHTML = '';
|
|
6203
6339
|
for (var i = 0; i < nodes.length; i++) {
|
|
6204
6340
|
var el = nodes[i];
|
|
6205
|
-
var lblText =
|
|
6341
|
+
var lblText = domTreeLabelFor(el);
|
|
6206
6342
|
if (filterText && lblText.toLowerCase().indexOf(filterText) < 0) continue;
|
|
6207
6343
|
|
|
6208
6344
|
var row = document.createElement('div');
|
|
@@ -6221,7 +6357,7 @@ function renderElementsTree(filterRaw) {
|
|
|
6221
6357
|
|
|
6222
6358
|
var lbl = document.createElement('div');
|
|
6223
6359
|
lbl.className = 'dt-lbl';
|
|
6224
|
-
lbl
|
|
6360
|
+
setDomTreeLabelContent(lbl, el);
|
|
6225
6361
|
lbl.title = buildSelector(el);
|
|
6226
6362
|
|
|
6227
6363
|
row.appendChild(spacer);
|
|
@@ -6246,11 +6382,35 @@ function renderElementsTree(filterRaw) {
|
|
|
6246
6382
|
};
|
|
6247
6383
|
}
|
|
6248
6384
|
|
|
6385
|
+
function domTreeLabelClassExcluded(className) {
|
|
6386
|
+
var c = String(className || '');
|
|
6387
|
+
return !c || c === 'vve-selected' || c === 'vve-tree-hover' || c.indexOf('vve-') === 0;
|
|
6388
|
+
}
|
|
6389
|
+
|
|
6390
|
+
function domTreeLabelClassString(el) {
|
|
6391
|
+
if (!el) return '';
|
|
6392
|
+
try {
|
|
6393
|
+
if (el.classList && el.classList.length) {
|
|
6394
|
+
var out = [];
|
|
6395
|
+
for (var i = 0; i < el.classList.length; i++) {
|
|
6396
|
+
var cls = el.classList[i];
|
|
6397
|
+
if (!domTreeLabelClassExcluded(cls)) out.push(cls);
|
|
6398
|
+
}
|
|
6399
|
+
return out.join(' ');
|
|
6400
|
+
}
|
|
6401
|
+
} catch(_) {}
|
|
6402
|
+
var cn = el.className;
|
|
6403
|
+
if (cn && typeof cn === 'object' && cn.baseVal != null) cn = String(cn.baseVal);
|
|
6404
|
+
return typeof cn === 'string' ? cn : '';
|
|
6405
|
+
}
|
|
6406
|
+
|
|
6249
6407
|
function domTreeLabelSuffix(el) {
|
|
6250
6408
|
if (el.id != null && el.id !== '') return '#' + String(el.id).slice(0, 40);
|
|
6251
|
-
var cn = el.
|
|
6409
|
+
var cn = domTreeLabelClassString(el).trim();
|
|
6252
6410
|
if (cn) {
|
|
6253
|
-
var parts = cn.split(/s+/).filter(function(x) {
|
|
6411
|
+
var parts = cn.split(/s+/).filter(function(x) {
|
|
6412
|
+
return x && !domTreeLabelClassExcluded(x);
|
|
6413
|
+
}).slice(0, 2).join('.');
|
|
6254
6414
|
if (parts) return '.' + parts.slice(0, 56);
|
|
6255
6415
|
}
|
|
6256
6416
|
return '';
|
|
@@ -6438,11 +6598,64 @@ function isFormControlElement(el) {
|
|
|
6438
6598
|
function shouldShowInnerContentFields(el) {
|
|
6439
6599
|
if (!el || el.nodeType !== 1) return false;
|
|
6440
6600
|
var tag = (el.tagName || '').toLowerCase();
|
|
6441
|
-
if (tag === 'input' || tag === 'textarea' || tag === 'video') return false;
|
|
6601
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select' || tag === 'video') return false;
|
|
6442
6602
|
if (isEmbeddedVideoIframe(el)) return false;
|
|
6443
6603
|
return true;
|
|
6444
6604
|
}
|
|
6445
6605
|
|
|
6606
|
+
function getSelectOptionsText(el) {
|
|
6607
|
+
if (!el || el.nodeType !== 1) return '';
|
|
6608
|
+
try {
|
|
6609
|
+
var opts = el.querySelectorAll('option');
|
|
6610
|
+
var lines = [];
|
|
6611
|
+
for (var i = 0; i < opts.length; i++) {
|
|
6612
|
+
lines.push(opts[i].textContent || '');
|
|
6613
|
+
}
|
|
6614
|
+
return lines.join('\\n');
|
|
6615
|
+
} catch(_) {
|
|
6616
|
+
return '';
|
|
6617
|
+
}
|
|
6618
|
+
}
|
|
6619
|
+
|
|
6620
|
+
function selectOptionsTextToHtml(text) {
|
|
6621
|
+
var lines = String(text == null ? '' : text).split('\\n');
|
|
6622
|
+
var parts = [];
|
|
6623
|
+
for (var i = 0; i < lines.length; i++) {
|
|
6624
|
+
var label = lines[i];
|
|
6625
|
+
if (!label && i === lines.length - 1 && lines.length > 1) continue;
|
|
6626
|
+
parts.push('<option>' + esc(label) + '</option>');
|
|
6627
|
+
}
|
|
6628
|
+
if (!parts.length) parts.push('<option>Option 1</option>');
|
|
6629
|
+
return parts.join('');
|
|
6630
|
+
}
|
|
6631
|
+
|
|
6632
|
+
function applySelectOptionsFromText(el, text) {
|
|
6633
|
+
if (!el || el.nodeType !== 1) return;
|
|
6634
|
+
beginSuppressIframeMutationDirty();
|
|
6635
|
+
try {
|
|
6636
|
+
var prevValue = '';
|
|
6637
|
+
try { prevValue = el.value || ''; } catch(_) {}
|
|
6638
|
+
var doc = el.ownerDocument;
|
|
6639
|
+
while (el.firstChild) el.removeChild(el.firstChild);
|
|
6640
|
+
var lines = String(text == null ? '' : text).split('\\n');
|
|
6641
|
+
if (!lines.length || (lines.length === 1 && !String(lines[0] || '').trim())) {
|
|
6642
|
+
lines = ['Option 1', 'Option 2'];
|
|
6643
|
+
}
|
|
6644
|
+
for (var i = 0; i < lines.length; i++) {
|
|
6645
|
+
var label = lines[i];
|
|
6646
|
+
if (!label && i === lines.length - 1) continue;
|
|
6647
|
+
var opt = doc.createElement('option');
|
|
6648
|
+
opt.textContent = label;
|
|
6649
|
+
el.appendChild(opt);
|
|
6650
|
+
}
|
|
6651
|
+
if (prevValue) {
|
|
6652
|
+
try { el.value = prevValue; } catch(_) {}
|
|
6653
|
+
}
|
|
6654
|
+
} finally {
|
|
6655
|
+
endSuppressIframeMutationDirty();
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
|
|
6446
6659
|
function elementHasHtmlChildren(el) {
|
|
6447
6660
|
if (!el || el.nodeType !== 1) return false;
|
|
6448
6661
|
try {
|
|
@@ -7101,6 +7314,12 @@ function renderRightPanel(el, options) {
|
|
|
7101
7314
|
subLbl('Placeholder') +
|
|
7102
7315
|
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
7103
7316
|
}
|
|
7317
|
+
if (tag === 'select') {
|
|
7318
|
+
contentHtml +=
|
|
7319
|
+
subLbl('Options') +
|
|
7320
|
+
'<div style="font-size:11px;color:var(--text-3);margin:-4px 0 8px">One option label per line</div>' +
|
|
7321
|
+
'<textarea class="pr-inp" id="pp-select-options" style="width:100%;min-height:80px;font-family:var(--font-mono);font-size:11px">'+esc(getSelectOptionsText(el))+'</textarea>';
|
|
7322
|
+
}
|
|
7104
7323
|
if (shouldShowInnerContentFields(el)) {
|
|
7105
7324
|
if (elementHasHtmlChildren(el)) {
|
|
7106
7325
|
contentHtml +=
|
|
@@ -7208,18 +7427,49 @@ function renderRightPanel(el, options) {
|
|
|
7208
7427
|
function wireContentFieldSync(el, sel) {
|
|
7209
7428
|
var textInp = document.getElementById('pp-text');
|
|
7210
7429
|
var htmlInp = document.getElementById('pp-html');
|
|
7430
|
+
var selectOptsInp = document.getElementById('pp-select-options');
|
|
7211
7431
|
var syncing = false;
|
|
7212
|
-
|
|
7432
|
+
var htmlApplyTimer = null;
|
|
7433
|
+
var selectApplyTimer = null;
|
|
7434
|
+
|
|
7435
|
+
function applyHtmlToElement(htmlValue) {
|
|
7436
|
+
beginSuppressIframeMutationDirty();
|
|
7437
|
+
try {
|
|
7438
|
+
el.innerHTML = htmlValue;
|
|
7439
|
+
} finally {
|
|
7440
|
+
endSuppressIframeMutationDirty();
|
|
7441
|
+
}
|
|
7442
|
+
}
|
|
7443
|
+
|
|
7444
|
+
function applyContentChange(changedId, immediate) {
|
|
7213
7445
|
if (syncing) return;
|
|
7446
|
+
if (changedId === 'pp-html' && !immediate) {
|
|
7447
|
+
if (htmlApplyTimer) clearTimeout(htmlApplyTimer);
|
|
7448
|
+
htmlApplyTimer = setTimeout(function() { applyContentChange('pp-html', true); }, 250);
|
|
7449
|
+
return;
|
|
7450
|
+
}
|
|
7451
|
+
if (changedId === 'pp-select-options' && !immediate) {
|
|
7452
|
+
if (selectApplyTimer) clearTimeout(selectApplyTimer);
|
|
7453
|
+
selectApplyTimer = setTimeout(function() { applyContentChange('pp-select-options', true); }, 250);
|
|
7454
|
+
return;
|
|
7455
|
+
}
|
|
7214
7456
|
syncing = true;
|
|
7215
7457
|
try {
|
|
7216
7458
|
var orig = getOriginalValue(changedId, el);
|
|
7217
7459
|
if (changedId === 'pp-text') {
|
|
7218
|
-
|
|
7460
|
+
beginSuppressIframeMutationDirty();
|
|
7461
|
+
try {
|
|
7462
|
+
el.innerText = textInp.value;
|
|
7463
|
+
} finally {
|
|
7464
|
+
endSuppressIframeMutationDirty();
|
|
7465
|
+
}
|
|
7219
7466
|
if (htmlInp) htmlInp.value = el.innerHTML;
|
|
7220
7467
|
logChange(sel, 'pp-text', textInp.value, el, orig);
|
|
7468
|
+
} else if (changedId === 'pp-select-options') {
|
|
7469
|
+
applySelectOptionsFromText(el, selectOptsInp.value);
|
|
7470
|
+
logChange(sel, 'pp-select-options', selectOptsInp.value, el, orig);
|
|
7221
7471
|
} else {
|
|
7222
|
-
|
|
7472
|
+
applyHtmlToElement(htmlInp.value);
|
|
7223
7473
|
if (textInp) textInp.value = el.innerText;
|
|
7224
7474
|
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
7225
7475
|
}
|
|
@@ -7232,8 +7482,12 @@ function wireContentFieldSync(el, sel) {
|
|
|
7232
7482
|
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
7233
7483
|
}
|
|
7234
7484
|
if (htmlInp) {
|
|
7235
|
-
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
7236
|
-
htmlInp.addEventListener('change', function() { applyContentChange('pp-html'); });
|
|
7485
|
+
htmlInp.addEventListener('input', function() { applyContentChange('pp-html', false); });
|
|
7486
|
+
htmlInp.addEventListener('change', function() { applyContentChange('pp-html', true); });
|
|
7487
|
+
}
|
|
7488
|
+
if (selectOptsInp) {
|
|
7489
|
+
selectOptsInp.addEventListener('input', function() { applyContentChange('pp-select-options', false); });
|
|
7490
|
+
selectOptsInp.addEventListener('change', function() { applyContentChange('pp-select-options', true); });
|
|
7237
7491
|
}
|
|
7238
7492
|
}
|
|
7239
7493
|
|
|
@@ -7724,14 +7978,21 @@ function attachChangeObserver() {
|
|
|
7724
7978
|
changeObserverDoc = null;
|
|
7725
7979
|
}
|
|
7726
7980
|
changeObserver = new MutationObserver(function(mutations) {
|
|
7981
|
+
if (suppressIframeMutationDirty > 0) return;
|
|
7727
7982
|
var hasMeaningfulMutation = false;
|
|
7728
7983
|
for (var mi = 0; mi < mutations.length; mi++) {
|
|
7729
|
-
if (!
|
|
7984
|
+
if (!isEditorChromeOnlyClassMutation(mutations[mi])) {
|
|
7730
7985
|
hasMeaningfulMutation = true;
|
|
7731
7986
|
break;
|
|
7732
7987
|
}
|
|
7733
7988
|
}
|
|
7734
7989
|
if (!hasMeaningfulMutation) return;
|
|
7990
|
+
var activeId = '';
|
|
7991
|
+
try { activeId = document.activeElement && document.activeElement.id ? String(document.activeElement.id) : ''; } catch(_) {}
|
|
7992
|
+
if (activeId === 'pp-html' || activeId === 'pp-text' || activeId === 'pp-select-options') {
|
|
7993
|
+
scheduleDomTreeRefresh();
|
|
7994
|
+
return;
|
|
7995
|
+
}
|
|
7735
7996
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
7736
7997
|
// Host scripts can replace selected nodes every few frames (e.g. A/B tool observers).
|
|
7737
7998
|
// Keep selection sticky by re-resolving from fingerprint.
|
|
@@ -8227,7 +8488,9 @@ window.addEventListener('load', function() {
|
|
|
8227
8488
|
return;
|
|
8228
8489
|
}
|
|
8229
8490
|
hideIframeLoadError();
|
|
8230
|
-
|
|
8491
|
+
var iframeLiveUrl = '';
|
|
8492
|
+
try { iframeLiveUrl = String(iframe.contentWindow.location.href || ''); } catch(_) {}
|
|
8493
|
+
emitEditorUrlChanged(iframeLiveUrl || docUrl || iframe.src || '');
|
|
8231
8494
|
// Stale events: src may already be the proxy URL while the document is still
|
|
8232
8495
|
// about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
|
|
8233
8496
|
if (docUrl === 'about:blank') {
|
|
@@ -8612,6 +8875,11 @@ function createVisualEditorMiddleware(options) {
|
|
|
8612
8875
|
}
|
|
8613
8876
|
if (chunks.length > 0) requestBody = Buffer.concat(chunks);
|
|
8614
8877
|
}
|
|
8878
|
+
const secFetchMode = (req.headers?.["sec-fetch-mode"] || "").toLowerCase();
|
|
8879
|
+
const secFetchDest = (req.headers?.["sec-fetch-dest"] || "").toLowerCase();
|
|
8880
|
+
const isLikelyDocumentNavigation = secFetchMode === "navigate" || secFetchDest === "iframe" || secFetchDest === "document" || secFetchDest === "nested-document" || secFetchDest === "frame";
|
|
8881
|
+
const isLikelyFetchOrXHR = secFetchDest === "empty" && (secFetchMode === "cors" || secFetchMode === "same-origin" || secFetchMode === "no-cors");
|
|
8882
|
+
const passthroughUpstreamRedirects = (method === "GET" || method === "HEAD") && (isLikelyDocumentNavigation || !isLikelyFetchOrXHR);
|
|
8615
8883
|
const upstreamTimeoutMs = 12e4;
|
|
8616
8884
|
const ac = new AbortController();
|
|
8617
8885
|
const timeoutId = setTimeout(() => ac.abort(), upstreamTimeoutMs);
|
|
@@ -8621,7 +8889,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
8621
8889
|
method,
|
|
8622
8890
|
headers: fetchHeaders,
|
|
8623
8891
|
body: requestBody ? Buffer.from(requestBody) : null,
|
|
8624
|
-
redirect: "follow",
|
|
8892
|
+
redirect: passthroughUpstreamRedirects ? "manual" : "follow",
|
|
8625
8893
|
signal: ac.signal
|
|
8626
8894
|
});
|
|
8627
8895
|
} catch (fetchErr) {
|
|
@@ -8645,12 +8913,43 @@ function createVisualEditorMiddleware(options) {
|
|
|
8645
8913
|
return;
|
|
8646
8914
|
}
|
|
8647
8915
|
clearTimeout(timeoutId);
|
|
8916
|
+
if (passthroughUpstreamRedirects && upstream.status >= 300 && upstream.status < 400) {
|
|
8917
|
+
const locationHeader = upstream.headers.get("location") || upstream.headers.get("Location");
|
|
8918
|
+
if (locationHeader) {
|
|
8919
|
+
try {
|
|
8920
|
+
const redirectTarget = new URL(locationHeader, targetUrl);
|
|
8921
|
+
if (redirectTarget.origin === origin) {
|
|
8922
|
+
const proxyRedirect = new URL(proxyRootForRequest, "http://localhost");
|
|
8923
|
+
proxyRedirect.searchParams.set("password", password);
|
|
8924
|
+
proxyRedirect.searchParams.set("url", redirectTarget.toString());
|
|
8925
|
+
url.searchParams.forEach((value, key) => {
|
|
8926
|
+
if (key === "url" || key === "password") return;
|
|
8927
|
+
proxyRedirect.searchParams.set(key, value);
|
|
8928
|
+
});
|
|
8929
|
+
res.statusCode = upstream.status === 303 ? 303 : 302;
|
|
8930
|
+
res.setHeader("Location", `${proxyRedirect.pathname}${proxyRedirect.search}`);
|
|
8931
|
+
res.setHeader("Cache-Control", "no-store");
|
|
8932
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
8933
|
+
setFrameHeaders(req, res);
|
|
8934
|
+
res.end();
|
|
8935
|
+
return;
|
|
8936
|
+
}
|
|
8937
|
+
res.statusCode = 502;
|
|
8938
|
+
res.setHeader("Content-Type", "application/json");
|
|
8939
|
+
res.end(
|
|
8940
|
+
JSON.stringify({
|
|
8941
|
+
error: "Cross-origin redirect blocked in editor preview",
|
|
8942
|
+
location: redirectTarget.toString(),
|
|
8943
|
+
from: targetUrl
|
|
8944
|
+
})
|
|
8945
|
+
);
|
|
8946
|
+
return;
|
|
8947
|
+
} catch (_) {
|
|
8948
|
+
}
|
|
8949
|
+
}
|
|
8950
|
+
}
|
|
8648
8951
|
const responseContentType = upstream.headers.get("content-type") || "";
|
|
8649
8952
|
const isHtmlResponse = responseContentType.includes("text/html");
|
|
8650
|
-
const secFetchMode = (req.headers?.["sec-fetch-mode"] || "").toLowerCase();
|
|
8651
|
-
const secFetchDest = (req.headers?.["sec-fetch-dest"] || "").toLowerCase();
|
|
8652
|
-
const isLikelyDocumentNavigation = secFetchMode === "navigate" || secFetchDest === "iframe" || secFetchDest === "document" || secFetchDest === "nested-document" || secFetchDest === "frame";
|
|
8653
|
-
const isLikelyFetchOrXHR = secFetchDest === "empty" && (secFetchMode === "cors" || secFetchMode === "same-origin" || secFetchMode === "no-cors");
|
|
8654
8953
|
const shouldInjectHtmlBridge = isHtmlResponse && (isLikelyDocumentNavigation || !isLikelyFetchOrXHR);
|
|
8655
8954
|
if (!isHtmlResponse || !shouldInjectHtmlBridge) {
|
|
8656
8955
|
const binary = Buffer.from(await upstream.arrayBuffer());
|
|
@@ -8704,6 +9003,18 @@ ${iframeAlwaysShowCssGuardScript}
|
|
|
8704
9003
|
/<meta[^>]+name=["']?\s*content-security-policy\s*["']?[^>]*>/gi,
|
|
8705
9004
|
""
|
|
8706
9005
|
);
|
|
9006
|
+
html = html.replace(
|
|
9007
|
+
/(<meta[^>]+http-equiv=["']?refresh["']?[^>]*content=["'][^"']*url=)([^"';]+)(["'][^>]*>)/gi,
|
|
9008
|
+
(match, prefix, urlPart, suffix) => {
|
|
9009
|
+
try {
|
|
9010
|
+
const abs = new URL(String(urlPart).trim(), origin).toString();
|
|
9011
|
+
if (new URL(abs).origin !== origin) return match;
|
|
9012
|
+
return `${prefix}${proxyBase}${encodeURIComponent(abs)}${suffix}`;
|
|
9013
|
+
} catch {
|
|
9014
|
+
return match;
|
|
9015
|
+
}
|
|
9016
|
+
}
|
|
9017
|
+
);
|
|
8707
9018
|
const runtimePreflightScript = `<script>(function(){try{
|
|
8708
9019
|
var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
8709
9020
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
@@ -8910,6 +9221,8 @@ try{if(window.history&&typeof window.history.pushState==="function"){var nativeP
|
|
|
8910
9221
|
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(_){}
|
|
8911
9222
|
try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
8912
9223
|
try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
|
|
9224
|
+
try{window.addEventListener("pageshow",notifyEditorUrlChanged,true);}catch(_){}
|
|
9225
|
+
try{window.addEventListener("load",function(){setTimeout(notifyEditorUrlChanged,0);},true);}catch(_){}
|
|
8913
9226
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
8914
9227
|
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;}}
|
|
8915
9228
|
function toProxy(raw){
|
|
@@ -8938,6 +9251,9 @@ function toProxy(raw){
|
|
|
8938
9251
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
8939
9252
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
8940
9253
|
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;}}
|
|
9254
|
+
function interceptMetaRefresh(){try{var metas=document.querySelectorAll('meta[http-equiv="refresh" i],meta[http-equiv="Refresh"]');for(var i=0;i<metas.length;i++){var content=metas[i].getAttribute("content")||"";var m=content.match(/url=(.+)$/i);if(!m)continue;var raw=m[1].trim().replace(/^['"]|['"]$/g,"");if(safeNavigate(raw,"replace"))metas[i].parentNode&&metas[i].parentNode.removeChild(metas[i]);}}catch(_){}}
|
|
9255
|
+
try{interceptMetaRefresh();}catch(_){}
|
|
9256
|
+
try{document.addEventListener("DOMContentLoaded",interceptMetaRefresh,true);}catch(_){}
|
|
8941
9257
|
try{if(nativeAssign){window.location.assign=function(url){return safeNavigate(url,"assign");};}}catch(_){}
|
|
8942
9258
|
try{if(nativeReplace){window.location.replace=function(url){return safeNavigate(url,"replace");};}}catch(_){}
|
|
8943
9259
|
try{var hrefDesc=Object.getOwnPropertyDescriptor(Location.prototype,"href");if(hrefDesc&&hrefDesc.configurable&&hrefDesc.get&&hrefDesc.set){Object.defineProperty(Location.prototype,"href",{configurable:true,enumerable:hrefDesc.enumerable,get:function(){return hrefDesc.get.call(this);},set:function(v){safeNavigate(v,"assign");}});}}catch(_){}
|