@accelerated-agency/visual-editor 0.6.0 → 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 +334 -28
- package/dist/vite.js +334 -28
- package/package.json +1 -1
package/dist/vite.cjs
CHANGED
|
@@ -3150,6 +3150,7 @@ var PROP_META = {
|
|
|
3150
3150
|
'pp-value': {label:'Value', cssProp:null},
|
|
3151
3151
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
3152
3152
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
3153
|
+
'pp-select-options': {label:'Options', cssProp:null},
|
|
3153
3154
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
3154
3155
|
'pp-tab-css': {label:'Tablet CSS', cssProp:null},
|
|
3155
3156
|
};
|
|
@@ -3166,6 +3167,7 @@ function getOriginalValue(inputId, el) {
|
|
|
3166
3167
|
switch (inputId) {
|
|
3167
3168
|
case 'pp-text': return el.innerText || '';
|
|
3168
3169
|
case 'pp-html': return el.innerHTML || '';
|
|
3170
|
+
case 'pp-select-options': return getSelectOptionsText(el);
|
|
3169
3171
|
case 'pp-cls': return el.className || '';
|
|
3170
3172
|
case 'pp-id': return el.id || '';
|
|
3171
3173
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
@@ -3315,6 +3317,7 @@ function revertChangeOnDom(change) {
|
|
|
3315
3317
|
switch (change.inputId) {
|
|
3316
3318
|
case 'pp-text': el.innerText = orig; break;
|
|
3317
3319
|
case 'pp-html': el.innerHTML = orig; break;
|
|
3320
|
+
case 'pp-select-options': applySelectOptionsFromText(el, orig); break;
|
|
3318
3321
|
case 'pp-cls': el.className = orig; break;
|
|
3319
3322
|
case 'pp-id': el.id = orig; break;
|
|
3320
3323
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
@@ -4973,6 +4976,8 @@ function stateChangeToChainSet(c) {
|
|
|
4973
4976
|
return { selector: c.selector, type: 'content', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4974
4977
|
case 'pp-html':
|
|
4975
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() };
|
|
4976
4981
|
case 'pp-cls':
|
|
4977
4982
|
return { selector: c.selector, type: 'attribute', attribute: 'class', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4978
4983
|
case 'pp-id':
|
|
@@ -5586,6 +5591,10 @@ function setTreeHoverHighlight(el) {
|
|
|
5586
5591
|
}
|
|
5587
5592
|
|
|
5588
5593
|
function isTreeHoverOnlyClassMutation(mutation) {
|
|
5594
|
+
return isEditorChromeOnlyClassMutation(mutation);
|
|
5595
|
+
}
|
|
5596
|
+
|
|
5597
|
+
function isEditorChromeOnlyClassMutation(mutation) {
|
|
5589
5598
|
if (!mutation || mutation.type !== 'attributes' || mutation.attributeName !== 'class') return false;
|
|
5590
5599
|
var oldClass = String(mutation.oldValue || '');
|
|
5591
5600
|
var target = mutation.target;
|
|
@@ -5593,7 +5602,12 @@ function isTreeHoverOnlyClassMutation(mutation) {
|
|
|
5593
5602
|
try {
|
|
5594
5603
|
nextClass = target && typeof target.className === 'string' ? target.className : '';
|
|
5595
5604
|
} catch(_) {}
|
|
5596
|
-
|
|
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
|
+
);
|
|
5597
5611
|
}
|
|
5598
5612
|
|
|
5599
5613
|
function setDragHandleActive(on) {
|
|
@@ -5643,7 +5657,13 @@ function positionSelectionToolbar() {
|
|
|
5643
5657
|
if (!bar || !liveSelected || !iframe || !iframe.contentWindow || !panel) return;
|
|
5644
5658
|
if (selectedEl !== liveSelected) {
|
|
5645
5659
|
selectedEl = liveSelected;
|
|
5646
|
-
|
|
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
|
+
}
|
|
5647
5667
|
syncDomTreeSelection();
|
|
5648
5668
|
}
|
|
5649
5669
|
var elR = getIframeElementVisualRect(selectedEl);
|
|
@@ -6177,19 +6197,149 @@ function renderElementsTree(filterRaw) {
|
|
|
6177
6197
|
return;
|
|
6178
6198
|
}
|
|
6179
6199
|
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
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
|
+
}
|
|
6342
|
+
|
|
6193
6343
|
|
|
6194
6344
|
var nodes = collectEditorInsertedElements(doc);
|
|
6195
6345
|
|
|
@@ -6456,11 +6606,64 @@ function isFormControlElement(el) {
|
|
|
6456
6606
|
function shouldShowInnerContentFields(el) {
|
|
6457
6607
|
if (!el || el.nodeType !== 1) return false;
|
|
6458
6608
|
var tag = (el.tagName || '').toLowerCase();
|
|
6459
|
-
if (tag === 'input' || tag === 'textarea' || tag === 'video') return false;
|
|
6609
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select' || tag === 'video') return false;
|
|
6460
6610
|
if (isEmbeddedVideoIframe(el)) return false;
|
|
6461
6611
|
return true;
|
|
6462
6612
|
}
|
|
6463
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
|
+
|
|
6464
6667
|
function elementHasHtmlChildren(el) {
|
|
6465
6668
|
if (!el || el.nodeType !== 1) return false;
|
|
6466
6669
|
try {
|
|
@@ -7119,6 +7322,12 @@ function renderRightPanel(el, options) {
|
|
|
7119
7322
|
subLbl('Placeholder') +
|
|
7120
7323
|
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
7121
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
|
+
}
|
|
7122
7331
|
if (shouldShowInnerContentFields(el)) {
|
|
7123
7332
|
if (elementHasHtmlChildren(el)) {
|
|
7124
7333
|
contentHtml +=
|
|
@@ -7226,18 +7435,49 @@ function renderRightPanel(el, options) {
|
|
|
7226
7435
|
function wireContentFieldSync(el, sel) {
|
|
7227
7436
|
var textInp = document.getElementById('pp-text');
|
|
7228
7437
|
var htmlInp = document.getElementById('pp-html');
|
|
7438
|
+
var selectOptsInp = document.getElementById('pp-select-options');
|
|
7229
7439
|
var syncing = false;
|
|
7230
|
-
|
|
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) {
|
|
7231
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
|
+
}
|
|
7232
7464
|
syncing = true;
|
|
7233
7465
|
try {
|
|
7234
7466
|
var orig = getOriginalValue(changedId, el);
|
|
7235
7467
|
if (changedId === 'pp-text') {
|
|
7236
|
-
|
|
7468
|
+
beginSuppressIframeMutationDirty();
|
|
7469
|
+
try {
|
|
7470
|
+
el.innerText = textInp.value;
|
|
7471
|
+
} finally {
|
|
7472
|
+
endSuppressIframeMutationDirty();
|
|
7473
|
+
}
|
|
7237
7474
|
if (htmlInp) htmlInp.value = el.innerHTML;
|
|
7238
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);
|
|
7239
7479
|
} else {
|
|
7240
|
-
|
|
7480
|
+
applyHtmlToElement(htmlInp.value);
|
|
7241
7481
|
if (textInp) textInp.value = el.innerText;
|
|
7242
7482
|
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
7243
7483
|
}
|
|
@@ -7250,8 +7490,12 @@ function wireContentFieldSync(el, sel) {
|
|
|
7250
7490
|
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
7251
7491
|
}
|
|
7252
7492
|
if (htmlInp) {
|
|
7253
|
-
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
7254
|
-
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); });
|
|
7255
7499
|
}
|
|
7256
7500
|
}
|
|
7257
7501
|
|
|
@@ -7742,14 +7986,21 @@ function attachChangeObserver() {
|
|
|
7742
7986
|
changeObserverDoc = null;
|
|
7743
7987
|
}
|
|
7744
7988
|
changeObserver = new MutationObserver(function(mutations) {
|
|
7989
|
+
if (suppressIframeMutationDirty > 0) return;
|
|
7745
7990
|
var hasMeaningfulMutation = false;
|
|
7746
7991
|
for (var mi = 0; mi < mutations.length; mi++) {
|
|
7747
|
-
if (!
|
|
7992
|
+
if (!isEditorChromeOnlyClassMutation(mutations[mi])) {
|
|
7748
7993
|
hasMeaningfulMutation = true;
|
|
7749
7994
|
break;
|
|
7750
7995
|
}
|
|
7751
7996
|
}
|
|
7752
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
|
+
}
|
|
7753
8004
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
7754
8005
|
// Host scripts can replace selected nodes every few frames (e.g. A/B tool observers).
|
|
7755
8006
|
// Keep selection sticky by re-resolving from fingerprint.
|
|
@@ -8245,7 +8496,9 @@ window.addEventListener('load', function() {
|
|
|
8245
8496
|
return;
|
|
8246
8497
|
}
|
|
8247
8498
|
hideIframeLoadError();
|
|
8248
|
-
|
|
8499
|
+
var iframeLiveUrl = '';
|
|
8500
|
+
try { iframeLiveUrl = String(iframe.contentWindow.location.href || ''); } catch(_) {}
|
|
8501
|
+
emitEditorUrlChanged(iframeLiveUrl || docUrl || iframe.src || '');
|
|
8249
8502
|
// Stale events: src may already be the proxy URL while the document is still
|
|
8250
8503
|
// about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
|
|
8251
8504
|
if (docUrl === 'about:blank') {
|
|
@@ -8630,6 +8883,11 @@ function createVisualEditorMiddleware(options) {
|
|
|
8630
8883
|
}
|
|
8631
8884
|
if (chunks.length > 0) requestBody = Buffer.concat(chunks);
|
|
8632
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);
|
|
8633
8891
|
const upstreamTimeoutMs = 12e4;
|
|
8634
8892
|
const ac = new AbortController();
|
|
8635
8893
|
const timeoutId = setTimeout(() => ac.abort(), upstreamTimeoutMs);
|
|
@@ -8639,7 +8897,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
8639
8897
|
method,
|
|
8640
8898
|
headers: fetchHeaders,
|
|
8641
8899
|
body: requestBody ? Buffer.from(requestBody) : null,
|
|
8642
|
-
redirect: "follow",
|
|
8900
|
+
redirect: passthroughUpstreamRedirects ? "manual" : "follow",
|
|
8643
8901
|
signal: ac.signal
|
|
8644
8902
|
});
|
|
8645
8903
|
} catch (fetchErr) {
|
|
@@ -8663,12 +8921,43 @@ function createVisualEditorMiddleware(options) {
|
|
|
8663
8921
|
return;
|
|
8664
8922
|
}
|
|
8665
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
|
+
}
|
|
8666
8959
|
const responseContentType = upstream.headers.get("content-type") || "";
|
|
8667
8960
|
const isHtmlResponse = responseContentType.includes("text/html");
|
|
8668
|
-
const secFetchMode = (req.headers?.["sec-fetch-mode"] || "").toLowerCase();
|
|
8669
|
-
const secFetchDest = (req.headers?.["sec-fetch-dest"] || "").toLowerCase();
|
|
8670
|
-
const isLikelyDocumentNavigation = secFetchMode === "navigate" || secFetchDest === "iframe" || secFetchDest === "document" || secFetchDest === "nested-document" || secFetchDest === "frame";
|
|
8671
|
-
const isLikelyFetchOrXHR = secFetchDest === "empty" && (secFetchMode === "cors" || secFetchMode === "same-origin" || secFetchMode === "no-cors");
|
|
8672
8961
|
const shouldInjectHtmlBridge = isHtmlResponse && (isLikelyDocumentNavigation || !isLikelyFetchOrXHR);
|
|
8673
8962
|
if (!isHtmlResponse || !shouldInjectHtmlBridge) {
|
|
8674
8963
|
const binary = Buffer.from(await upstream.arrayBuffer());
|
|
@@ -8722,6 +9011,18 @@ ${iframeAlwaysShowCssGuardScript}
|
|
|
8722
9011
|
/<meta[^>]+name=["']?\s*content-security-policy\s*["']?[^>]*>/gi,
|
|
8723
9012
|
""
|
|
8724
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
|
+
);
|
|
8725
9026
|
const runtimePreflightScript = `<script>(function(){try{
|
|
8726
9027
|
var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
8727
9028
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
@@ -8928,6 +9229,8 @@ try{if(window.history&&typeof window.history.pushState==="function"){var nativeP
|
|
|
8928
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(_){}
|
|
8929
9230
|
try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
8930
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(_){}
|
|
8931
9234
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
8932
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;}}
|
|
8933
9236
|
function toProxy(raw){
|
|
@@ -8956,6 +9259,9 @@ function toProxy(raw){
|
|
|
8956
9259
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
8957
9260
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
8958
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(_){}
|
|
8959
9265
|
try{if(nativeAssign){window.location.assign=function(url){return safeNavigate(url,"assign");};}}catch(_){}
|
|
8960
9266
|
try{if(nativeReplace){window.location.replace=function(url){return safeNavigate(url,"replace");};}}catch(_){}
|
|
8961
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
|
@@ -3142,6 +3142,7 @@ var PROP_META = {
|
|
|
3142
3142
|
'pp-value': {label:'Value', cssProp:null},
|
|
3143
3143
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
3144
3144
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
3145
|
+
'pp-select-options': {label:'Options', cssProp:null},
|
|
3145
3146
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
3146
3147
|
'pp-tab-css': {label:'Tablet CSS', cssProp:null},
|
|
3147
3148
|
};
|
|
@@ -3158,6 +3159,7 @@ function getOriginalValue(inputId, el) {
|
|
|
3158
3159
|
switch (inputId) {
|
|
3159
3160
|
case 'pp-text': return el.innerText || '';
|
|
3160
3161
|
case 'pp-html': return el.innerHTML || '';
|
|
3162
|
+
case 'pp-select-options': return getSelectOptionsText(el);
|
|
3161
3163
|
case 'pp-cls': return el.className || '';
|
|
3162
3164
|
case 'pp-id': return el.id || '';
|
|
3163
3165
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
@@ -3307,6 +3309,7 @@ function revertChangeOnDom(change) {
|
|
|
3307
3309
|
switch (change.inputId) {
|
|
3308
3310
|
case 'pp-text': el.innerText = orig; break;
|
|
3309
3311
|
case 'pp-html': el.innerHTML = orig; break;
|
|
3312
|
+
case 'pp-select-options': applySelectOptionsFromText(el, orig); break;
|
|
3310
3313
|
case 'pp-cls': el.className = orig; break;
|
|
3311
3314
|
case 'pp-id': el.id = orig; break;
|
|
3312
3315
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
@@ -4965,6 +4968,8 @@ function stateChangeToChainSet(c) {
|
|
|
4965
4968
|
return { selector: c.selector, type: 'content', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4966
4969
|
case 'pp-html':
|
|
4967
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() };
|
|
4968
4973
|
case 'pp-cls':
|
|
4969
4974
|
return { selector: c.selector, type: 'attribute', attribute: 'class', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4970
4975
|
case 'pp-id':
|
|
@@ -5578,6 +5583,10 @@ function setTreeHoverHighlight(el) {
|
|
|
5578
5583
|
}
|
|
5579
5584
|
|
|
5580
5585
|
function isTreeHoverOnlyClassMutation(mutation) {
|
|
5586
|
+
return isEditorChromeOnlyClassMutation(mutation);
|
|
5587
|
+
}
|
|
5588
|
+
|
|
5589
|
+
function isEditorChromeOnlyClassMutation(mutation) {
|
|
5581
5590
|
if (!mutation || mutation.type !== 'attributes' || mutation.attributeName !== 'class') return false;
|
|
5582
5591
|
var oldClass = String(mutation.oldValue || '');
|
|
5583
5592
|
var target = mutation.target;
|
|
@@ -5585,7 +5594,12 @@ function isTreeHoverOnlyClassMutation(mutation) {
|
|
|
5585
5594
|
try {
|
|
5586
5595
|
nextClass = target && typeof target.className === 'string' ? target.className : '';
|
|
5587
5596
|
} catch(_) {}
|
|
5588
|
-
|
|
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
|
+
);
|
|
5589
5603
|
}
|
|
5590
5604
|
|
|
5591
5605
|
function setDragHandleActive(on) {
|
|
@@ -5635,7 +5649,13 @@ function positionSelectionToolbar() {
|
|
|
5635
5649
|
if (!bar || !liveSelected || !iframe || !iframe.contentWindow || !panel) return;
|
|
5636
5650
|
if (selectedEl !== liveSelected) {
|
|
5637
5651
|
selectedEl = liveSelected;
|
|
5638
|
-
|
|
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
|
+
}
|
|
5639
5659
|
syncDomTreeSelection();
|
|
5640
5660
|
}
|
|
5641
5661
|
var elR = getIframeElementVisualRect(selectedEl);
|
|
@@ -6169,19 +6189,149 @@ function renderElementsTree(filterRaw) {
|
|
|
6169
6189
|
return;
|
|
6170
6190
|
}
|
|
6171
6191
|
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
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
|
+
}
|
|
6334
|
+
|
|
6185
6335
|
|
|
6186
6336
|
var nodes = collectEditorInsertedElements(doc);
|
|
6187
6337
|
|
|
@@ -6448,11 +6598,64 @@ function isFormControlElement(el) {
|
|
|
6448
6598
|
function shouldShowInnerContentFields(el) {
|
|
6449
6599
|
if (!el || el.nodeType !== 1) return false;
|
|
6450
6600
|
var tag = (el.tagName || '').toLowerCase();
|
|
6451
|
-
if (tag === 'input' || tag === 'textarea' || tag === 'video') return false;
|
|
6601
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select' || tag === 'video') return false;
|
|
6452
6602
|
if (isEmbeddedVideoIframe(el)) return false;
|
|
6453
6603
|
return true;
|
|
6454
6604
|
}
|
|
6455
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
|
+
|
|
6456
6659
|
function elementHasHtmlChildren(el) {
|
|
6457
6660
|
if (!el || el.nodeType !== 1) return false;
|
|
6458
6661
|
try {
|
|
@@ -7111,6 +7314,12 @@ function renderRightPanel(el, options) {
|
|
|
7111
7314
|
subLbl('Placeholder') +
|
|
7112
7315
|
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
7113
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
|
+
}
|
|
7114
7323
|
if (shouldShowInnerContentFields(el)) {
|
|
7115
7324
|
if (elementHasHtmlChildren(el)) {
|
|
7116
7325
|
contentHtml +=
|
|
@@ -7218,18 +7427,49 @@ function renderRightPanel(el, options) {
|
|
|
7218
7427
|
function wireContentFieldSync(el, sel) {
|
|
7219
7428
|
var textInp = document.getElementById('pp-text');
|
|
7220
7429
|
var htmlInp = document.getElementById('pp-html');
|
|
7430
|
+
var selectOptsInp = document.getElementById('pp-select-options');
|
|
7221
7431
|
var syncing = false;
|
|
7222
|
-
|
|
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) {
|
|
7223
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
|
+
}
|
|
7224
7456
|
syncing = true;
|
|
7225
7457
|
try {
|
|
7226
7458
|
var orig = getOriginalValue(changedId, el);
|
|
7227
7459
|
if (changedId === 'pp-text') {
|
|
7228
|
-
|
|
7460
|
+
beginSuppressIframeMutationDirty();
|
|
7461
|
+
try {
|
|
7462
|
+
el.innerText = textInp.value;
|
|
7463
|
+
} finally {
|
|
7464
|
+
endSuppressIframeMutationDirty();
|
|
7465
|
+
}
|
|
7229
7466
|
if (htmlInp) htmlInp.value = el.innerHTML;
|
|
7230
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);
|
|
7231
7471
|
} else {
|
|
7232
|
-
|
|
7472
|
+
applyHtmlToElement(htmlInp.value);
|
|
7233
7473
|
if (textInp) textInp.value = el.innerText;
|
|
7234
7474
|
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
7235
7475
|
}
|
|
@@ -7242,8 +7482,12 @@ function wireContentFieldSync(el, sel) {
|
|
|
7242
7482
|
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
7243
7483
|
}
|
|
7244
7484
|
if (htmlInp) {
|
|
7245
|
-
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
7246
|
-
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); });
|
|
7247
7491
|
}
|
|
7248
7492
|
}
|
|
7249
7493
|
|
|
@@ -7734,14 +7978,21 @@ function attachChangeObserver() {
|
|
|
7734
7978
|
changeObserverDoc = null;
|
|
7735
7979
|
}
|
|
7736
7980
|
changeObserver = new MutationObserver(function(mutations) {
|
|
7981
|
+
if (suppressIframeMutationDirty > 0) return;
|
|
7737
7982
|
var hasMeaningfulMutation = false;
|
|
7738
7983
|
for (var mi = 0; mi < mutations.length; mi++) {
|
|
7739
|
-
if (!
|
|
7984
|
+
if (!isEditorChromeOnlyClassMutation(mutations[mi])) {
|
|
7740
7985
|
hasMeaningfulMutation = true;
|
|
7741
7986
|
break;
|
|
7742
7987
|
}
|
|
7743
7988
|
}
|
|
7744
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
|
+
}
|
|
7745
7996
|
// Dirty state is derived from changesets baseline + stateChanges (not raw DOM mutations).
|
|
7746
7997
|
// Host scripts can replace selected nodes every few frames (e.g. A/B tool observers).
|
|
7747
7998
|
// Keep selection sticky by re-resolving from fingerprint.
|
|
@@ -8237,7 +8488,9 @@ window.addEventListener('load', function() {
|
|
|
8237
8488
|
return;
|
|
8238
8489
|
}
|
|
8239
8490
|
hideIframeLoadError();
|
|
8240
|
-
|
|
8491
|
+
var iframeLiveUrl = '';
|
|
8492
|
+
try { iframeLiveUrl = String(iframe.contentWindow.location.href || ''); } catch(_) {}
|
|
8493
|
+
emitEditorUrlChanged(iframeLiveUrl || docUrl || iframe.src || '');
|
|
8241
8494
|
// Stale events: src may already be the proxy URL while the document is still
|
|
8242
8495
|
// about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
|
|
8243
8496
|
if (docUrl === 'about:blank') {
|
|
@@ -8622,6 +8875,11 @@ function createVisualEditorMiddleware(options) {
|
|
|
8622
8875
|
}
|
|
8623
8876
|
if (chunks.length > 0) requestBody = Buffer.concat(chunks);
|
|
8624
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);
|
|
8625
8883
|
const upstreamTimeoutMs = 12e4;
|
|
8626
8884
|
const ac = new AbortController();
|
|
8627
8885
|
const timeoutId = setTimeout(() => ac.abort(), upstreamTimeoutMs);
|
|
@@ -8631,7 +8889,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
8631
8889
|
method,
|
|
8632
8890
|
headers: fetchHeaders,
|
|
8633
8891
|
body: requestBody ? Buffer.from(requestBody) : null,
|
|
8634
|
-
redirect: "follow",
|
|
8892
|
+
redirect: passthroughUpstreamRedirects ? "manual" : "follow",
|
|
8635
8893
|
signal: ac.signal
|
|
8636
8894
|
});
|
|
8637
8895
|
} catch (fetchErr) {
|
|
@@ -8655,12 +8913,43 @@ function createVisualEditorMiddleware(options) {
|
|
|
8655
8913
|
return;
|
|
8656
8914
|
}
|
|
8657
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
|
+
}
|
|
8658
8951
|
const responseContentType = upstream.headers.get("content-type") || "";
|
|
8659
8952
|
const isHtmlResponse = responseContentType.includes("text/html");
|
|
8660
|
-
const secFetchMode = (req.headers?.["sec-fetch-mode"] || "").toLowerCase();
|
|
8661
|
-
const secFetchDest = (req.headers?.["sec-fetch-dest"] || "").toLowerCase();
|
|
8662
|
-
const isLikelyDocumentNavigation = secFetchMode === "navigate" || secFetchDest === "iframe" || secFetchDest === "document" || secFetchDest === "nested-document" || secFetchDest === "frame";
|
|
8663
|
-
const isLikelyFetchOrXHR = secFetchDest === "empty" && (secFetchMode === "cors" || secFetchMode === "same-origin" || secFetchMode === "no-cors");
|
|
8664
8953
|
const shouldInjectHtmlBridge = isHtmlResponse && (isLikelyDocumentNavigation || !isLikelyFetchOrXHR);
|
|
8665
8954
|
if (!isHtmlResponse || !shouldInjectHtmlBridge) {
|
|
8666
8955
|
const binary = Buffer.from(await upstream.arrayBuffer());
|
|
@@ -8714,6 +9003,18 @@ ${iframeAlwaysShowCssGuardScript}
|
|
|
8714
9003
|
/<meta[^>]+name=["']?\s*content-security-policy\s*["']?[^>]*>/gi,
|
|
8715
9004
|
""
|
|
8716
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
|
+
);
|
|
8717
9018
|
const runtimePreflightScript = `<script>(function(){try{
|
|
8718
9019
|
var TARGET_ORIGIN=${JSON.stringify(origin)};
|
|
8719
9020
|
var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
|
|
@@ -8920,6 +9221,8 @@ try{if(window.history&&typeof window.history.pushState==="function"){var nativeP
|
|
|
8920
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(_){}
|
|
8921
9222
|
try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
8922
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(_){}
|
|
8923
9226
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
8924
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;}}
|
|
8925
9228
|
function toProxy(raw){
|
|
@@ -8948,6 +9251,9 @@ function toProxy(raw){
|
|
|
8948
9251
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
8949
9252
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
8950
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(_){}
|
|
8951
9257
|
try{if(nativeAssign){window.location.assign=function(url){return safeNavigate(url,"assign");};}}catch(_){}
|
|
8952
9258
|
try{if(nativeReplace){window.location.replace=function(url){return safeNavigate(url,"replace");};}}catch(_){}
|
|
8953
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(_){}
|