mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-12 16:44:46 +08:00
This PR merges the bulleted and numbered list buttons into a single
Lists dropdown menu in the composer toolbar and introduces a new
checklist option to the dropdown.
* Combines individual list buttons into a single "Lists" dropdown
* Adds a new checklist option within the list menu (integrated via the
checklist plugin)
* ProseMirror/Rich Editor:
* Added logic for checklist continuation on Enter and exit on double
Enter
* Implemented Backspace handling to manage checkbox removal and line
joining
* Added cursor positioning constraints to prevent selection before the
checkbox
* Added handler to toggle the check when clicked
Updated `addComposerToolbarPopupMenuOption` to allow plugins to register
custom options specifically within a popup menu through its identifier
<img width="467" height="190" alt="image"
src="https://github.com/user-attachments/assets/91205405-3d6f-4e04-85f5-800e6b9d95b4"
/>
80 lines
3.2 KiB
JavaScript
80 lines
3.2 KiB
JavaScript
import { module, test } from "qunit";
|
|
import {
|
|
registerRichEditorExtension,
|
|
resetRichEditorExtensions,
|
|
} from "discourse/lib/composer/rich-editor-extensions";
|
|
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
|
import { testMarkdown } from "discourse/tests/helpers/rich-editor-helper";
|
|
import richEditorExtension from "discourse/plugins/checklist/lib/rich-editor-extension";
|
|
|
|
module(
|
|
"Integration | Component | prosemirror-editor - checklist plugin extension",
|
|
function (hooks) {
|
|
setupRenderingTest(hooks);
|
|
|
|
hooks.beforeEach(function () {
|
|
this.siteSettings.rich_editor = true;
|
|
|
|
resetRichEditorExtensions().then(() => {
|
|
registerRichEditorExtension(richEditorExtension);
|
|
});
|
|
});
|
|
|
|
const checked =
|
|
'<span class="chcklst-box checked fa fa-square-check-o" contenteditable="false" draggable="true"></span>';
|
|
const unchecked =
|
|
'<span class="chcklst-box fa fa-square-o" contenteditable="false" draggable="true"></span>';
|
|
|
|
Object.entries({
|
|
"renders unchecked checkbox correctly": [
|
|
"[ ] todo item",
|
|
`<p>${unchecked} todo item</p>`,
|
|
"[ ] todo item",
|
|
],
|
|
"renders checked checkbox correctly": [
|
|
"[x] completed item",
|
|
`<p>${checked} completed item</p>`,
|
|
"[x] completed item",
|
|
],
|
|
"handles multiple checkboxes in a single paragraph": [
|
|
"[] first task [x] second task",
|
|
`<p>${unchecked} first task ${checked} second task</p>`,
|
|
"[ ] first task [x] second task",
|
|
],
|
|
"handles checkboxes in lists": [
|
|
"* [ ] unchecked list item\n* [x] checked list item",
|
|
`<ul data-tight="true"><li class="has-checkbox"><p>${unchecked} unchecked list item</p></li><li class="has-checkbox"><p>${checked} checked list item</p></li></ul>`,
|
|
"* [ ] unchecked list item\n* [x] checked list item",
|
|
],
|
|
"handles checkboxes with formatting": [
|
|
"[ ] *italics* and [x] **bold**",
|
|
`<p>${unchecked} <em>italics</em> and ${checked} <strong>bold</strong></p>`,
|
|
"[ ] *italics* and [x] **bold**",
|
|
],
|
|
"does not render escaped checkbox": [
|
|
"\\[x] not a checkbox",
|
|
"<p>[x] not a checkbox</p>",
|
|
"\\[x\\] not a checkbox",
|
|
],
|
|
"handles escaped checkbox followed by real checkbox": [
|
|
"\\[x] escaped [x] real",
|
|
`<p>[x] escaped ${checked} real</p>`,
|
|
"\\[x\\] escaped [x] real",
|
|
],
|
|
"preserves checkbox state in ordered lists": [
|
|
"1. [ ] unchecked\n2. [x] checked",
|
|
`<ol data-tight="true"><li><p>${unchecked} unchecked</p></li><li><p>${checked} checked</p></li></ol>`,
|
|
"1. [ ] unchecked\n2. [x] checked",
|
|
],
|
|
"handles nested list with checkboxes": [
|
|
"* [ ] parent\n * [x] child",
|
|
`<ul data-tight="true"><li class="has-checkbox"><p>${unchecked} parent</p><ul data-tight="true"><li class="has-checkbox"><p>${checked} child</p></li></ul></li></ul>`,
|
|
"* [ ] parent\n * [x] child",
|
|
],
|
|
}).forEach(([name, [markdown, html, expectedMarkdown]]) => {
|
|
test(name, async function (assert) {
|
|
await testMarkdown(assert, markdown, html, expectedMarkdown);
|
|
});
|
|
});
|
|
}
|
|
);
|