mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-04 15:13:41 +08:00
When editing posts in the rich text editor, custom date formats and
advanced options (recurring, timezones, countdown, displayedTimezone)
were silently dropped. Users who carefully configured dates via the
Advanced Mode dialog would lose those settings as soon as they touched
the post in rich text mode.
This happened because the rich-editor-extension only tracked the basic
date/time/timezone attributes, ignoring everything else. Similarly,
copy-pasting date ranges would crash with "No value supplied for
attribute fromDate" because the parseDOM logic was reading attributes
from the wrapper span instead of the inner date spans.
Changes:
- Extend `formatLocalDate` to accept all LocalDateBuilder options so
dates render correctly with custom formats in the editor
- Update rich-editor-extension to parse, store, and serialize all
date attributes for both single dates and date ranges
- Fix date range copy/paste by querying the inner spans via
`dom.querySelector('[data-range="from"]')` instead of reading from
the wrapper element
- Add shared `serializeBBCodeAttr` and `buildBBCodeAttrs` helpers to
`discourse/lib/text.js` that only quote values when necessary
(whitespace or `]` characters)
- Refactor local-dates, poll, calendar, and chat plugins to use the
shared BBCode serialization helpers, eliminating duplicated logic
Internal ref - t/165719
**MARKDOWN (reference)**
<img width="1477" height="548" alt="2025-12-18 @ 18 20 25"
src="https://github.com/user-attachments/assets/f7a20835-ec09-4b41-aff7-6894451fae72"
/>
**RTE (before)**
<img width="759" height="549" alt="2025-12-18 @ 18 22 36"
src="https://github.com/user-attachments/assets/ea914a84-d087-43b6-9007-5807523a6c7c"
/>
**RTE (after)**
<img width="762" height="547" alt="2025-12-18 @ 18 20 35"
src="https://github.com/user-attachments/assets/79c6c70f-80b2-44ff-a1a5-f2564c53b3da"
/>
58 lines
2.9 KiB
JavaScript
58 lines
2.9 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/poll/lib/rich-editor-extension";
|
|
|
|
module(
|
|
"Integration | Component | prosemirror-editor - poll plugin extension",
|
|
function (hooks) {
|
|
setupRenderingTest(hooks);
|
|
|
|
hooks.beforeEach(function () {
|
|
this.siteSettings.rich_editor = true;
|
|
|
|
resetRichEditorExtensions().then(() => {
|
|
registerRichEditorExtension(richEditorExtension);
|
|
});
|
|
});
|
|
|
|
const voters =
|
|
'<div class="poll-info" contenteditable="false">0 voters</div>';
|
|
|
|
Object.entries({
|
|
"regular poll": [
|
|
"[poll]\n* Option 1\n* Option 2\n[/poll]\n\n",
|
|
`<div class="poll"><ul data-tight="true"><li><p>Option 1</p></li><li><p>Option 2</p></li></ul>${voters}</div>`,
|
|
"[poll]\n* Option 1\n* Option 2\n\n[/poll]\n\n",
|
|
],
|
|
"multiple choice poll": [
|
|
"[poll type=multiple min=1 max=2]\n* Option 1\n* Option 2\n* Option 3\n[/poll]",
|
|
`<div class="poll" data-poll-type="multiple" data-poll-max="2" data-poll-min="1"><ul data-tight="true"><li><p>Option 1</p></li><li><p>Option 2</p></li><li><p>Option 3</p></li></ul>${voters}</div>`,
|
|
"[poll type=multiple max=2 min=1]\n* Option 1\n* Option 2\n* Option 3\n\n[/poll]\n\n",
|
|
],
|
|
"public poll": [
|
|
"[poll public=true]\n* Option 1\n* Option 2\n[/poll]",
|
|
`<div class="poll" data-poll-public="true"><ul data-tight="true"><li><p>Option 1</p></li><li><p>Option 2</p></li></ul>${voters}</div>`,
|
|
"[poll public=true]\n* Option 1\n* Option 2\n\n[/poll]\n\n",
|
|
],
|
|
"poll with name, results, close date, groups": [
|
|
"[poll name=PollName chartType=pie results=always anonymous=true close=2021-01-01 groups=group1,group2]\n* Option 1\n* Option 2\n[/poll]",
|
|
`<div class="poll" data-poll-results="always" data-poll-name="PollName" data-poll-chart-type="pie" data-poll-close="2021-01-01" data-poll-groups="group1,group2"><ul data-tight="true"><li><p>Option 1</p></li><li><p>Option 2</p></li></ul>${voters}</div>`,
|
|
"[poll results=always name=PollName chartType=pie close=2021-01-01 groups=group1,group2]\n* Option 1\n* Option 2\n\n[/poll]\n\n",
|
|
],
|
|
"poll with bar chart type": [
|
|
"[poll chartType=bar]\n* Option 1\n* Option 2\n[/poll]",
|
|
`<div class="poll" data-poll-chart-type="bar"><ul data-tight="true"><li><p>Option 1</p></li><li><p>Option 2</p></li></ul>${voters}</div>`,
|
|
"[poll chartType=bar]\n* Option 1\n* Option 2\n\n[/poll]\n\n",
|
|
],
|
|
}).forEach(([name, [markdown, html, expectedMarkdown]]) => {
|
|
test(name, async function (assert) {
|
|
await testMarkdown(assert, markdown, html, expectedMarkdown);
|
|
});
|
|
});
|
|
}
|
|
);
|