release: v0.1.3 — bug fixes, performance, hardening
Bug Fixes:
- fix(core): exec() now supports _customActions registered via addToolbarButton
- fix(core): _emit('focus'/'blur') no longer passes editor argument twice
- fix(core): getHTML() now triggers beforeRender/afterRender hooks
- fix(core): _wrapSelection defaults to 'text' instead of i18n placeholder
- fix(core): addToolbarButton onClick+action no longer double-fires
- fix(core): null-safety on focus/blur/enable/disable after destroy
- fix(parser): empty headings (# ) no longer produce empty <h1> tags
- fix(parser): slugify returns 'heading' fallback for empty/special inputs
- fix(i18n): setCurrentLocale no longer mutates input parameter
- fix(core): autofocus skipped when readOnly is enabled
Performance:
- perf(core): cache last rendered value, skip parsing when content unchanged
- perf(core): add refresh() API to force re-render after theme/locale changes
Hardening:
- feat(core): tabSize dynamically applied to textarea via style.tabSize
- feat(core): getStatus() now includes readOnly field
Tests:
- 7 new test cases: customActions, refresh, focus args, destroy safety,
getStatus readOnly, autofocus+readOnly, slugify edge cases
- Total: 425 tests passing (+7 from v0.1.2)
Types:
- EditorStatus includes readOnly field
- MarkdownEditor.refresh() added to type definitions
This commit is contained in:
@@ -1278,4 +1278,77 @@ describe('MarkdownEditor - v0.1.2 readOnly 模式', () => {
|
||||
expect(ed.getValue()).toBe('# hello');
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('getStatus 包含 readOnly 字段', () => {
|
||||
document.body.innerHTML = '';
|
||||
const c = document.createElement('div');
|
||||
document.body.appendChild(c);
|
||||
const ed = new MarkdownEditor(c, { readOnly: true });
|
||||
expect(ed.getStatus().readOnly).toBe(true);
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('autofocus 在 readOnly 模式下不聚焦', () => {
|
||||
document.body.innerHTML = '';
|
||||
const c = document.createElement('div');
|
||||
document.body.appendChild(c);
|
||||
const ed = new MarkdownEditor(c, { readOnly: true, autofocus: true });
|
||||
// readOnly textarea 不应被 focus(autofocus 被跳过)
|
||||
expect(ed.textarea.readOnly).toBe(true);
|
||||
ed.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('MarkdownEditor - v0.1.3 修复验证', () => {
|
||||
test('exec 支持 _customActions 自定义动作', () => {
|
||||
document.body.innerHTML = '';
|
||||
const c = document.createElement('div');
|
||||
document.body.appendChild(c);
|
||||
const ed = new MarkdownEditor(c, { value: 'hello' });
|
||||
let called = false;
|
||||
ed._customActions = { myAction: () => { called = true; } };
|
||||
ed.exec('myAction');
|
||||
expect(called).toBe(true);
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('refresh 清除渲染缓存并强制重渲染', () => {
|
||||
document.body.innerHTML = '';
|
||||
const c = document.createElement('div');
|
||||
document.body.appendChild(c);
|
||||
const ed = new MarkdownEditor(c, { value: '# test', mode: 'split' });
|
||||
const first = ed.previewEl.innerHTML;
|
||||
// setValue 不改变内容,正常 _render 会跳过
|
||||
ed.setValue('# test', { silent: true });
|
||||
// refresh 强制重渲染
|
||||
ed.refresh();
|
||||
// 内容一致,预览应一致
|
||||
expect(ed.previewEl.innerHTML).toBe(first);
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('focus/blur 监听器接收正确参数', () => {
|
||||
document.body.innerHTML = '';
|
||||
const c = document.createElement('div');
|
||||
document.body.appendChild(c);
|
||||
const ed = new MarkdownEditor(c, {});
|
||||
let focusArg;
|
||||
ed.on('focus', (...args) => { focusArg = args; });
|
||||
ed.textarea.dispatchEvent(new Event('focus', { bubbles: true }));
|
||||
// focus 事件只传 editor 一次
|
||||
expect(focusArg.length).toBe(1);
|
||||
expect(focusArg[0]).toBe(ed);
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('destroy 后 focus/blur 不抛错', () => {
|
||||
document.body.innerHTML = '';
|
||||
const c = document.createElement('div');
|
||||
document.body.appendChild(c);
|
||||
const ed = new MarkdownEditor(c, {});
|
||||
ed.destroy();
|
||||
expect(() => ed.focus()).not.toThrow();
|
||||
expect(() => ed.blur()).not.toThrow();
|
||||
expect(ed.isDisabled()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -350,6 +350,11 @@ describe('slugify', () => {
|
||||
test('去除首尾连字符', () => {
|
||||
expect(slugify('-hello-')).toBe('hello');
|
||||
});
|
||||
|
||||
test('slugify 空/特殊字符输入返回兜底值', () => {
|
||||
expect(slugify('')).toBe('heading');
|
||||
expect(slugify('###')).toBe('heading');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseMarkdown - v0.1.2 新语法', () => {
|
||||
|
||||
Reference in New Issue
Block a user