fix(editor): 隐藏无语言标识代码块的空工具栏顶栏
This commit is contained in:
parent
67406f661a
commit
f569258633
@ -39,6 +39,10 @@ describe('CodeBlockNodeView', () => {
|
||||
} as any);
|
||||
expect(view.dom.querySelector('.tiptap-codeblock-lang')?.textContent).toBe('python');
|
||||
expect(view.dom.querySelector('.tiptap-codeblock-run')).not.toBeNull();
|
||||
expect(view.dom.querySelector<HTMLElement>('.tiptap-codeblock-toolbar')?.style.display).toBe(
|
||||
'',
|
||||
);
|
||||
expect(view.dom.classList.contains('has-toolbar')).toBe(true);
|
||||
});
|
||||
|
||||
it('普通块(python):显示语言标签,无运行按钮', () => {
|
||||
@ -48,16 +52,47 @@ describe('CodeBlockNodeView', () => {
|
||||
} as any);
|
||||
expect(view.dom.querySelector('.tiptap-codeblock-lang')?.textContent).toBe('python');
|
||||
expect(view.dom.querySelector('.tiptap-codeblock-run')).toBeNull();
|
||||
expect(view.dom.querySelector<HTMLElement>('.tiptap-codeblock-toolbar')?.style.display).toBe(
|
||||
'',
|
||||
);
|
||||
expect(view.dom.classList.contains('has-toolbar')).toBe(true);
|
||||
});
|
||||
|
||||
it('无 language 的块:标签为空或占位,无运行按钮', () => {
|
||||
it('无 language 的块:隐藏 toolbar,无运行按钮', () => {
|
||||
const view = new CodeBlockNodeView({
|
||||
node: mockNode(''),
|
||||
editor: mockEditor(),
|
||||
} as any);
|
||||
expect(view.dom.querySelector('.tiptap-codeblock-run')).toBeNull();
|
||||
expect(view.dom.querySelector<HTMLElement>('.tiptap-codeblock-toolbar')?.style.display).toBe(
|
||||
'none',
|
||||
);
|
||||
expect(view.dom.classList.contains('has-toolbar')).toBe(false);
|
||||
});
|
||||
|
||||
it('node 语言由空更新为 python 时 update() 显示 toolbar', () => {
|
||||
const view = new CodeBlockNodeView({
|
||||
node: mockNode(''),
|
||||
editor: mockEditor(),
|
||||
} as any);
|
||||
expect(view.dom.querySelector<HTMLElement>('.tiptap-codeblock-toolbar')?.style.display).toBe(
|
||||
'none',
|
||||
);
|
||||
expect(view.dom.classList.contains('has-toolbar')).toBe(false);
|
||||
|
||||
view.update(mockNode('python'));
|
||||
expect(view.dom.querySelector('.tiptap-codeblock-lang')?.textContent).toBe('python');
|
||||
expect(view.dom.querySelector<HTMLElement>('.tiptap-codeblock-toolbar')?.style.display).toBe(
|
||||
'',
|
||||
);
|
||||
expect(view.dom.classList.contains('has-toolbar')).toBe(true);
|
||||
|
||||
view.update(mockNode(''));
|
||||
expect(view.dom.querySelector<HTMLElement>('.tiptap-codeblock-toolbar')?.style.display).toBe(
|
||||
'none',
|
||||
);
|
||||
expect(view.dom.classList.contains('has-toolbar')).toBe(false);
|
||||
});
|
||||
it('node 语言变化时 update() 刷新标签', () => {
|
||||
const view = new CodeBlockNodeView({
|
||||
node: mockNode('python'),
|
||||
|
||||
@ -66,10 +66,10 @@ export class CodeBlockNodeView {
|
||||
this.langBadge.classList.add('tiptap-codeblock-lang');
|
||||
this.langBadge.textContent = extractLang((this.node.attrs.language as string) ?? '');
|
||||
// runnable 块的语言标签可点击,触发编辑模态框(改语言/overrides)
|
||||
this.langBadge.addEventListener('click', () => this.openEditModal());
|
||||
if (isRunnable(this.node)) {
|
||||
this.langBadge.classList.add('tiptap-codeblock-lang-editable');
|
||||
this.langBadge.title = '点击修改语言与运行配置';
|
||||
this.langBadge.addEventListener('click', () => this.openEditModal());
|
||||
}
|
||||
this.toolbar.appendChild(this.langBadge);
|
||||
|
||||
@ -93,6 +93,9 @@ export class CodeBlockNodeView {
|
||||
}
|
||||
this.pre.appendChild(this.code);
|
||||
this.container.appendChild(this.pre);
|
||||
|
||||
// 校验并设置工具栏显隐(无语言且非 runnable 时隐藏)
|
||||
this.updateToolbarVisibility();
|
||||
}
|
||||
|
||||
get dom(): HTMLElement {
|
||||
@ -114,12 +117,22 @@ export class CodeBlockNodeView {
|
||||
this.node = node;
|
||||
if (oldLang !== newLang) {
|
||||
this.langBadge.textContent = extractLang(newLang);
|
||||
const runnable = isRunnable(node);
|
||||
this.langBadge.classList.toggle('tiptap-codeblock-lang-editable', runnable);
|
||||
if (runnable) {
|
||||
this.langBadge.title = '点击修改语言与运行配置';
|
||||
} else {
|
||||
this.langBadge.removeAttribute('title');
|
||||
}
|
||||
|
||||
// 更新 <code> 的 language class(低亮按新语言重算)
|
||||
this.code.className = '';
|
||||
const langClass = extractLang(newLang);
|
||||
if (langClass) this.code.classList.add(`language-${langClass}`);
|
||||
// runnable 状态变化时重建按钮(简化:不细粒度增删,整体重建工具栏按钮区)
|
||||
this.refreshRunButton();
|
||||
// 刷新工具栏显隐状态(无语言且非 runnable 时隐藏)
|
||||
this.updateToolbarVisibility();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -137,6 +150,18 @@ export class CodeBlockNodeView {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新工具栏显隐与容器类名:无语言且非 runnable 时隐藏工具栏。
|
||||
*/
|
||||
private updateToolbarVisibility(): void {
|
||||
const lang = extractLang((this.node.attrs.language as string) ?? '');
|
||||
const runnable = isRunnable(this.node);
|
||||
const show = lang !== '' || runnable;
|
||||
|
||||
this.toolbar.style.display = show ? '' : 'none';
|
||||
this.container.classList.toggle('has-toolbar', show);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 DOM mutation 是否应被 ProseMirror 忽略。
|
||||
*
|
||||
@ -178,6 +203,7 @@ export class CodeBlockNodeView {
|
||||
/** 点击运行:调 editor.storage.__onRunCode,结果填入结果区。 */
|
||||
/** 点击语言标签:打开编辑模态框,修改当前 runnable 块的语言/overrides。 */
|
||||
private openEditModal(): void {
|
||||
if (!isRunnable(this.node)) return;
|
||||
const pos = this.getPos?.();
|
||||
const currentInfo = (this.node.attrs.language as string) ?? '';
|
||||
if (pos === undefined) return;
|
||||
|
||||
@ -960,9 +960,13 @@
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* pre 紧贴 toolbar 下方,合并圆角 */
|
||||
/* pre 默认全圆角;有 toolbar 时与 toolbar 合并顶部圆角 */
|
||||
.tiptap-codeblock > pre {
|
||||
margin: 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.tiptap-codeblock.has-toolbar > pre {
|
||||
border-radius: 0 0 6px 6px;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user