pi-studio 0.5.50 → 0.5.52
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/CHANGELOG.md +25 -0
- package/README.md +2 -1
- package/client/studio-client.js +811 -92
- package/client/studio.css +98 -29
- package/index.ts +26 -1
- package/package.json +1 -1
package/client/studio-client.js
CHANGED
|
@@ -53,7 +53,9 @@
|
|
|
53
53
|
const lineNumberGutterContentEl = document.getElementById("lineNumberGutterContent");
|
|
54
54
|
const lineNumberMeasureEl = document.getElementById("lineNumberMeasure");
|
|
55
55
|
const sourcePreviewEl = document.getElementById("sourcePreview");
|
|
56
|
+
const editorSelectionActionsEl = document.getElementById("editorSelectionActions");
|
|
56
57
|
const editorSelectionCommentBtn = document.getElementById("editorSelectionCommentBtn");
|
|
58
|
+
const editorSelectionJumpBtn = document.getElementById("editorSelectionJumpBtn");
|
|
57
59
|
const leftPaneEl = document.getElementById("leftPane");
|
|
58
60
|
const rightPaneEl = document.getElementById("rightPane");
|
|
59
61
|
const sourceBadgeEl = document.getElementById("sourceBadge");
|
|
@@ -102,6 +104,7 @@
|
|
|
102
104
|
const leftFocusBtn = document.getElementById("leftFocusBtn");
|
|
103
105
|
const rightFocusBtn = document.getElementById("rightFocusBtn");
|
|
104
106
|
const reviewNotesBtn = document.getElementById("reviewNotesBtn");
|
|
107
|
+
const outlineBtn = document.getElementById("outlineBtn");
|
|
105
108
|
const scratchpadBtn = document.getElementById("scratchpadBtn");
|
|
106
109
|
const scratchpadOverlayEl = document.getElementById("scratchpadOverlay");
|
|
107
110
|
const scratchpadDialogEl = document.getElementById("scratchpadDialog");
|
|
@@ -112,6 +115,13 @@
|
|
|
112
115
|
const scratchpadClearBtn = document.getElementById("scratchpadClearBtn");
|
|
113
116
|
const scratchpadCloseBtn = document.getElementById("scratchpadCloseBtn");
|
|
114
117
|
const scratchpadDoneBtn = document.getElementById("scratchpadDoneBtn");
|
|
118
|
+
const outlineOverlayEl = document.getElementById("outlineOverlay");
|
|
119
|
+
const outlineDialogEl = document.getElementById("outlineDialog");
|
|
120
|
+
const outlineMetaEl = document.getElementById("outlineMeta");
|
|
121
|
+
const outlineListEl = document.getElementById("outlineList");
|
|
122
|
+
const outlineEmptyStateEl = document.getElementById("outlineEmptyState");
|
|
123
|
+
const outlineCloseBtn = document.getElementById("outlineCloseBtn");
|
|
124
|
+
const outlineDoneBtn = document.getElementById("outlineDoneBtn");
|
|
115
125
|
const reviewNotesOverlayEl = document.getElementById("reviewNotesOverlay");
|
|
116
126
|
const reviewNotesDialogEl = document.getElementById("reviewNotesDialog");
|
|
117
127
|
const reviewNotesMetaEl = document.getElementById("reviewNotesMeta");
|
|
@@ -303,6 +313,8 @@
|
|
|
303
313
|
let reviewNotesReturnFocusEl = null;
|
|
304
314
|
let reviewNotesPersistTimer = null;
|
|
305
315
|
let reviewNotesLoadNonce = 0;
|
|
316
|
+
let outlineEntries = [];
|
|
317
|
+
let outlineReturnFocusEl = null;
|
|
306
318
|
let pendingReviewNoteFocusId = null;
|
|
307
319
|
let pendingReviewNoteInlineFocusId = null;
|
|
308
320
|
let activePreviewCommentSelection = null;
|
|
@@ -1128,6 +1140,12 @@
|
|
|
1128
1140
|
&& typeof reviewNotesDialogEl.contains === "function"
|
|
1129
1141
|
&& reviewNotesDialogEl.contains(event.target)
|
|
1130
1142
|
);
|
|
1143
|
+
const outlineOwnsEvent = Boolean(
|
|
1144
|
+
outlineDialogEl
|
|
1145
|
+
&& event.target
|
|
1146
|
+
&& typeof outlineDialogEl.contains === "function"
|
|
1147
|
+
&& outlineDialogEl.contains(event.target)
|
|
1148
|
+
);
|
|
1131
1149
|
|
|
1132
1150
|
if (isScratchpadOpen() && plainEscape) {
|
|
1133
1151
|
event.preventDefault();
|
|
@@ -1141,7 +1159,13 @@
|
|
|
1141
1159
|
return;
|
|
1142
1160
|
}
|
|
1143
1161
|
|
|
1144
|
-
if (
|
|
1162
|
+
if (isOutlineOpen() && plainEscape) {
|
|
1163
|
+
event.preventDefault();
|
|
1164
|
+
closeOutline();
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
if (scratchpadOwnsEvent || reviewNotesOwnsEvent || outlineOwnsEvent) {
|
|
1145
1169
|
return;
|
|
1146
1170
|
}
|
|
1147
1171
|
|
|
@@ -2989,6 +3013,7 @@
|
|
|
2989
3013
|
scheduleEditorMetaUpdate();
|
|
2990
3014
|
}
|
|
2991
3015
|
updateEditorSelectionCommentUi();
|
|
3016
|
+
updateOutlineUi();
|
|
2992
3017
|
}
|
|
2993
3018
|
|
|
2994
3019
|
function setEditorView(nextView) {
|
|
@@ -3023,6 +3048,7 @@
|
|
|
3023
3048
|
}
|
|
3024
3049
|
updateReviewNotesUi();
|
|
3025
3050
|
updateEditorSelectionCommentUi();
|
|
3051
|
+
updateOutlineUi();
|
|
3026
3052
|
}
|
|
3027
3053
|
|
|
3028
3054
|
function setRightView(nextView) {
|
|
@@ -3859,11 +3885,6 @@
|
|
|
3859
3885
|
+ " data-review-note-line-end='" + String(lineNumber) + "'"
|
|
3860
3886
|
+ " data-preview-comment-kind='" + escapeHtml(kind) + "'"
|
|
3861
3887
|
+ ">"
|
|
3862
|
-
+ "<div class='preview-comment-controls'>"
|
|
3863
|
-
+ "<button type='button' class='preview-comment-summary' hidden></button>"
|
|
3864
|
-
+ "<button type='button' class='preview-comment-add' data-preview-comment-action='comment'>Comment</button>"
|
|
3865
|
-
+ "<button type='button' class='preview-comment-jump' data-preview-comment-action='jump'>Jump</button>"
|
|
3866
|
-
+ "</div>"
|
|
3867
3888
|
+ "<div class='preview-comment-block-content preview-code-line-content'>" + lineHtml + "</div>"
|
|
3868
3889
|
+ "</div>",
|
|
3869
3890
|
);
|
|
@@ -3879,6 +3900,7 @@
|
|
|
3879
3900
|
clearPreviewJumpHighlight(targetEl);
|
|
3880
3901
|
finishPreviewRender(targetEl);
|
|
3881
3902
|
targetEl.innerHTML = buildCodePreviewHtmlWithCommentBlocks(text, editorLanguage || "");
|
|
3903
|
+
ensurePreviewSelectionActions(targetEl);
|
|
3882
3904
|
updatePreviewCommentBlocksForElement(targetEl);
|
|
3883
3905
|
if (pane === "response") {
|
|
3884
3906
|
applyPendingResponseScrollReset();
|
|
@@ -4027,6 +4049,10 @@
|
|
|
4027
4049
|
return Boolean(scratchpadOverlayEl && !scratchpadOverlayEl.hidden);
|
|
4028
4050
|
}
|
|
4029
4051
|
|
|
4052
|
+
function isOutlineOpen() {
|
|
4053
|
+
return Boolean(outlineOverlayEl && !outlineOverlayEl.hidden);
|
|
4054
|
+
}
|
|
4055
|
+
|
|
4030
4056
|
function isReviewNotesOpen() {
|
|
4031
4057
|
return Boolean(reviewNotesOverlayEl && !reviewNotesOverlayEl.hidden);
|
|
4032
4058
|
}
|
|
@@ -4200,6 +4226,400 @@
|
|
|
4200
4226
|
};
|
|
4201
4227
|
}
|
|
4202
4228
|
|
|
4229
|
+
function buildOutlineLineIndex(text) {
|
|
4230
|
+
const source = String(text || "").replace(/\r\n/g, "\n");
|
|
4231
|
+
const lines = source.split("\n");
|
|
4232
|
+
const lineOffsets = [];
|
|
4233
|
+
let runningOffset = 0;
|
|
4234
|
+
for (const line of lines) {
|
|
4235
|
+
lineOffsets.push(runningOffset);
|
|
4236
|
+
runningOffset += line.length + 1;
|
|
4237
|
+
}
|
|
4238
|
+
return { source, lines, lineOffsets };
|
|
4239
|
+
}
|
|
4240
|
+
|
|
4241
|
+
function makeOutlineEntry(options) {
|
|
4242
|
+
const entry = options && typeof options === "object" ? options : {};
|
|
4243
|
+
const label = typeof entry.label === "string" ? entry.label.trim() : "";
|
|
4244
|
+
if (!label) return null;
|
|
4245
|
+
const selectionStart = Math.max(0, Math.floor(Number(entry.selectionStart) || 0));
|
|
4246
|
+
const selectionEnd = Math.max(selectionStart, Math.floor(Number(entry.selectionEnd) || selectionStart));
|
|
4247
|
+
return {
|
|
4248
|
+
id: typeof entry.id === "string" && entry.id ? entry.id : makeRequestId(),
|
|
4249
|
+
kind: typeof entry.kind === "string" && entry.kind ? entry.kind : "section",
|
|
4250
|
+
depth: Math.max(1, Math.floor(Number(entry.depth) || 1)),
|
|
4251
|
+
label,
|
|
4252
|
+
lineStart: Math.max(1, Math.floor(Number(entry.lineStart) || 1)),
|
|
4253
|
+
lineEnd: Math.max(Math.max(1, Math.floor(Number(entry.lineStart) || 1)), Math.floor(Number(entry.lineEnd) || Math.max(1, Math.floor(Number(entry.lineStart) || 1)))),
|
|
4254
|
+
selectionStart,
|
|
4255
|
+
selectionEnd,
|
|
4256
|
+
selectedText: typeof entry.selectedText === "string" ? entry.selectedText : "",
|
|
4257
|
+
selectedDisplayText: typeof entry.selectedDisplayText === "string" && entry.selectedDisplayText ? entry.selectedDisplayText : label,
|
|
4258
|
+
};
|
|
4259
|
+
}
|
|
4260
|
+
|
|
4261
|
+
function getOutlineKindLabel(kind) {
|
|
4262
|
+
switch (String(kind || "")) {
|
|
4263
|
+
case "heading": return "Heading";
|
|
4264
|
+
case "section": return "Section";
|
|
4265
|
+
case "subsection": return "Subsection";
|
|
4266
|
+
case "subsubsection": return "Subsubsection";
|
|
4267
|
+
case "paragraph": return "Paragraph";
|
|
4268
|
+
case "subparagraph": return "Subparagraph";
|
|
4269
|
+
case "class": return "Class";
|
|
4270
|
+
case "function": return "Function";
|
|
4271
|
+
case "interface": return "Interface";
|
|
4272
|
+
case "enum": return "Enum";
|
|
4273
|
+
case "type": return "Type";
|
|
4274
|
+
case "struct": return "Struct";
|
|
4275
|
+
case "module": return "Module";
|
|
4276
|
+
case "macro": return "Macro";
|
|
4277
|
+
case "file": return "File";
|
|
4278
|
+
case "hunk": return "Hunk";
|
|
4279
|
+
default: return "Item";
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
|
|
4283
|
+
function getOutlineKindBadge(kind) {
|
|
4284
|
+
switch (String(kind || "")) {
|
|
4285
|
+
case "section": return "§";
|
|
4286
|
+
case "subsection": return "§§";
|
|
4287
|
+
case "subsubsection": return "§3";
|
|
4288
|
+
case "paragraph": return "¶";
|
|
4289
|
+
case "subparagraph": return "¶2";
|
|
4290
|
+
case "class": return "class";
|
|
4291
|
+
case "function": return "def";
|
|
4292
|
+
case "interface": return "iface";
|
|
4293
|
+
case "enum": return "enum";
|
|
4294
|
+
case "type": return "type";
|
|
4295
|
+
case "struct": return "struct";
|
|
4296
|
+
case "module": return "mod";
|
|
4297
|
+
case "macro": return "macro";
|
|
4298
|
+
case "file": return "file";
|
|
4299
|
+
case "hunk": return "@@";
|
|
4300
|
+
default: return "#";
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
|
|
4304
|
+
function scanMarkdownOutlineEntries(text) {
|
|
4305
|
+
const { source, lines, lineOffsets } = buildOutlineLineIndex(text);
|
|
4306
|
+
const entries = [];
|
|
4307
|
+
let activeFence = null;
|
|
4308
|
+
|
|
4309
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4310
|
+
const line = String(lines[lineIndex] || "");
|
|
4311
|
+
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
4312
|
+
if (fenceMatch) {
|
|
4313
|
+
if (!activeFence) {
|
|
4314
|
+
activeFence = fenceMatch[1];
|
|
4315
|
+
} else if (fenceMatch[1][0] === activeFence[0] && fenceMatch[1].length >= activeFence.length) {
|
|
4316
|
+
activeFence = null;
|
|
4317
|
+
}
|
|
4318
|
+
continue;
|
|
4319
|
+
}
|
|
4320
|
+
if (activeFence) continue;
|
|
4321
|
+
|
|
4322
|
+
const atxMatch = line.match(/^ {0,3}(#{1,6})[ \t]+(.+?)(?:[ \t]+#+[ \t]*)?$/);
|
|
4323
|
+
if (atxMatch) {
|
|
4324
|
+
const label = normalizeVisiblePreviewText(atxMatch[2] || "");
|
|
4325
|
+
const entry = makeOutlineEntry({
|
|
4326
|
+
kind: atxMatch[1].length === 1 ? "section" : atxMatch[1].length === 2 ? "subsection" : atxMatch[1].length === 3 ? "subsubsection" : "heading",
|
|
4327
|
+
depth: atxMatch[1].length,
|
|
4328
|
+
label,
|
|
4329
|
+
lineStart: lineIndex + 1,
|
|
4330
|
+
lineEnd: lineIndex + 1,
|
|
4331
|
+
selectionStart: lineOffsets[lineIndex] || 0,
|
|
4332
|
+
selectionEnd: (lineOffsets[lineIndex] || 0) + line.length,
|
|
4333
|
+
selectedText: line,
|
|
4334
|
+
selectedDisplayText: label,
|
|
4335
|
+
});
|
|
4336
|
+
if (entry) entries.push(entry);
|
|
4337
|
+
continue;
|
|
4338
|
+
}
|
|
4339
|
+
|
|
4340
|
+
const nextLine = lineIndex + 1 < lines.length ? String(lines[lineIndex + 1] || "") : "";
|
|
4341
|
+
const setextMatch = nextLine.match(/^ {0,3}(=+|-+)\s*$/);
|
|
4342
|
+
if (setextMatch && normalizeVisiblePreviewText(line)) {
|
|
4343
|
+
const depth = setextMatch[1][0] === "=" ? 1 : 2;
|
|
4344
|
+
const label = normalizeVisiblePreviewText(line);
|
|
4345
|
+
const entry = makeOutlineEntry({
|
|
4346
|
+
kind: depth === 1 ? "section" : "subsection",
|
|
4347
|
+
depth,
|
|
4348
|
+
label,
|
|
4349
|
+
lineStart: lineIndex + 1,
|
|
4350
|
+
lineEnd: lineIndex + 1,
|
|
4351
|
+
selectionStart: lineOffsets[lineIndex] || 0,
|
|
4352
|
+
selectionEnd: (lineOffsets[lineIndex] || 0) + line.length,
|
|
4353
|
+
selectedText: line,
|
|
4354
|
+
selectedDisplayText: label,
|
|
4355
|
+
});
|
|
4356
|
+
if (entry) entries.push(entry);
|
|
4357
|
+
lineIndex += 1;
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
return entries;
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
const LATEX_OUTLINE_LEVEL_BY_COMMAND = {
|
|
4365
|
+
part: 1,
|
|
4366
|
+
chapter: 1,
|
|
4367
|
+
section: 1,
|
|
4368
|
+
subsection: 2,
|
|
4369
|
+
subsubsection: 3,
|
|
4370
|
+
paragraph: 4,
|
|
4371
|
+
subparagraph: 5,
|
|
4372
|
+
};
|
|
4373
|
+
|
|
4374
|
+
function scanLatexOutlineEntries(text) {
|
|
4375
|
+
const source = String(text || "").replace(/\r\n/g, "\n");
|
|
4376
|
+
const bodyRange = findLatexDocumentBodyRange(source);
|
|
4377
|
+
const bodyStart = Math.max(0, Math.min(bodyRange.start, source.length));
|
|
4378
|
+
const bodyEnd = Math.max(bodyStart, Math.min(bodyRange.end, source.length));
|
|
4379
|
+
const bodyText = source.slice(bodyStart, bodyEnd);
|
|
4380
|
+
const { lines, lineOffsets } = buildOutlineLineIndex(bodyText);
|
|
4381
|
+
const entries = [];
|
|
4382
|
+
|
|
4383
|
+
function getLine(index) {
|
|
4384
|
+
return index >= 0 && index < lines.length ? String(lines[index] || "") : "";
|
|
4385
|
+
}
|
|
4386
|
+
|
|
4387
|
+
function getStrippedLine(index) {
|
|
4388
|
+
return stripLatexPreviewComments(getLine(index)).trim();
|
|
4389
|
+
}
|
|
4390
|
+
|
|
4391
|
+
function isBibliographyCommandLine(index) {
|
|
4392
|
+
return /^\\(?:bibliographystyle|bibliography|printbibliography)\b/i.test(getStrippedLine(index));
|
|
4393
|
+
}
|
|
4394
|
+
|
|
4395
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4396
|
+
let chunk = getLine(lineIndex);
|
|
4397
|
+
let endLineIndex = lineIndex;
|
|
4398
|
+
let heading = readLatexHeadingChunk(chunk);
|
|
4399
|
+
if (/^\s*\\(?:part|chapter|section|subsection|subsubsection|paragraph|subparagraph)\b/.test(chunk)) {
|
|
4400
|
+
while (!heading && endLineIndex + 1 < lines.length && endLineIndex < lineIndex + 5) {
|
|
4401
|
+
endLineIndex += 1;
|
|
4402
|
+
chunk += "\n" + getLine(endLineIndex);
|
|
4403
|
+
heading = readLatexHeadingChunk(chunk);
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
if (heading) {
|
|
4407
|
+
const label = extractLatexPreviewVisibleText(heading.titleText || "");
|
|
4408
|
+
const kind = String(heading.commandName || "section").replace(/\*$/, "").toLowerCase();
|
|
4409
|
+
const entry = makeOutlineEntry({
|
|
4410
|
+
kind,
|
|
4411
|
+
depth: LATEX_OUTLINE_LEVEL_BY_COMMAND[kind] || 1,
|
|
4412
|
+
label,
|
|
4413
|
+
lineStart: lineIndex + 1,
|
|
4414
|
+
lineEnd: endLineIndex + 1,
|
|
4415
|
+
selectionStart: bodyStart + (lineOffsets[lineIndex] || 0),
|
|
4416
|
+
selectionEnd: bodyStart + (lineOffsets[endLineIndex] || 0) + getLine(endLineIndex).length,
|
|
4417
|
+
selectedText: source.slice(bodyStart + (lineOffsets[lineIndex] || 0), bodyStart + (lineOffsets[endLineIndex] || 0) + getLine(endLineIndex).length),
|
|
4418
|
+
selectedDisplayText: label,
|
|
4419
|
+
});
|
|
4420
|
+
if (entry) entries.push(entry);
|
|
4421
|
+
lineIndex = endLineIndex;
|
|
4422
|
+
continue;
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4425
|
+
if (isBibliographyCommandLine(lineIndex)) {
|
|
4426
|
+
let endLine = lineIndex;
|
|
4427
|
+
while (endLine + 1 < lines.length && isBibliographyCommandLine(endLine + 1)) {
|
|
4428
|
+
endLine += 1;
|
|
4429
|
+
}
|
|
4430
|
+
const entry = makeOutlineEntry({
|
|
4431
|
+
kind: "section",
|
|
4432
|
+
depth: 1,
|
|
4433
|
+
label: "References",
|
|
4434
|
+
lineStart: lineIndex + 1,
|
|
4435
|
+
lineEnd: endLine + 1,
|
|
4436
|
+
selectionStart: bodyStart + (lineOffsets[lineIndex] || 0),
|
|
4437
|
+
selectionEnd: bodyStart + (lineOffsets[endLine] || 0) + getLine(endLine).length,
|
|
4438
|
+
selectedText: source.slice(bodyStart + (lineOffsets[lineIndex] || 0), bodyStart + (lineOffsets[endLine] || 0) + getLine(endLine).length),
|
|
4439
|
+
selectedDisplayText: "References",
|
|
4440
|
+
});
|
|
4441
|
+
if (entry) entries.push(entry);
|
|
4442
|
+
lineIndex = endLine;
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
return entries;
|
|
4447
|
+
}
|
|
4448
|
+
|
|
4449
|
+
function scanPythonOutlineEntries(text) {
|
|
4450
|
+
const { lines, lineOffsets } = buildOutlineLineIndex(text);
|
|
4451
|
+
const entries = [];
|
|
4452
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4453
|
+
const line = String(lines[lineIndex] || "");
|
|
4454
|
+
const classMatch = line.match(/^(\s*)class\s+([A-Za-z_][A-Za-z0-9_]*)\b/);
|
|
4455
|
+
const defMatch = line.match(/^(\s*)(?:async\s+def|def)\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/);
|
|
4456
|
+
const match = classMatch || defMatch;
|
|
4457
|
+
if (!match) continue;
|
|
4458
|
+
const indent = String(match[1] || "").replace(/\t/g, " ").length;
|
|
4459
|
+
const label = String(match[2] || "");
|
|
4460
|
+
const kind = classMatch ? "class" : "function";
|
|
4461
|
+
const entry = makeOutlineEntry({
|
|
4462
|
+
kind,
|
|
4463
|
+
depth: Math.max(1, Math.floor(indent / 4) + 1),
|
|
4464
|
+
label,
|
|
4465
|
+
lineStart: lineIndex + 1,
|
|
4466
|
+
lineEnd: lineIndex + 1,
|
|
4467
|
+
selectionStart: lineOffsets[lineIndex] || 0,
|
|
4468
|
+
selectionEnd: (lineOffsets[lineIndex] || 0) + line.length,
|
|
4469
|
+
selectedText: line,
|
|
4470
|
+
selectedDisplayText: label,
|
|
4471
|
+
});
|
|
4472
|
+
if (entry) entries.push(entry);
|
|
4473
|
+
}
|
|
4474
|
+
return entries;
|
|
4475
|
+
}
|
|
4476
|
+
|
|
4477
|
+
function scanJsLikeOutlineEntries(text) {
|
|
4478
|
+
const { lines, lineOffsets } = buildOutlineLineIndex(text);
|
|
4479
|
+
const entries = [];
|
|
4480
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4481
|
+
const line = String(lines[lineIndex] || "");
|
|
4482
|
+
const patterns = [
|
|
4483
|
+
{ kind: "class", match: line.match(/^(\s*)(?:export\s+)?(?:default\s+)?class\s+([A-Za-z_$][A-Za-z0-9_$]*)\b/) },
|
|
4484
|
+
{ kind: "function", match: line.match(/^(\s*)(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*\(/) },
|
|
4485
|
+
{ kind: "function", match: line.match(/^(\s*)(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][A-Za-z0-9_$]*)\s*=>/) },
|
|
4486
|
+
{ kind: "interface", match: line.match(/^(\s*)(?:export\s+)?interface\s+([A-Za-z_$][A-Za-z0-9_$]*)\b/) },
|
|
4487
|
+
{ kind: "enum", match: line.match(/^(\s*)(?:export\s+)?enum\s+([A-Za-z_$][A-Za-z0-9_$]*)\b/) },
|
|
4488
|
+
{ kind: "type", match: line.match(/^(\s*)(?:export\s+)?type\s+([A-Za-z_$][A-Za-z0-9_$]*)\b/) },
|
|
4489
|
+
];
|
|
4490
|
+
const found = patterns.find((entry) => entry.match);
|
|
4491
|
+
if (!found || !found.match) continue;
|
|
4492
|
+
const indent = String(found.match[1] || "").replace(/\t/g, " ").length;
|
|
4493
|
+
const label = String(found.match[2] || "");
|
|
4494
|
+
const entry = makeOutlineEntry({
|
|
4495
|
+
kind: found.kind,
|
|
4496
|
+
depth: Math.max(1, Math.floor(indent / 2) + 1),
|
|
4497
|
+
label,
|
|
4498
|
+
lineStart: lineIndex + 1,
|
|
4499
|
+
lineEnd: lineIndex + 1,
|
|
4500
|
+
selectionStart: lineOffsets[lineIndex] || 0,
|
|
4501
|
+
selectionEnd: (lineOffsets[lineIndex] || 0) + line.length,
|
|
4502
|
+
selectedText: line,
|
|
4503
|
+
selectedDisplayText: label,
|
|
4504
|
+
});
|
|
4505
|
+
if (entry) entries.push(entry);
|
|
4506
|
+
}
|
|
4507
|
+
return entries;
|
|
4508
|
+
}
|
|
4509
|
+
|
|
4510
|
+
function scanJuliaOutlineEntries(text) {
|
|
4511
|
+
const { lines, lineOffsets } = buildOutlineLineIndex(text);
|
|
4512
|
+
const entries = [];
|
|
4513
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4514
|
+
const line = String(lines[lineIndex] || "");
|
|
4515
|
+
const patterns = [
|
|
4516
|
+
{ kind: "module", match: line.match(/^(\s*)module\s+([A-Za-z_][A-Za-z0-9_]*)\b/) },
|
|
4517
|
+
{ kind: "struct", match: line.match(/^(\s*)(?:mutable\s+)?struct\s+([A-Za-z_][A-Za-z0-9_]*)\b/) },
|
|
4518
|
+
{ kind: "function", match: line.match(/^(\s*)function\s+([A-Za-z_][A-Za-z0-9_!]*)\s*\(/) },
|
|
4519
|
+
{ kind: "macro", match: line.match(/^(\s*)macro\s+([A-Za-z_][A-Za-z0-9_!]*)\b/) },
|
|
4520
|
+
];
|
|
4521
|
+
const found = patterns.find((entry) => entry.match);
|
|
4522
|
+
if (!found || !found.match) continue;
|
|
4523
|
+
const indent = String(found.match[1] || "").replace(/\t/g, " ").length;
|
|
4524
|
+
const label = String(found.match[2] || "");
|
|
4525
|
+
const entry = makeOutlineEntry({
|
|
4526
|
+
kind: found.kind,
|
|
4527
|
+
depth: Math.max(1, Math.floor(indent / 2) + 1),
|
|
4528
|
+
label,
|
|
4529
|
+
lineStart: lineIndex + 1,
|
|
4530
|
+
lineEnd: lineIndex + 1,
|
|
4531
|
+
selectionStart: lineOffsets[lineIndex] || 0,
|
|
4532
|
+
selectionEnd: (lineOffsets[lineIndex] || 0) + line.length,
|
|
4533
|
+
selectedText: line,
|
|
4534
|
+
selectedDisplayText: label,
|
|
4535
|
+
});
|
|
4536
|
+
if (entry) entries.push(entry);
|
|
4537
|
+
}
|
|
4538
|
+
return entries;
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4541
|
+
function scanBashOutlineEntries(text) {
|
|
4542
|
+
const { lines, lineOffsets } = buildOutlineLineIndex(text);
|
|
4543
|
+
const entries = [];
|
|
4544
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4545
|
+
const line = String(lines[lineIndex] || "");
|
|
4546
|
+
const match = line.match(/^(\s*)(?:function\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*\(\)\s*\{/);
|
|
4547
|
+
if (!match) continue;
|
|
4548
|
+
const indent = String(match[1] || "").replace(/\t/g, " ").length;
|
|
4549
|
+
const label = String(match[2] || "");
|
|
4550
|
+
const entry = makeOutlineEntry({
|
|
4551
|
+
kind: "function",
|
|
4552
|
+
depth: Math.max(1, Math.floor(indent / 2) + 1),
|
|
4553
|
+
label,
|
|
4554
|
+
lineStart: lineIndex + 1,
|
|
4555
|
+
lineEnd: lineIndex + 1,
|
|
4556
|
+
selectionStart: lineOffsets[lineIndex] || 0,
|
|
4557
|
+
selectionEnd: (lineOffsets[lineIndex] || 0) + line.length,
|
|
4558
|
+
selectedText: line,
|
|
4559
|
+
selectedDisplayText: label,
|
|
4560
|
+
});
|
|
4561
|
+
if (entry) entries.push(entry);
|
|
4562
|
+
}
|
|
4563
|
+
return entries;
|
|
4564
|
+
}
|
|
4565
|
+
|
|
4566
|
+
function scanDiffOutlineEntries(text) {
|
|
4567
|
+
const { lines, lineOffsets } = buildOutlineLineIndex(text);
|
|
4568
|
+
const entries = [];
|
|
4569
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4570
|
+
const line = String(lines[lineIndex] || "");
|
|
4571
|
+
let kind = "";
|
|
4572
|
+
let label = "";
|
|
4573
|
+
let depth = 1;
|
|
4574
|
+
const fileMatch = line.match(/^diff\s+--git\s+a\/([^\s]+)\s+b\/([^\s]+)/);
|
|
4575
|
+
if (fileMatch) {
|
|
4576
|
+
kind = "file";
|
|
4577
|
+
label = String(fileMatch[2] || fileMatch[1] || "");
|
|
4578
|
+
depth = 1;
|
|
4579
|
+
} else if (/^@@/.test(line)) {
|
|
4580
|
+
kind = "hunk";
|
|
4581
|
+
label = line.replace(/^@@\s*|\s*@@.*$/g, "").trim() || line.trim();
|
|
4582
|
+
depth = 2;
|
|
4583
|
+
}
|
|
4584
|
+
if (!kind || !label) continue;
|
|
4585
|
+
const entry = makeOutlineEntry({
|
|
4586
|
+
kind,
|
|
4587
|
+
depth,
|
|
4588
|
+
label,
|
|
4589
|
+
lineStart: lineIndex + 1,
|
|
4590
|
+
lineEnd: lineIndex + 1,
|
|
4591
|
+
selectionStart: lineOffsets[lineIndex] || 0,
|
|
4592
|
+
selectionEnd: (lineOffsets[lineIndex] || 0) + line.length,
|
|
4593
|
+
selectedText: line,
|
|
4594
|
+
selectedDisplayText: label,
|
|
4595
|
+
});
|
|
4596
|
+
if (entry) entries.push(entry);
|
|
4597
|
+
}
|
|
4598
|
+
return entries;
|
|
4599
|
+
}
|
|
4600
|
+
|
|
4601
|
+
function scanOutlineEntries(text, language) {
|
|
4602
|
+
switch (String(language || "").toLowerCase()) {
|
|
4603
|
+
case "markdown":
|
|
4604
|
+
return scanMarkdownOutlineEntries(text);
|
|
4605
|
+
case "latex":
|
|
4606
|
+
return scanLatexOutlineEntries(text);
|
|
4607
|
+
case "python":
|
|
4608
|
+
return scanPythonOutlineEntries(text);
|
|
4609
|
+
case "javascript":
|
|
4610
|
+
case "typescript":
|
|
4611
|
+
return scanJsLikeOutlineEntries(text);
|
|
4612
|
+
case "julia":
|
|
4613
|
+
return scanJuliaOutlineEntries(text);
|
|
4614
|
+
case "bash":
|
|
4615
|
+
return scanBashOutlineEntries(text);
|
|
4616
|
+
case "diff":
|
|
4617
|
+
return scanDiffOutlineEntries(text);
|
|
4618
|
+
default:
|
|
4619
|
+
return [];
|
|
4620
|
+
}
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4203
4623
|
function cloneReviewNotes(notes) {
|
|
4204
4624
|
return Array.isArray(notes)
|
|
4205
4625
|
? notes
|
|
@@ -5575,8 +5995,23 @@
|
|
|
5575
5995
|
return bestIndex;
|
|
5576
5996
|
}
|
|
5577
5997
|
|
|
5998
|
+
function buildLiteralPreviewDisplayMap(text, rawOffsets) {
|
|
5999
|
+
const source = String(text || "");
|
|
6000
|
+
const rawMap = Array.isArray(rawOffsets) ? rawOffsets : [];
|
|
6001
|
+
const charStarts = [];
|
|
6002
|
+
const charEnds = [];
|
|
6003
|
+
for (let i = 0; i < source.length; i += 1) {
|
|
6004
|
+
charStarts.push(rawMap[i]);
|
|
6005
|
+
charEnds.push(rawMap[i] + 1);
|
|
6006
|
+
}
|
|
6007
|
+
return buildNormalizedPreviewDisplayMap(source, charStarts, charEnds);
|
|
6008
|
+
}
|
|
6009
|
+
|
|
5578
6010
|
function buildPreviewSelectionDisplayMap(blockText, kind) {
|
|
5579
6011
|
const body = buildPreviewSelectionSourceBody(blockText, kind);
|
|
6012
|
+
if (kind === "code-line" || kind === "diff-line" || kind === "text-line") {
|
|
6013
|
+
return buildLiteralPreviewDisplayMap(body.text, body.rawOffsets);
|
|
6014
|
+
}
|
|
5580
6015
|
const inlineMap = buildPreviewInlineDisplayMap(body.text, body.rawOffsets);
|
|
5581
6016
|
return buildNormalizedPreviewDisplayMap(inlineMap.text, inlineMap.charStarts, inlineMap.charEnds);
|
|
5582
6017
|
}
|
|
@@ -5593,6 +6028,7 @@
|
|
|
5593
6028
|
function getPreviewCommentSelectionKey(selection) {
|
|
5594
6029
|
if (!selection) return "";
|
|
5595
6030
|
return [
|
|
6031
|
+
String(selection.paneId || ""),
|
|
5596
6032
|
String(selection.blockKey || ""),
|
|
5597
6033
|
String(selection.selectionStart || 0),
|
|
5598
6034
|
String(selection.selectionEnd || 0),
|
|
@@ -5620,6 +6056,96 @@
|
|
|
5620
6056
|
: null;
|
|
5621
6057
|
}
|
|
5622
6058
|
|
|
6059
|
+
function getPreviewSelectionPaneIdForNode(node) {
|
|
6060
|
+
if (!node) return "";
|
|
6061
|
+
const element = node instanceof Element ? node : node.parentElement;
|
|
6062
|
+
const paneEl = element && typeof element.closest === "function"
|
|
6063
|
+
? element.closest("#sourcePreview, #critiqueView")
|
|
6064
|
+
: null;
|
|
6065
|
+
return paneEl && paneEl.id ? String(paneEl.id) : "";
|
|
6066
|
+
}
|
|
6067
|
+
|
|
6068
|
+
function getPreviewSelectionPaneElement(paneId) {
|
|
6069
|
+
if (paneId === "sourcePreview") return sourcePreviewEl;
|
|
6070
|
+
if (paneId === "critiqueView") return critiqueViewEl;
|
|
6071
|
+
return null;
|
|
6072
|
+
}
|
|
6073
|
+
|
|
6074
|
+
function getActivePreviewSelectionForPane(paneId) {
|
|
6075
|
+
if (!paneId) return null;
|
|
6076
|
+
return activePreviewCommentSelection && activePreviewCommentSelection.paneId === paneId
|
|
6077
|
+
? activePreviewCommentSelection
|
|
6078
|
+
: null;
|
|
6079
|
+
}
|
|
6080
|
+
|
|
6081
|
+
function ensurePreviewSelectionActions(targetEl) {
|
|
6082
|
+
if (!targetEl || typeof document.createElement !== "function") return null;
|
|
6083
|
+
const paneId = targetEl.id ? String(targetEl.id) : "";
|
|
6084
|
+
if (!paneId) return null;
|
|
6085
|
+
const existing = Array.from(targetEl.children || []).find((child) => child.classList && child.classList.contains("preview-selection-actions"));
|
|
6086
|
+
if (existing) {
|
|
6087
|
+
existing.dataset.previewPane = paneId;
|
|
6088
|
+
return existing;
|
|
6089
|
+
}
|
|
6090
|
+
|
|
6091
|
+
const actionsEl = document.createElement("div");
|
|
6092
|
+
actionsEl.className = "preview-selection-actions";
|
|
6093
|
+
actionsEl.dataset.previewPane = paneId;
|
|
6094
|
+
actionsEl.hidden = true;
|
|
6095
|
+
|
|
6096
|
+
const commentBtn = document.createElement("button");
|
|
6097
|
+
commentBtn.type = "button";
|
|
6098
|
+
commentBtn.className = "preview-comment-add";
|
|
6099
|
+
commentBtn.dataset.previewCommentAction = "comment";
|
|
6100
|
+
commentBtn.textContent = "Comment";
|
|
6101
|
+
commentBtn.hidden = true;
|
|
6102
|
+
actionsEl.appendChild(commentBtn);
|
|
6103
|
+
|
|
6104
|
+
const jumpBtn = document.createElement("button");
|
|
6105
|
+
jumpBtn.type = "button";
|
|
6106
|
+
jumpBtn.className = "preview-comment-jump";
|
|
6107
|
+
jumpBtn.dataset.previewCommentAction = "jump";
|
|
6108
|
+
jumpBtn.textContent = "Jump";
|
|
6109
|
+
jumpBtn.hidden = true;
|
|
6110
|
+
actionsEl.appendChild(jumpBtn);
|
|
6111
|
+
|
|
6112
|
+
targetEl.insertBefore(actionsEl, targetEl.firstChild || null);
|
|
6113
|
+
return actionsEl;
|
|
6114
|
+
}
|
|
6115
|
+
|
|
6116
|
+
function updatePreviewSelectionActions(targetEl) {
|
|
6117
|
+
if (!targetEl) return;
|
|
6118
|
+
const actionsEl = ensurePreviewSelectionActions(targetEl);
|
|
6119
|
+
if (!actionsEl) return;
|
|
6120
|
+
const paneId = targetEl.id ? String(targetEl.id) : "";
|
|
6121
|
+
const selection = getActivePreviewSelectionForPane(paneId);
|
|
6122
|
+
const commentBtn = actionsEl.querySelector(".preview-comment-add");
|
|
6123
|
+
const jumpBtn = actionsEl.querySelector(".preview-comment-jump");
|
|
6124
|
+
if (!selection) {
|
|
6125
|
+
actionsEl.hidden = true;
|
|
6126
|
+
if (commentBtn) commentBtn.hidden = true;
|
|
6127
|
+
if (jumpBtn) jumpBtn.hidden = true;
|
|
6128
|
+
return;
|
|
6129
|
+
}
|
|
6130
|
+
const lineLabel = summarizeReviewNoteAnchor(selection).toLowerCase();
|
|
6131
|
+
const blockKindLabel = getPreviewCommentBlockKindLabel(selection.previewCommentKind || "paragraph");
|
|
6132
|
+
actionsEl.hidden = false;
|
|
6133
|
+
if (commentBtn) {
|
|
6134
|
+
commentBtn.hidden = false;
|
|
6135
|
+
commentBtn.dataset.previewCommentMode = "selection";
|
|
6136
|
+
commentBtn.dataset.previewPane = paneId;
|
|
6137
|
+
commentBtn.title = "Add a local comment from the current preview selection on this " + blockKindLabel + " (" + lineLabel + ").";
|
|
6138
|
+
commentBtn.setAttribute("aria-label", commentBtn.title || "Comment");
|
|
6139
|
+
}
|
|
6140
|
+
if (jumpBtn) {
|
|
6141
|
+
jumpBtn.hidden = false;
|
|
6142
|
+
jumpBtn.dataset.previewCommentMode = "selection";
|
|
6143
|
+
jumpBtn.dataset.previewPane = paneId;
|
|
6144
|
+
jumpBtn.title = "Jump to the current preview selection on this " + blockKindLabel + " in the raw editor (" + lineLabel + ").";
|
|
6145
|
+
jumpBtn.setAttribute("aria-label", jumpBtn.title || "Jump");
|
|
6146
|
+
}
|
|
6147
|
+
}
|
|
6148
|
+
|
|
5623
6149
|
function unwrapPreviewJumpHighlightElement(element) {
|
|
5624
6150
|
if (!element || !element.parentNode) return;
|
|
5625
6151
|
const parent = element.parentNode;
|
|
@@ -6449,52 +6975,26 @@
|
|
|
6449
6975
|
|
|
6450
6976
|
function updatePreviewCommentBlockState(blockEl, sourceText, displayNotes) {
|
|
6451
6977
|
if (!blockEl || !blockEl.dataset) return;
|
|
6452
|
-
const lineStart = Math.max(1, Number(blockEl.dataset.reviewNoteLineStart) || 1);
|
|
6453
|
-
const lineEnd = Math.max(lineStart, Number(blockEl.dataset.reviewNoteLineEnd) || lineStart);
|
|
6454
|
-
const summaryBtn = blockEl.querySelector(".preview-comment-summary");
|
|
6455
|
-
const addBtn = blockEl.querySelector(".preview-comment-add");
|
|
6456
|
-
const jumpBtn = blockEl.querySelector(".preview-comment-jump");
|
|
6457
|
-
const lineLabel = summarizeReviewNoteAnchor({ lineStart: lineStart, lineEnd: lineEnd }).toLowerCase();
|
|
6458
|
-
const blockKindLabel = getPreviewCommentBlockKindLabel(blockEl.dataset.previewCommentKind || "paragraph");
|
|
6459
6978
|
const blockKey = getPreviewCommentBlockKey(blockEl);
|
|
6460
|
-
const
|
|
6979
|
+
const paneId = getPreviewSelectionPaneIdForNode(blockEl);
|
|
6980
|
+
const hasSelection = Boolean(
|
|
6981
|
+
activePreviewCommentSelection
|
|
6982
|
+
&& activePreviewCommentSelection.paneId === paneId
|
|
6983
|
+
&& activePreviewCommentSelection.blockKey === blockKey
|
|
6984
|
+
);
|
|
6461
6985
|
|
|
6462
6986
|
blockEl.classList.remove("has-comments");
|
|
6463
6987
|
blockEl.classList.toggle("has-selection", hasSelection);
|
|
6464
|
-
|
|
6465
|
-
if (summaryBtn) {
|
|
6466
|
-
summaryBtn.hidden = true;
|
|
6467
|
-
summaryBtn.textContent = "";
|
|
6468
|
-
summaryBtn.dataset.reviewNoteId = "";
|
|
6469
|
-
}
|
|
6470
|
-
|
|
6471
|
-
if (addBtn) {
|
|
6472
|
-
addBtn.hidden = !hasSelection;
|
|
6473
|
-
addBtn.textContent = "Comment";
|
|
6474
|
-
addBtn.dataset.previewCommentMode = hasSelection ? "selection" : "";
|
|
6475
|
-
addBtn.title = hasSelection
|
|
6476
|
-
? ("Add a local comment from the current preview selection on this " + blockKindLabel + " (" + lineLabel + ").")
|
|
6477
|
-
: "";
|
|
6478
|
-
addBtn.setAttribute("aria-label", addBtn.title || "Comment");
|
|
6479
|
-
}
|
|
6480
|
-
|
|
6481
|
-
if (jumpBtn) {
|
|
6482
|
-
jumpBtn.hidden = !hasSelection;
|
|
6483
|
-
jumpBtn.textContent = "Jump";
|
|
6484
|
-
jumpBtn.dataset.previewCommentMode = hasSelection ? "selection" : "";
|
|
6485
|
-
jumpBtn.title = hasSelection
|
|
6486
|
-
? ("Jump to the current preview selection on this " + blockKindLabel + " in the raw editor (" + lineLabel + ").")
|
|
6487
|
-
: "";
|
|
6488
|
-
jumpBtn.setAttribute("aria-label", jumpBtn.title || "Jump");
|
|
6489
|
-
}
|
|
6490
6988
|
}
|
|
6491
6989
|
|
|
6492
6990
|
function updatePreviewCommentBlocksForElement(targetEl) {
|
|
6493
6991
|
if (!targetEl || typeof targetEl.querySelectorAll !== "function") return;
|
|
6992
|
+
ensurePreviewSelectionActions(targetEl);
|
|
6494
6993
|
const sourceText = String(sourceTextEl && sourceTextEl.value ? sourceTextEl.value : "");
|
|
6495
6994
|
Array.from(targetEl.querySelectorAll(".preview-comment-block")).forEach((blockEl) => {
|
|
6496
6995
|
updatePreviewCommentBlockState(blockEl, sourceText);
|
|
6497
6996
|
});
|
|
6997
|
+
updatePreviewSelectionActions(targetEl);
|
|
6498
6998
|
}
|
|
6499
6999
|
|
|
6500
7000
|
function decorateRenderedEditorPreviewComments(targetEl, sourceText) {
|
|
@@ -6522,43 +7022,20 @@
|
|
|
6522
7022
|
wrapper.dataset.reviewNoteLineEnd = String(sourceBlock.lineEnd);
|
|
6523
7023
|
wrapper.dataset.previewCommentKind = sourceBlock.kind;
|
|
6524
7024
|
|
|
6525
|
-
const controls = document.createElement("div");
|
|
6526
|
-
controls.className = "preview-comment-controls";
|
|
6527
|
-
|
|
6528
|
-
const summaryBtn = document.createElement("button");
|
|
6529
|
-
summaryBtn.type = "button";
|
|
6530
|
-
summaryBtn.className = "preview-comment-summary";
|
|
6531
|
-
summaryBtn.hidden = true;
|
|
6532
|
-
controls.appendChild(summaryBtn);
|
|
6533
|
-
|
|
6534
|
-
const addBtn = document.createElement("button");
|
|
6535
|
-
addBtn.type = "button";
|
|
6536
|
-
addBtn.className = "preview-comment-add";
|
|
6537
|
-
addBtn.dataset.previewCommentAction = "comment";
|
|
6538
|
-
addBtn.textContent = "Comment";
|
|
6539
|
-
controls.appendChild(addBtn);
|
|
6540
|
-
|
|
6541
|
-
const jumpBtn = document.createElement("button");
|
|
6542
|
-
jumpBtn.type = "button";
|
|
6543
|
-
jumpBtn.className = "preview-comment-jump";
|
|
6544
|
-
jumpBtn.dataset.previewCommentAction = "jump";
|
|
6545
|
-
jumpBtn.textContent = "Jump";
|
|
6546
|
-
controls.appendChild(jumpBtn);
|
|
6547
|
-
|
|
6548
7025
|
originalElement.replaceWith(wrapper);
|
|
6549
|
-
wrapper.appendChild(controls);
|
|
6550
7026
|
originalElement.classList.add("preview-comment-block-content");
|
|
6551
7027
|
wrapper.appendChild(originalElement);
|
|
6552
7028
|
}
|
|
6553
7029
|
|
|
7030
|
+
ensurePreviewSelectionActions(targetEl);
|
|
6554
7031
|
updatePreviewCommentBlocksForElement(targetEl);
|
|
6555
7032
|
}
|
|
6556
7033
|
|
|
6557
7034
|
function refreshRenderedEditorPreviewComments() {
|
|
6558
|
-
if (sourcePreviewEl
|
|
7035
|
+
if (sourcePreviewEl) {
|
|
6559
7036
|
updatePreviewCommentBlocksForElement(sourcePreviewEl);
|
|
6560
7037
|
}
|
|
6561
|
-
if (critiqueViewEl
|
|
7038
|
+
if (critiqueViewEl) {
|
|
6562
7039
|
updatePreviewCommentBlocksForElement(critiqueViewEl);
|
|
6563
7040
|
}
|
|
6564
7041
|
}
|
|
@@ -6792,10 +7269,11 @@
|
|
|
6792
7269
|
}
|
|
6793
7270
|
|
|
6794
7271
|
function revealReviewNoteInPreview(note) {
|
|
6795
|
-
if (!supportsPreviewCommentsForCurrentEditor()) return;
|
|
7272
|
+
if (!supportsPreviewCommentsForCurrentEditor()) return false;
|
|
6796
7273
|
if (rightView === "editor-preview" && critiqueViewEl && critiqueViewEl.isConnected) {
|
|
6797
|
-
revealReviewNoteInPreviewElement(critiqueViewEl, note);
|
|
7274
|
+
return revealReviewNoteInPreviewElement(critiqueViewEl, note);
|
|
6798
7275
|
}
|
|
7276
|
+
return false;
|
|
6799
7277
|
}
|
|
6800
7278
|
|
|
6801
7279
|
function updateActivePreviewCommentSelectionFromDom() {
|
|
@@ -6827,7 +7305,9 @@
|
|
|
6827
7305
|
|
|
6828
7306
|
setActivePreviewCommentSelection({
|
|
6829
7307
|
...anchor,
|
|
7308
|
+
paneId: getPreviewSelectionPaneIdForNode(startBlock),
|
|
6830
7309
|
blockKey: getPreviewCommentBlockKey(startBlock),
|
|
7310
|
+
previewCommentKind: String(startBlock.dataset && startBlock.dataset.previewCommentKind || "paragraph"),
|
|
6831
7311
|
});
|
|
6832
7312
|
}
|
|
6833
7313
|
|
|
@@ -6922,11 +7402,27 @@
|
|
|
6922
7402
|
&& typeof sourceTextEl.selectionEnd === "number"
|
|
6923
7403
|
&& sourceTextEl.selectionEnd > sourceTextEl.selectionStart
|
|
6924
7404
|
);
|
|
7405
|
+
const canJumpToPreview = Boolean(
|
|
7406
|
+
hasSelection
|
|
7407
|
+
&& rightView === "editor-preview"
|
|
7408
|
+
&& critiqueViewEl
|
|
7409
|
+
&& supportsPreviewCommentsForCurrentEditor()
|
|
7410
|
+
);
|
|
6925
7411
|
editorSelectionCommentBtn.hidden = !hasSelection;
|
|
7412
|
+
if (editorSelectionJumpBtn) {
|
|
7413
|
+
editorSelectionJumpBtn.hidden = !canJumpToPreview;
|
|
7414
|
+
}
|
|
7415
|
+
if (editorSelectionActionsEl) {
|
|
7416
|
+
editorSelectionActionsEl.hidden = !hasSelection;
|
|
7417
|
+
}
|
|
6926
7418
|
if (hasSelection) {
|
|
6927
7419
|
editorSelectionCommentBtn.title = "Create a new local comment from the current editor selection.";
|
|
6928
7420
|
editorSelectionCommentBtn.setAttribute("aria-label", editorSelectionCommentBtn.title);
|
|
6929
7421
|
}
|
|
7422
|
+
if (editorSelectionJumpBtn && canJumpToPreview) {
|
|
7423
|
+
editorSelectionJumpBtn.title = "Jump to the current editor selection in the preview.";
|
|
7424
|
+
editorSelectionJumpBtn.setAttribute("aria-label", editorSelectionJumpBtn.title);
|
|
7425
|
+
}
|
|
6930
7426
|
}
|
|
6931
7427
|
|
|
6932
7428
|
function clearSuppressedEditorSelectionComment() {
|
|
@@ -6937,6 +7433,138 @@
|
|
|
6937
7433
|
updateEditorSelectionCommentUi();
|
|
6938
7434
|
}
|
|
6939
7435
|
|
|
7436
|
+
function getOutlineEntriesForCurrentEditor() {
|
|
7437
|
+
return scanOutlineEntries(sourceTextEl && sourceTextEl.value ? sourceTextEl.value : "", editorLanguage || "markdown");
|
|
7438
|
+
}
|
|
7439
|
+
|
|
7440
|
+
function updateOutlineUi() {
|
|
7441
|
+
outlineEntries = getOutlineEntriesForCurrentEditor();
|
|
7442
|
+
const descriptor = getCurrentStudioDocumentDescriptor();
|
|
7443
|
+
const count = outlineEntries.length;
|
|
7444
|
+
const hasEntries = count > 0;
|
|
7445
|
+
const isOpen = isOutlineOpen();
|
|
7446
|
+
if (outlineBtn) {
|
|
7447
|
+
outlineBtn.textContent = "Outline";
|
|
7448
|
+
outlineBtn.classList.remove("has-content");
|
|
7449
|
+
outlineBtn.classList.toggle("is-active", isOpen);
|
|
7450
|
+
outlineBtn.setAttribute("aria-pressed", isOpen ? "true" : "false");
|
|
7451
|
+
outlineBtn.title = isOpen
|
|
7452
|
+
? "Hide document outline."
|
|
7453
|
+
: (hasEntries
|
|
7454
|
+
? (count + " outline entr" + (count === 1 ? "y" : "ies") + " for " + descriptor.label + ". Open the outline rail.")
|
|
7455
|
+
: "Open document outline for the current editor text.");
|
|
7456
|
+
}
|
|
7457
|
+
if (outlineMetaEl) {
|
|
7458
|
+
outlineMetaEl.textContent = hasEntries
|
|
7459
|
+
? (count + " entr" + (count === 1 ? "y" : "ies") + " · " + (editorLanguage || "text") + " · " + descriptor.label)
|
|
7460
|
+
: ("No outline entries · " + (editorLanguage || "text"));
|
|
7461
|
+
}
|
|
7462
|
+
if (outlineDoneBtn) {
|
|
7463
|
+
outlineDoneBtn.disabled = !isOpen;
|
|
7464
|
+
}
|
|
7465
|
+
if (outlineEmptyStateEl) {
|
|
7466
|
+
outlineEmptyStateEl.hidden = hasEntries;
|
|
7467
|
+
}
|
|
7468
|
+
renderOutlineList();
|
|
7469
|
+
}
|
|
7470
|
+
|
|
7471
|
+
function renderOutlineList() {
|
|
7472
|
+
if (!outlineListEl) return;
|
|
7473
|
+
outlineListEl.innerHTML = "";
|
|
7474
|
+
for (const entry of outlineEntries) {
|
|
7475
|
+
const itemBtn = document.createElement("button");
|
|
7476
|
+
itemBtn.type = "button";
|
|
7477
|
+
itemBtn.className = "outline-entry";
|
|
7478
|
+
itemBtn.dataset.outlineId = String(entry.id || "");
|
|
7479
|
+
itemBtn.style.paddingLeft = (10 + Math.max(0, (entry.depth || 1) - 1) * 14) + "px";
|
|
7480
|
+
itemBtn.title = getOutlineKindLabel(entry.kind) + " · line " + String(entry.lineStart || 1) + "\n" + String(entry.label || "");
|
|
7481
|
+
|
|
7482
|
+
const kindEl = document.createElement("span");
|
|
7483
|
+
kindEl.className = "outline-entry-kind";
|
|
7484
|
+
kindEl.textContent = getOutlineKindBadge(entry.kind);
|
|
7485
|
+
itemBtn.appendChild(kindEl);
|
|
7486
|
+
|
|
7487
|
+
const titleEl = document.createElement("span");
|
|
7488
|
+
titleEl.className = "outline-entry-title";
|
|
7489
|
+
titleEl.textContent = String(entry.label || "");
|
|
7490
|
+
itemBtn.appendChild(titleEl);
|
|
7491
|
+
|
|
7492
|
+
const metaEl = document.createElement("span");
|
|
7493
|
+
metaEl.className = "outline-entry-meta";
|
|
7494
|
+
metaEl.textContent = "L" + String(entry.lineStart || 1);
|
|
7495
|
+
itemBtn.appendChild(metaEl);
|
|
7496
|
+
|
|
7497
|
+
outlineListEl.appendChild(itemBtn);
|
|
7498
|
+
}
|
|
7499
|
+
}
|
|
7500
|
+
|
|
7501
|
+
function buildOutlineEntryAnchor(entry) {
|
|
7502
|
+
if (!entry) return null;
|
|
7503
|
+
return normalizeReviewNote({
|
|
7504
|
+
selectionStart: entry.selectionStart,
|
|
7505
|
+
selectionEnd: entry.selectionEnd,
|
|
7506
|
+
lineStart: entry.lineStart,
|
|
7507
|
+
lineEnd: entry.lineEnd,
|
|
7508
|
+
selectedText: entry.selectedText,
|
|
7509
|
+
selectedDisplayText: entry.selectedDisplayText || entry.label,
|
|
7510
|
+
});
|
|
7511
|
+
}
|
|
7512
|
+
|
|
7513
|
+
function jumpToOutlineEntry(entryId) {
|
|
7514
|
+
const entry = outlineEntries.find((candidate) => candidate && String(candidate.id || "") === String(entryId || ""));
|
|
7515
|
+
if (!entry) return false;
|
|
7516
|
+
const anchor = buildOutlineEntryAnchor(entry);
|
|
7517
|
+
if (!anchor) return false;
|
|
7518
|
+
return jumpToReviewAnchor(anchor, {
|
|
7519
|
+
statusMessage: "Jumped to outline entry.",
|
|
7520
|
+
afterJump: () => {
|
|
7521
|
+
revealReviewNoteInPreview(anchor);
|
|
7522
|
+
},
|
|
7523
|
+
});
|
|
7524
|
+
}
|
|
7525
|
+
|
|
7526
|
+
function closeOutline(options) {
|
|
7527
|
+
if (!outlineOverlayEl || outlineOverlayEl.hidden) return;
|
|
7528
|
+
outlineOverlayEl.hidden = true;
|
|
7529
|
+
updateOutlineUi();
|
|
7530
|
+
if (editorView === "markdown") {
|
|
7531
|
+
scheduleEditorLineNumberRender();
|
|
7532
|
+
}
|
|
7533
|
+
const focusTarget = options && Object.prototype.hasOwnProperty.call(options, "focusTarget")
|
|
7534
|
+
? options.focusTarget
|
|
7535
|
+
: (outlineReturnFocusEl || outlineBtn || sourceTextEl);
|
|
7536
|
+
outlineReturnFocusEl = null;
|
|
7537
|
+
if (focusTarget && typeof focusTarget.focus === "function") {
|
|
7538
|
+
const schedule = typeof window.requestAnimationFrame === "function"
|
|
7539
|
+
? window.requestAnimationFrame.bind(window)
|
|
7540
|
+
: (cb) => window.setTimeout(cb, 16);
|
|
7541
|
+
schedule(() => focusTarget.focus());
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
|
|
7545
|
+
function openOutline() {
|
|
7546
|
+
if (!outlineOverlayEl) return;
|
|
7547
|
+
if (isReviewNotesOpen()) {
|
|
7548
|
+
closeReviewNotes({ focusTarget: null });
|
|
7549
|
+
}
|
|
7550
|
+
outlineReturnFocusEl = document.activeElement && document.activeElement !== document.body
|
|
7551
|
+
? document.activeElement
|
|
7552
|
+
: sourceTextEl;
|
|
7553
|
+
outlineOverlayEl.hidden = false;
|
|
7554
|
+
updateOutlineUi();
|
|
7555
|
+
if (editorView === "markdown") {
|
|
7556
|
+
scheduleEditorLineNumberRender();
|
|
7557
|
+
}
|
|
7558
|
+
}
|
|
7559
|
+
|
|
7560
|
+
function toggleOutline() {
|
|
7561
|
+
if (isOutlineOpen()) {
|
|
7562
|
+
closeOutline({ focusTarget: outlineBtn || sourceTextEl });
|
|
7563
|
+
} else {
|
|
7564
|
+
openOutline();
|
|
7565
|
+
}
|
|
7566
|
+
}
|
|
7567
|
+
|
|
6940
7568
|
function updateReviewNotesUi() {
|
|
6941
7569
|
const descriptor = getCurrentStudioDocumentDescriptor();
|
|
6942
7570
|
const count = reviewNotes.length;
|
|
@@ -7143,17 +7771,12 @@
|
|
|
7143
7771
|
});
|
|
7144
7772
|
}
|
|
7145
7773
|
|
|
7146
|
-
function
|
|
7147
|
-
|
|
7148
|
-
const blockKey = getPreviewCommentBlockKey(blockEl);
|
|
7149
|
-
return activePreviewCommentSelection && activePreviewCommentSelection.blockKey === blockKey
|
|
7150
|
-
? activePreviewCommentSelection
|
|
7151
|
-
: null;
|
|
7774
|
+
function getActivePreviewSelectionAnchorForPane(paneId) {
|
|
7775
|
+
return getActivePreviewSelectionForPane(paneId);
|
|
7152
7776
|
}
|
|
7153
7777
|
|
|
7154
|
-
function addReviewNoteFromPreviewSelection(
|
|
7155
|
-
|
|
7156
|
-
const anchor = getActivePreviewSelectionAnchorForBlock(blockEl);
|
|
7778
|
+
function addReviewNoteFromPreviewSelection(paneId) {
|
|
7779
|
+
const anchor = getActivePreviewSelectionAnchorForPane(paneId);
|
|
7157
7780
|
if (!anchor) {
|
|
7158
7781
|
setStatus("Select some preview text within a single block first.", "warning");
|
|
7159
7782
|
return null;
|
|
@@ -7189,6 +7812,12 @@
|
|
|
7189
7812
|
if (editorSelectionCommentBtn) {
|
|
7190
7813
|
editorSelectionCommentBtn.hidden = true;
|
|
7191
7814
|
}
|
|
7815
|
+
if (editorSelectionJumpBtn) {
|
|
7816
|
+
editorSelectionJumpBtn.hidden = true;
|
|
7817
|
+
}
|
|
7818
|
+
if (editorSelectionActionsEl) {
|
|
7819
|
+
editorSelectionActionsEl.hidden = true;
|
|
7820
|
+
}
|
|
7192
7821
|
const shouldOpenReviewNotes = !isReviewNotesOpen();
|
|
7193
7822
|
pendingReviewNoteFocusId = note.id;
|
|
7194
7823
|
setReviewNotes(reviewNotes.concat([note]));
|
|
@@ -7218,6 +7847,30 @@
|
|
|
7218
7847
|
});
|
|
7219
7848
|
}
|
|
7220
7849
|
|
|
7850
|
+
function jumpToEditorSelectionInPreview() {
|
|
7851
|
+
if (editorView !== "markdown") {
|
|
7852
|
+
setStatus("Switch to Editor (Raw) before jumping from an editor selection.", "warning");
|
|
7853
|
+
return false;
|
|
7854
|
+
}
|
|
7855
|
+
if (rightView !== "editor-preview" || !critiqueViewEl || !supportsPreviewCommentsForCurrentEditor()) {
|
|
7856
|
+
setStatus("Open Editor (Preview) on the right to jump the current editor selection there.", "warning");
|
|
7857
|
+
return false;
|
|
7858
|
+
}
|
|
7859
|
+
const anchor = getEditorAnchorForReviewNote();
|
|
7860
|
+
const jumped = revealReviewNoteInPreview(anchor);
|
|
7861
|
+
if (!jumped) {
|
|
7862
|
+
setStatus("Could not find the current editor selection in the preview.", "warning");
|
|
7863
|
+
return false;
|
|
7864
|
+
}
|
|
7865
|
+
const current = String(sourceTextEl.value || "");
|
|
7866
|
+
const range = resolveReviewNoteRange(anchor, current);
|
|
7867
|
+
if (range) {
|
|
7868
|
+
scrollEditorRangeIntoView(range);
|
|
7869
|
+
}
|
|
7870
|
+
setStatus("Jumped to the current editor selection in the preview.", "success");
|
|
7871
|
+
return true;
|
|
7872
|
+
}
|
|
7873
|
+
|
|
7221
7874
|
function addReviewNoteFromEditorLine() {
|
|
7222
7875
|
if (editorView !== "markdown") {
|
|
7223
7876
|
setStatus("Switch to Editor (Raw) before adding a line comment.", "warning");
|
|
@@ -7260,23 +7913,44 @@
|
|
|
7260
7913
|
return true;
|
|
7261
7914
|
}
|
|
7262
7915
|
|
|
7263
|
-
function jumpToPreviewSelection(
|
|
7264
|
-
|
|
7265
|
-
const anchor = getActivePreviewSelectionAnchorForBlock(blockEl);
|
|
7916
|
+
function jumpToPreviewSelection(paneId) {
|
|
7917
|
+
const anchor = getActivePreviewSelectionAnchorForPane(paneId);
|
|
7266
7918
|
if (!anchor) {
|
|
7267
7919
|
setStatus("Select some preview text within a single block first.", "warning");
|
|
7268
7920
|
return false;
|
|
7269
7921
|
}
|
|
7270
|
-
const
|
|
7922
|
+
const previewNote = normalizeReviewNote(anchor);
|
|
7923
|
+
const jumped = jumpToReviewAnchor(previewNote, {
|
|
7271
7924
|
statusMessage: "Jumped to preview selection in the raw editor.",
|
|
7925
|
+
afterJump: () => {
|
|
7926
|
+
const paneEl = getPreviewSelectionPaneElement(paneId);
|
|
7927
|
+
if (paneEl && previewNote) {
|
|
7928
|
+
revealReviewNoteInPreviewElement(paneEl, previewNote);
|
|
7929
|
+
}
|
|
7930
|
+
const schedule = typeof window.requestAnimationFrame === "function"
|
|
7931
|
+
? window.requestAnimationFrame.bind(window)
|
|
7932
|
+
: (cb) => window.setTimeout(cb, 16);
|
|
7933
|
+
schedule(() => {
|
|
7934
|
+
const selection = typeof window.getSelection === "function" ? window.getSelection() : null;
|
|
7935
|
+
if (selection && typeof selection.removeAllRanges === "function") {
|
|
7936
|
+
selection.removeAllRanges();
|
|
7937
|
+
}
|
|
7938
|
+
clearPreviewCommentSelection();
|
|
7939
|
+
const current = String(sourceTextEl && sourceTextEl.value ? sourceTextEl.value : "");
|
|
7940
|
+
const range = resolveReviewNoteRange(previewNote, current);
|
|
7941
|
+
if (range && sourceTextEl) {
|
|
7942
|
+
try {
|
|
7943
|
+
sourceTextEl.focus({ preventScroll: true });
|
|
7944
|
+
} catch {
|
|
7945
|
+
sourceTextEl.focus();
|
|
7946
|
+
}
|
|
7947
|
+
if (typeof sourceTextEl.setSelectionRange === "function") {
|
|
7948
|
+
sourceTextEl.setSelectionRange(range.start, range.end);
|
|
7949
|
+
}
|
|
7950
|
+
}
|
|
7951
|
+
});
|
|
7952
|
+
},
|
|
7272
7953
|
});
|
|
7273
|
-
if (jumped) {
|
|
7274
|
-
const selection = typeof window.getSelection === "function" ? window.getSelection() : null;
|
|
7275
|
-
if (selection && typeof selection.removeAllRanges === "function") {
|
|
7276
|
-
selection.removeAllRanges();
|
|
7277
|
-
}
|
|
7278
|
-
clearPreviewCommentSelection();
|
|
7279
|
-
}
|
|
7280
7954
|
return jumped;
|
|
7281
7955
|
}
|
|
7282
7956
|
|
|
@@ -7429,6 +8103,9 @@
|
|
|
7429
8103
|
if (isReviewNotesOpen()) {
|
|
7430
8104
|
closeReviewNotes({ focusTarget: null });
|
|
7431
8105
|
}
|
|
8106
|
+
if (isOutlineOpen()) {
|
|
8107
|
+
closeOutline({ focusTarget: null });
|
|
8108
|
+
}
|
|
7432
8109
|
scratchpadReturnFocusEl = document.activeElement && document.activeElement !== document.body
|
|
7433
8110
|
? document.activeElement
|
|
7434
8111
|
: sourceTextEl;
|
|
@@ -7472,6 +8149,9 @@
|
|
|
7472
8149
|
if (isScratchpadOpen()) {
|
|
7473
8150
|
closeScratchpad({ focusTarget: null });
|
|
7474
8151
|
}
|
|
8152
|
+
if (isOutlineOpen()) {
|
|
8153
|
+
closeOutline({ focusTarget: null });
|
|
8154
|
+
}
|
|
7475
8155
|
reviewNotesReturnFocusEl = document.activeElement && document.activeElement !== document.body
|
|
7476
8156
|
? document.activeElement
|
|
7477
8157
|
: sourceTextEl;
|
|
@@ -7589,6 +8269,7 @@
|
|
|
7589
8269
|
if (editorView === "preview") {
|
|
7590
8270
|
scheduleSourcePreviewRender(0);
|
|
7591
8271
|
}
|
|
8272
|
+
updateOutlineUi();
|
|
7592
8273
|
}
|
|
7593
8274
|
|
|
7594
8275
|
function setEditorHighlightMode(mode) {
|
|
@@ -8788,6 +9469,7 @@
|
|
|
8788
9469
|
renderSourcePreview({ previewDelayMs: PREVIEW_INPUT_DEBOUNCE_MS });
|
|
8789
9470
|
scheduleEditorMetaUpdate();
|
|
8790
9471
|
updateEditorSelectionCommentUi();
|
|
9472
|
+
updateOutlineUi();
|
|
8791
9473
|
if (isReviewNotesOpen() && reviewNotes.length > 0) {
|
|
8792
9474
|
renderReviewNotesList();
|
|
8793
9475
|
updateReviewNotesUi();
|
|
@@ -9176,6 +9858,35 @@
|
|
|
9176
9858
|
});
|
|
9177
9859
|
}
|
|
9178
9860
|
|
|
9861
|
+
if (outlineBtn) {
|
|
9862
|
+
outlineBtn.addEventListener("click", () => {
|
|
9863
|
+
toggleOutline();
|
|
9864
|
+
});
|
|
9865
|
+
}
|
|
9866
|
+
|
|
9867
|
+
if (outlineCloseBtn) {
|
|
9868
|
+
outlineCloseBtn.addEventListener("click", () => {
|
|
9869
|
+
closeOutline();
|
|
9870
|
+
});
|
|
9871
|
+
}
|
|
9872
|
+
|
|
9873
|
+
if (outlineDoneBtn) {
|
|
9874
|
+
outlineDoneBtn.addEventListener("click", () => {
|
|
9875
|
+
closeOutline();
|
|
9876
|
+
});
|
|
9877
|
+
}
|
|
9878
|
+
|
|
9879
|
+
if (outlineListEl) {
|
|
9880
|
+
outlineListEl.addEventListener("click", (event) => {
|
|
9881
|
+
const target = event.target;
|
|
9882
|
+
const entryBtn = target instanceof Element ? target.closest(".outline-entry") : null;
|
|
9883
|
+
if (!entryBtn) return;
|
|
9884
|
+
const outlineId = entryBtn.getAttribute("data-outline-id") || "";
|
|
9885
|
+
if (!outlineId) return;
|
|
9886
|
+
jumpToOutlineEntry(outlineId);
|
|
9887
|
+
});
|
|
9888
|
+
}
|
|
9889
|
+
|
|
9179
9890
|
if (reviewNotesCloseBtn) {
|
|
9180
9891
|
reviewNotesCloseBtn.addEventListener("click", () => {
|
|
9181
9892
|
closeReviewNotes();
|
|
@@ -9203,6 +9914,15 @@
|
|
|
9203
9914
|
});
|
|
9204
9915
|
}
|
|
9205
9916
|
|
|
9917
|
+
if (editorSelectionJumpBtn) {
|
|
9918
|
+
editorSelectionJumpBtn.addEventListener("mousedown", (event) => {
|
|
9919
|
+
event.preventDefault();
|
|
9920
|
+
});
|
|
9921
|
+
editorSelectionJumpBtn.addEventListener("click", () => {
|
|
9922
|
+
jumpToEditorSelectionInPreview();
|
|
9923
|
+
});
|
|
9924
|
+
}
|
|
9925
|
+
|
|
9206
9926
|
if (reviewNotesInlineAllBtn) {
|
|
9207
9927
|
reviewNotesInlineAllBtn.addEventListener("click", () => {
|
|
9208
9928
|
toggleAllReviewNotesInlineAnnotations();
|
|
@@ -9231,18 +9951,17 @@
|
|
|
9231
9951
|
const target = event.target;
|
|
9232
9952
|
const actionBtn = target instanceof Element ? target.closest(".preview-comment-add, .preview-comment-jump, .preview-comment-summary") : null;
|
|
9233
9953
|
if (!actionBtn) return;
|
|
9234
|
-
const blockEl = actionBtn.closest(".preview-comment-block");
|
|
9235
|
-
if (!blockEl) return;
|
|
9236
9954
|
event.preventDefault();
|
|
9237
9955
|
event.stopPropagation();
|
|
9238
9956
|
const mode = String(actionBtn.dataset && actionBtn.dataset.previewCommentMode ? actionBtn.dataset.previewCommentMode : "");
|
|
9239
9957
|
if (!mode || !mode.startsWith("selection")) return;
|
|
9958
|
+
const paneId = String(actionBtn.dataset && actionBtn.dataset.previewPane ? actionBtn.dataset.previewPane : "");
|
|
9240
9959
|
const action = String(actionBtn.dataset && actionBtn.dataset.previewCommentAction ? actionBtn.dataset.previewCommentAction : "comment");
|
|
9241
9960
|
if (action === "jump") {
|
|
9242
|
-
jumpToPreviewSelection(
|
|
9961
|
+
jumpToPreviewSelection(paneId);
|
|
9243
9962
|
return;
|
|
9244
9963
|
}
|
|
9245
|
-
addReviewNoteFromPreviewSelection(
|
|
9964
|
+
addReviewNoteFromPreviewSelection(paneId);
|
|
9246
9965
|
}
|
|
9247
9966
|
|
|
9248
9967
|
if (leftPaneEl) {
|