Skip to content

last update - #375

Merged
saa938 merged 31 commits into
frqfrom
main
Aug 19, 2026
Merged

last update#375
saa938 merged 31 commits into
frqfrom
main

Conversation

@saa938

@saa938 saa938 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

saa938 and others added 30 commits August 6, 2026 12:39
Adds bold/italic/underline/highlight/link support to the Image block's
caption field, with a floating formatting toolbar and a link edit/remove
popover. Formatting is stored as structured segments (text + marks) rather
than raw HTML, sanitized on render, and shared between the editor and the
published-article renderers so output stays consistent.
…captions

- isValidUrl accepted "/\host" as a safe root-relative path, but browsers
  treat backslash like forward slash in http(s) URLs, so it actually
  resolves to an arbitrary external host (verified with the WHATWG URL
  parser) -- the same bypass the "//host" check was meant to close.
- The Highlight toolbar button only ever wrapped selections in a new
  <mark>, with no way to remove an existing highlight.
- The floating toolbar and link popover never repositioned below the
  selection, so they clamped to the viewport edge and covered the
  selected text when there wasn't room above.
- Removed an unused captionHostMap WeakMap that was written to but never
  read.
Add rich-text formatting to image captions (fixes #337)
CustomImage.save() in the EditorJS image tool copied _data.centerImage
straight through, but centerImage is a custom action (not one of
@editorjs/image's built-in tunes), so it is never initialized and stays
undefined until an author explicitly toggles "Center image". Firestore's
setDoc() rejects any field holding a literal undefined, which was the
cause of the reported "Unsupported field value: undefined" errors when
saving articles containing images.
…centerimage

Fix undefined centerImage crashing article saves with images
The base @editorjs/image `set data()` accessor copies only `file`, `caption`,
and its three built-in tunes into `_data`, so every custom key is dropped when
a block is constructed. The constructor already restores `altText` and
`richCaption` for this reason; `centerImage` was left out.

Because `blocks.update()` composes a new block from `Object.assign({},
await block.data, patch)`, it round-trips through `save()` and the
constructor — so replacing an image reset centering to false, contradicting
the replace dialog's promise that styling is kept. Reopening an article lost
the setting the same way.
Two fixes to the rich-text question editor.

Enter no longer starts a new line. emitChange restored the caret on every
input, not just when sanitizing had replaced innerHTML and destroyed the
selection. Because a <br> contributes no characters to the plain-text offset
model, restoring on a freshly created empty line mapped the caret back onto
the end of the previous line, so "one", Enter, "two" produced
"onetwo<div><br></div>". Restore only when the rewrite actually happened, and
let callers that mutate the DOM themselves pass their offsets explicitly.

Highlight could not be turned off. removeHighlightFromSelection unwrapped only
the marks that range extraction pulled into the fragment, and extraction sees a
mark only when the range fully contains it. Selecting the highlighted words --
the natural gesture -- makes that mark the range's common ancestor, so nothing
was found and the highlight stayed. The branch guard made it worse: it read
active.highlight, derived from anchorNode.closest("mark"), which is true
exactly for the selections where removal did nothing and false for the one
selection where it worked, where the code instead added a second mark and
produced nested <mark> elements.

Unwrap by intersection instead, and derive the toggle state from the whole
range rather than the anchor, which also stops the reported state from
depending on drag direction.

Verified in a browser: Enter now yields "one<div>two</div>" and three lines
nest correctly; highlight adds and removes across all three selection
geometries with no nested marks; the LaTeX guard, bold toggling, mid-string
typing, and selection preservation across a sanitizer rewrite are unchanged.
Showing the completion page unmounts Header, so continuing on to the
results remounts it with a fresh countdown at the full test duration.
When that timer expired it re-fired setSubmitted(true), which now routes
through handleSetSubmitted and flipped showCompletionPage back on --
throwing the user from their results back to the completion page, once
per test duration, indefinitely. Measured on a 12-second test: it
returned 11.8s after Continue and again 11.5s later, interrupting a
question explanation mid-read.

Ignore repeat submits so the restarted timer can't re-trigger it.

Also fix the footer's primary button on the results page. Its label was
keyed on currentQuestionIndex === questions.length - 1, but submitting
resets the index to 0, so it read "Next" while actually triggering the
exit confirm. Branch on showReviewPage first; pre-submit labels are
unchanged, since the review page was previously only reachable from the
last question.
…-issue

fix completion page to show test results
Line breaks typed into the Explanation box disappeared. Two separate
causes, both from the rich-text question editor:

EditorJS stripped them on save. QuestionsAddCard declared no `sanitize`
config, so EditorJS sanitized the saved block data with the merged tag
list of the enabled inline tools, which contains no `<br>` or `<div>`.
Saving an article rewrote

  First.<div><br></div><div>Second.</div>

as `First.Second.`. Declaring `sanitize` opts the block out; question
rich text is already sanitized by `sanitizeQuestionRichText` with an
explicit allow-list, on write and again at render.

The editor collapsed legacy newlines. The box is a `contentEditable`,
so `white-space: normal` applied, but questions written before it became
rich text store their breaks as newline characters. HTML collapsed each
one to a space, so opening an older explanation showed its paragraphs
already merged even though the stored data and the learner view were
both fine. `whitespace-pre-wrap` matches the learner renderer.
…eaks

Preserve line breaks in question rich text (fixes #372)
Copilot AI lite review requested due to automatic review settings August 19, 2026 03:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@saa938
saa938 merged commit c528939 into frq Aug 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants