Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,27 @@ export class QuestionsAddCard implements BlockToolConstructable {
static get toolbox() {
return {
title: "Questions",
icon: "?",
icon: "?",
};
}

/**
* Opt this block's data out of EditorJS's own sanitizer.
*
* A block tool without a `sanitize` config inherits the merged tag list of the
* enabled inline tools, and EditorJS applies it to every string in the saved
* data. That list has no `<br>` or `<div>`, so saving an article silently
* stripped the line breaks out of question/explanation rich text (#372).
*
* `true` means "leave this value as-is" in EditorJS's sanitizer. That is safe
* here because question rich text is sanitized by `sanitizeQuestionRichText`
* with an explicit allow-list — on write in the editor and again at render
* time — rather than relying on EditorJS.
*/
static get sanitize() {
return {
instanceId: true,
questions: true,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ const RichTextEditor = forwardRef<HTMLDivElement, Props>(function RichTextEditor

return (
<div className="relative">
{/*
`whitespace-pre-wrap` matches the learner renderer. Questions written
before this box became rich text store their line breaks as newline
characters, and HTML whitespace collapsing rendered each of those as
a single space, so opening an older explanation looked like its
paragraphs had been merged together (#372).
*/}
<div
ref={editorRef}
contentEditable
Expand All @@ -252,7 +259,7 @@ const RichTextEditor = forwardRef<HTMLDivElement, Props>(function RichTextEditor
document.execCommand("insertHTML", false, sanitizeQuestionRichText(html || text));
emitChange();
}}
className="min-h-24 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&:empty]:before:pointer-events-none [&:empty]:before:text-muted-foreground [&:empty]:before:content-[attr(data-placeholder)] [&_mark]:rounded [&_mark]:bg-yellow-200 [&_mark]:px-0.5 [&_mark]:text-gray-950"
className="min-h-24 w-full whitespace-pre-wrap rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&:empty]:before:pointer-events-none [&:empty]:before:text-muted-foreground [&:empty]:before:content-[attr(data-placeholder)] [&_mark]:rounded [&_mark]:bg-yellow-200 [&_mark]:px-0.5 [&_mark]:text-gray-950"
/>
{toolbar && (
<div
Expand Down
Loading