fix: 浮动工具栏水平/垂直定位完全重写 — 基于等宽字体精确计算列偏移+滚动补偿
This commit is contained in:
Vendored
+15
-11
@@ -3717,27 +3717,31 @@ dl{margin:.8em 0}dt{font-weight:650;margin:.6em 0 .2em}dd{margin:0 0 .3em 1.6em;
|
||||
// Position the toolbar near the selection (toolbar is absolute inside editorPane)
|
||||
const taRect = ta.getBoundingClientRect();
|
||||
const paneRect = this.editorPane.getBoundingClientRect();
|
||||
const taStyle = getComputedStyle(ta);
|
||||
const lineHeight = parseFloat(taStyle.lineHeight) || 22;
|
||||
const paddingTop = parseFloat(taStyle.paddingTop) || 16;
|
||||
const paddingLeft = parseFloat(taStyle.paddingLeft) || 18;
|
||||
const fontSize = parseFloat(taStyle.fontSize) || 13.5;
|
||||
// Monospace: char width ≈ fontSize * 0.6
|
||||
const charWidth = fontSize * 0.6;
|
||||
const textBefore = ta.value.substring(0, start);
|
||||
const lines = textBefore.split('\n');
|
||||
const currentLine = lines.length - 1;
|
||||
const lineHeight = parseInt(getComputedStyle(ta).lineHeight, 10) || 22;
|
||||
const paddingTop = parseInt(getComputedStyle(ta).paddingTop, 10) || 16;
|
||||
const scrollOffset = ta.scrollTop;
|
||||
// Line top relative to viewport
|
||||
const lineViewportTop = taRect.top + paddingTop + currentLine * lineHeight - scrollOffset;
|
||||
// Convert to editorPane-local coordinates
|
||||
const currentCol = textBefore.length - textBefore.lastIndexOf('\n') - 1;
|
||||
// Middle column of selection
|
||||
const midCol = currentCol + Math.floor((end - start) / 2 * ((ta.selectionDirection === 'backward') ? -1 : 1));
|
||||
// Vertical: line position in textarea content, then convert to pane-local
|
||||
const lineViewportTop = taRect.top + paddingTop + currentLine * lineHeight - ta.scrollTop;
|
||||
const lineLocalTop = lineViewportTop - paneRect.top;
|
||||
const toolbarHeight = 36;
|
||||
const gap = 4;
|
||||
// Try above first
|
||||
let top = lineLocalTop - toolbarHeight - gap;
|
||||
// If not enough room above, place below the selection
|
||||
if (top < gap) {
|
||||
top = lineLocalTop + lineHeight + gap;
|
||||
}
|
||||
// Horizontal: center near selection, in pane-local coords
|
||||
const selMidX = taRect.left + (ta.selectionEnd - ta.selectionStart) / 2 * (taRect.width / Math.max(1, ta.value.length || 1));
|
||||
let left = selMidX - paneRect.left - 80; // ~half toolbar width (5*28 + gaps)
|
||||
// Horizontal: column position in textarea content, convert to pane-local
|
||||
const colX = taRect.left + paddingLeft + midCol * charWidth - ta.scrollLeft;
|
||||
let left = colX - paneRect.left - 80;
|
||||
left = Math.max(4, Math.min(left, paneRect.width - 200));
|
||||
this._floatingToolbar.style.top = top + 'px';
|
||||
this._floatingToolbar.style.left = left + 'px';
|
||||
|
||||
Reference in New Issue
Block a user