fix(submit): repair placeholder, code block, hidden block and settings toggles
- placeholder: hide the body ::before hint once the editor body has focus, so clicking an empty document no longer leaves the hint sitting under the caret - code block: edit as a bare <pre> and convert to pre > code on save. TinyMCE treats pre > code as an inline boundary, so typing there leaked into the following paragraph; Enlighter also splits lines on newlines, so the <br> the editor produced rendered the whole block as one overflowing line - code block: align the iframe rendering with Enlighter (Menlo 13px/1.4, #f8f9fa, 8px radius, 12px 17px padding, nowrap) in both content CSS files - code block: move the caret into the block after insertion - hidden block: hang the block-delete overlay on documentElement instead of body. data-mce-bogus only skips serialization, so the extra body child made mceInsertContent wipe the document and drop the first hidden block - settings: give the toggle a real 44x24 hit area, align it to the top of the row, add aria-labels and show the disabled state - styles: drop the duplicated @use/@import of publish-drawer and block-tools - media insert/embed now serialize through serializeBlocks so code blocks are never stored in editor form
This commit is contained in:
1 parent
4f9347b6aa
commit
ec582ac9f9
11 files changed
+248
-56
No files matched your search
@@ -207,14 +207,16 @@ test('fixed top toolbar has TinyMCE formatting, media, and extension actions', (
|
||||
// 表格 / 公式 / 注释 / 代码都走参数弹窗,不再是固定内容。
|
||||
assert.match(appSource, /<BlockDialog/);
|
||||
assert.match(appSource, /setBlockDialog\(kind as BlockDialogKind\)/);
|
||||
// 代码块直接插入,不弹窗、不选语言。
|
||||
assert.match(appSource, /insertHtml\(codeBlockMarkup\(\)\)/);
|
||||
// 代码块直接插入,不弹窗、不选语言;插入后光标留在代码块里。
|
||||
assert.match(appSource, /insertCodeBlock\(\)/);
|
||||
assert.match(appSource, /editor\.selection\.setCursorLocation\(pre, 0\)/);
|
||||
assert.doesNotMatch(appSource, /setCodeDialog/);
|
||||
assert.doesNotMatch(read('assets/creator-studio/src/components/block-dialog.tsx'), /kind === 'code'/);
|
||||
assert.match(read('assets/creator-studio/src/components/block-dialog.tsx'), /onSubmit\(\{ kind, rows: clamp\(rows, 1, 20\), cols: clamp\(cols, 1, 10\), header, striped \}\)/);
|
||||
assert.match(appSource, /onInsertBlock=\{insertBlock\}/);
|
||||
assert.match(appSource, /onInsertQuote=\{insertQuote\}/);
|
||||
const markup = read('assets/creator-studio/src/utils/block-markup.ts');
|
||||
const serialize = read('assets/creator-studio/src/utils/serialize.ts');
|
||||
assert.match(markup, /jio-math/);
|
||||
// 引用沿用主题的 quote_q 结构与配色类。
|
||||
assert.match(markup, /quote_q/);
|
||||
@@ -225,16 +227,23 @@ test('fixed top toolbar has TinyMCE formatting, media, and extension actions', (
|
||||
assert.match(markup, /data-jio-math-source/);
|
||||
assert.match(read('assets/creator-studio/src/utils/serialize.ts'), /\[jio_math display=/);
|
||||
assert.match(read('assets/creator-studio/src/utils/serialize.ts'), /\[jio_footnote\]/);
|
||||
// 代码块与前台文章页一致:pre > code,不写语言 / 主题属性。
|
||||
assert.match(markup, /<pre><code><\/code><\/pre>/);
|
||||
// 代码块:编辑器里是裸 pre(TinyMCE 把 pre > code 当行内边界,光标落不进去),
|
||||
// 保存时才由 serializeBlocks 套回前台的 pre > code。不写语言 / 主题属性。
|
||||
assert.match(markup, /<pre><br><\/pre><p><\/p>/);
|
||||
assert.doesNotMatch(markup, /<pre><code><\/code><\/pre>/);
|
||||
assert.match(serialize, /querySelectorAll\('pre'\)[\s\S]*?serializeCodeBlock/);
|
||||
assert.match(serialize, /createElement\('code'\)/);
|
||||
assert.match(serialize, /hydrateCodeBlock/);
|
||||
assert.doesNotMatch(markup, /enlighter-pre/);
|
||||
assert.doesNotMatch(markup, /data-enlighter-language/);
|
||||
assert.doesNotMatch(read('assets/creator-studio/src/editor-runtime.ts'), /syncCodeLabels/);
|
||||
assert.doesNotMatch(read('assets/creator-studio/src/components/block-dialog.tsx'), /CODE_LANGUAGES/);
|
||||
// 外观:编辑器 iframe 与前台投稿编辑器保持同一套代码块样式。
|
||||
// 外观:编辑器 iframe 与前台 Enlighter 渲染值一致(不折行、浅底、8px 圆角)。
|
||||
const editorCss = read('assets/css/frontend/pages/submit-editor.css');
|
||||
assert.doesNotMatch(editorCss, /\.enlighter-pre/);
|
||||
assert.match(editorCss, /pre code \{/);
|
||||
assert.match(editorCss, /pre \{[^}]*white-space: pre;/);
|
||||
assert.match(editorCss, /pre \{[^}]*background: #f8f9fa/);
|
||||
// 隐藏内容沿用 .tinymce-hide 结构,短代码作为文本落库。
|
||||
assert.match(markup, /tinymce-hide/);
|
||||
assert.match(markup, /\[jio_hide mode="login"\]/);
|
||||
@@ -301,13 +310,16 @@ test('top bar is masthead + centered toolbar, with no brand text in the toolbar
|
||||
assert.doesNotMatch(rest, /'home'\s*=>\s*esc_url_raw\(\$home\)/);
|
||||
});
|
||||
|
||||
test('block delete overlay lives inside the editor iframe and stays hidden', () => {
|
||||
test('block delete overlay lives outside the editable body and stays hidden', () => {
|
||||
const runtime = read('assets/creator-studio/src/editor-runtime.ts');
|
||||
const contentStyle = read('assets/creator-studio/src/editor-content-style.ts');
|
||||
const pageStyles = read('assets/creator-studio/src/styles/_block-tools.scss');
|
||||
|
||||
// 浮层插在 TinyMCE iframe 的 body 里。
|
||||
assert.match(runtime, /doc\.body\.appendChild\(bar\)/);
|
||||
// 浮层挂在 iframe 的 documentElement 上,不能进 body:data-mce-bogus 只跳过
|
||||
// 序列化,body 里多一个非常规子节点会让 mceInsertContent 把整篇正文清空
|
||||
// (表现为「第一次点隐藏块没有插进正文」)。
|
||||
assert.match(runtime, /doc\.documentElement\.appendChild\(bar\)/);
|
||||
assert.doesNotMatch(runtime, /doc\.body\.appendChild\(bar\)/);
|
||||
assert.match(runtime, /bar\.id = 'jio-block-actions'/);
|
||||
// iframe 是独立文档:页面级样式表管不到它,隐藏规则必须写在 content_style。
|
||||
assert.match(contentStyle, /#jio-block-actions\s*\{[^}]*position:\s*absolute/);
|
||||
|
||||
Reference in new issue
Block a user