fix: 浮动工具栏开关按钮无效 — 新增 toggleFloatingToolbar/isFloatingToolbar API
This commit is contained in:
+2
-9
@@ -229,15 +229,8 @@ bar.addEventListener('click', function(e){
|
||||
else if (cmd === 'outline') { toggleOutline(btn); }
|
||||
else if (cmd === 'wrap') { editor.toggleWordWrap(); btn.classList.toggle('on', !editor.isWordWrap()); }
|
||||
else if (cmd === 'float') {
|
||||
var hasFloat = editor._floatingToolbar && editor._floatingToolbar.parentNode;
|
||||
if (hasFloat) {
|
||||
if (editor._floatingToolbar.parentNode) editor._floatingToolbar.parentNode.removeChild(editor._floatingToolbar);
|
||||
editor._floatingToolbar = null;
|
||||
} else {
|
||||
editor.config.floatingToolbar = true;
|
||||
editor._initFloatingToolbar();
|
||||
}
|
||||
btn.classList.toggle('on', !!editor._floatingToolbar);
|
||||
editor.toggleFloatingToolbar();
|
||||
btn.classList.toggle('on', editor.isFloatingToolbar());
|
||||
}
|
||||
else if (cmd === 'toast') {
|
||||
var types = ['success','error','warning','info'];
|
||||
|
||||
+39
-16
@@ -84,6 +84,7 @@ export class MarkdownEditor {
|
||||
_i18nCtx!: InstanceI18n;
|
||||
_floatingToolbar!: HTMLElement | null;
|
||||
_selectionTimer!: ReturnType<typeof setInterval> | null;
|
||||
_floatingEnabled!: boolean;
|
||||
|
||||
constructor(container: string | HTMLElement, options: EditorOptions = {}) {
|
||||
if (!isBrowser()) {
|
||||
@@ -108,6 +109,7 @@ export class MarkdownEditor {
|
||||
this._outlineTimer = null; this._zenMode = false; this._wordWrap = true; this._syncing = false;
|
||||
this._zenMouseHandler = null;
|
||||
this._floatingToolbar = null; this._selectionTimer = null;
|
||||
this._floatingEnabled = this.config.floatingToolbar !== false;
|
||||
|
||||
this._renderFn = (typeof this.config.render === 'function') ? this.config.render : parseMarkdown;
|
||||
this._highlightFn = (typeof this.config.highlight === 'function') ? this.config.highlight : null;
|
||||
@@ -716,13 +718,15 @@ export class MarkdownEditor {
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
if (!this._floatingEnabled) return;
|
||||
|
||||
const ta = this.textarea;
|
||||
const show = () => {
|
||||
if (this._destroyed || this.config.readOnly) return;
|
||||
if (this._destroyed || this.config.readOnly || !this._floatingEnabled) return;
|
||||
const start = ta.selectionStart; const end = ta.selectionEnd;
|
||||
if (start === end) { this._hideFloatingToolbar(); return; }
|
||||
|
||||
if (!this._floatingToolbar) this._buildFloatingToolbar();
|
||||
if (!this._floatingToolbar || !this._floatingToolbar.parentNode) this._buildFloatingToolbar();
|
||||
|
||||
// Position the toolbar near the selection
|
||||
const rect = ta.getBoundingClientRect();
|
||||
@@ -731,10 +735,9 @@ export class MarkdownEditor {
|
||||
const currentLine = lines.length - 1;
|
||||
const lineHeight = parseInt(getComputedStyle(ta).lineHeight, 10) || 22;
|
||||
|
||||
let top = rect.top + currentLine * lineHeight - 38; // above the selection
|
||||
let top = rect.top + currentLine * lineHeight - 38;
|
||||
let left = rect.left + (ta.selectionDirection !== 'backward' ? (ta.selectionEnd - ta.selectionStart) / 2 : 0) * 8 + 10;
|
||||
|
||||
// Clamp to stay within the editor pane
|
||||
if (top < rect.top) top = rect.top + currentLine * lineHeight + lineHeight + 4;
|
||||
if (left < rect.left) left = rect.left + 4;
|
||||
const maxLeft = rect.right - 200;
|
||||
@@ -747,35 +750,55 @@ export class MarkdownEditor {
|
||||
|
||||
const hide = () => { this._hideFloatingToolbar(); };
|
||||
|
||||
// Detect selection changes via events + throttled polling
|
||||
let lastSelStart = ta.selectionStart;
|
||||
let lastSelEnd = ta.selectionEnd;
|
||||
const check = () => {
|
||||
if (this._destroyed || !document.body.contains(ta)) return;
|
||||
this._selectionTimer = setInterval(() => {
|
||||
if (this._destroyed || !document.body.contains(ta) || !this._floatingEnabled) return;
|
||||
const s = ta.selectionStart; const e = ta.selectionEnd;
|
||||
if (s !== lastSelStart || e !== lastSelEnd) {
|
||||
lastSelStart = s; lastSelEnd = e;
|
||||
const text = this._value.slice(s, e);
|
||||
this._emit('selectionChange', { start: s, end: e, text });
|
||||
}
|
||||
};
|
||||
// Use longer interval for polling (won't block event loop as much)
|
||||
this._selectionTimer = setInterval(check, 500) as any;
|
||||
}, 500) as any;
|
||||
this._cleanups.push(() => { if (this._selectionTimer) { clearInterval(this._selectionTimer); this._selectionTimer = null; } });
|
||||
|
||||
ta.addEventListener('mouseup', () => setTimeout(show, 0));
|
||||
ta.addEventListener('mouseup', () => { if (this._floatingEnabled) setTimeout(show, 0); });
|
||||
ta.addEventListener('keyup', () => {
|
||||
const s = ta.selectionStart; const e = ta.selectionEnd;
|
||||
if (s !== e) setTimeout(show, 0);
|
||||
if (!this._floatingEnabled) return;
|
||||
if (ta.selectionStart !== ta.selectionEnd) setTimeout(show, 0);
|
||||
else setTimeout(hide, 0);
|
||||
this._emit('cursorMove', this.getCursorPosition());
|
||||
});
|
||||
ta.addEventListener('blur', () => setTimeout(hide, 300));
|
||||
ta.addEventListener('click', () => setTimeout(() => {
|
||||
if (ta.selectionStart === ta.selectionEnd) hide();
|
||||
}, 0));
|
||||
ta.addEventListener('click', () => { if (ta.selectionStart === ta.selectionEnd) setTimeout(hide, 0); });
|
||||
}
|
||||
|
||||
toggleFloatingToolbar(): this {
|
||||
this._floatingEnabled = !this._floatingEnabled;
|
||||
if (this._floatingEnabled) {
|
||||
// Re-enable: restart the interval
|
||||
if (!this._selectionTimer) {
|
||||
const ta = this.textarea;
|
||||
this._selectionTimer = setInterval(() => {
|
||||
if (this._destroyed || !this._floatingEnabled) return;
|
||||
const s = ta.selectionStart; const e = ta.selectionEnd;
|
||||
if (s !== e) { /* will show via keyup/mouseup */ }
|
||||
}, 500) as any;
|
||||
this._cleanups.push(() => { if (this._selectionTimer) { clearInterval(this._selectionTimer); this._selectionTimer = null; } });
|
||||
}
|
||||
} else {
|
||||
// Disable: clear interval and hide toolbar
|
||||
if (this._selectionTimer) { clearInterval(this._selectionTimer); this._selectionTimer = null; }
|
||||
if (this._floatingToolbar) {
|
||||
if (this._floatingToolbar.parentNode) this._floatingToolbar.parentNode.removeChild(this._floatingToolbar);
|
||||
this._floatingToolbar = null;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
isFloatingToolbar(): boolean { return this._floatingEnabled; }
|
||||
|
||||
_buildFloatingToolbar(): void {
|
||||
const bar = document.createElement('div');
|
||||
bar.className = 'me-float-toolbar';
|
||||
|
||||
Reference in New Issue
Block a user