FIX: allow quote-less details BBCode

In 53b3d2f0dc we introduced a stricter BBCode Tag parser. It prevents having "values" with spaces when they're not surrounded by a valid pair of quotes.

The `[details=` BBCode Tag is popular enough that it's worth adding a special case for it (especially since it doesn't support other parameters).

This also adds the Finnish pair of quotes.

Context - https://meta.discourse.org/t/details-accepts-only-one-word-as-summary/313019
This commit is contained in:
Régis Hanol 2024-06-24 12:33:24 +02:00
parent 55da8a7701
commit 3927b27f34
2 changed files with 30 additions and 31 deletions

View File

@ -34,15 +34,9 @@ function trailingSpaceOnly(src, start, max) {
return true;
}
// Easiest case is the closing tag which never has any attributes
const BBCODE_CLOSING_TAG_REGEXP = /^\[\/([-\w]+)\]/i;
// Old case where we supported attributes without quotation marks
const BBCODE_QUOTE_TAG_REGEXP = /^\[quote=([-\w,: ]+)\]/i;
// Most common quotation marks.
// More can be found at https://en.wikipedia.org/wiki/Quotation_mark
const QUOTATION_MARKS = [`""`, `''`, `“”`, ``, `„“`, ``, `«»`, ``];
const QUOTATION_MARKS = [`""`, `''`, `“”`, `””`, ``, `„“`, ``, `«»`, ``];
const QUOTATION_MARKS_NO_MATCH = QUOTATION_MARKS.map(
([a, b]) => `${a}[^${b}]+${b}`
@ -52,6 +46,15 @@ const QUOTATION_MARKS_WITH_MATCH = QUOTATION_MARKS.map(
([a, b]) => `${a}([^${b}]+)${b}`
).join("|");
// Easiest case is the closing tag which never has any attributes
const BBCODE_CLOSING_TAG_REGEXP = /^\[\/([-\w]+)\]/i;
// Old case where we supported attributes without quotation marks
const BBCODE_QUOTE_OR_DETAILS_TAG_REGEXP = new RegExp(
`^\\[(quote|details)=(\\s*[^${QUOTATION_MARKS.join("")}].+?)\\]`,
"i"
);
// This is used to match a **valid** opening tag
// NOTE: it does not match the closing bracket "]" because it makes the regexp too slow
// due to the backtracking. So we check for the "]" manually.
@ -86,18 +89,18 @@ export function parseBBCodeTag(src, start, max, multiline) {
};
}
// CASE 2 - [quote=...] tag (without quotes)
m = BBCODE_QUOTE_TAG_REGEXP.exec(text);
// CASE 2 - [quote=...] or [details=...] tag (without quotes)
m = BBCODE_QUOTE_OR_DETAILS_TAG_REGEXP.exec(text);
if (m && m[0] && m[1]) {
if (m && m[0] && m[1] && m[2]) {
if (multiline && !trailingSpaceOnly(src, start + m[0].length, max)) {
return null;
}
return {
tag: "quote",
tag: m[1],
length: m[0].length,
attrs: { _default: m[1] },
attrs: { _default: m[2] },
};
}

View File

@ -1,23 +1,16 @@
import { setupTest } from "ember-qunit";
import { module, test } from "qunit";
import { cook } from "discourse/lib/text";
const opts = {
siteSettings: {
enable_emoji: true,
emoji_set: "twitter",
highlighted_languages: "json|ruby|javascript",
default_code_lang: "auto",
},
censoredWords: "shucks|whiz|whizzer",
getURL: (url) => url,
};
module("lib:details-cooked-test", (hooks) => {
setupTest(hooks);
module("lib:details-cooked-test", function () {
test("details", async function (assert) {
test("details", async (assert) => {
const testCooked = async (input, expected, text) => {
const cooked = (await cook(input, opts)).toString();
const cooked = (await cook(input)).toString();
assert.strictEqual(cooked, expected, text);
};
await testCooked(
`<details><summary>Info</summary>coucou</details>`,
`<details><summary>Info</summary>coucou</details>`,
@ -25,12 +18,15 @@ module("lib:details-cooked-test", function () {
);
await testCooked(
"[details=testing]\ntest\n[/details]",
`<details>
<summary>
testing</summary>
<p>test</p>
</details>`
`[details=test'ing all the things]\ntest\n[/details]`,
`<details>\n<summary>\ntest'ing all the things</summary>\n<p>test</p>\n</details>`,
"details with spaces and a single quote"
);
await testCooked(
`[details=”test'ing all the things”]\ntest\n[/details]`,
`<details>\n<summary>\ntest'ing all the things</summary>\n<p>test</p>\n</details>`,
"details surrounded by finnish double quotes"
);
});
});