## 2.3.12 — 2026-06-04

### Security
- **Stored XSS in rendered Markdown fixed** — the renderer uses Parsedown with `setSafeMode(false)` / `setMarkupEscaped(false)` (to keep rich HTML), and `cleanAndSanitize()` only stripped `<script>` tags. Inline event handlers (`<img src=x onerror=…>`, `<div onmouseover=…>`) and `javascript:` URLs (`[x](javascript:…)`, `<a href="javascript:…">`) passed straight through and executed when the post was viewed. `cleanAndSanitize()` now routes the output through the new core `Sanitizer::stripXss()`, which removes `<script>`, all `on*` handlers, dangerous URL protocols and non-image data-URIs **without** stripping legitimate rich HTML (images, links, code blocks, embeds still render).
  *Files changed:* `libs/EasyMDEHelper.php` (+ core `app/Core/Sanitizer.php`).

## 2.3.11 — 2026-05-31

### Added

- **Portuguese (`pt.json`) and Chinese (`zh.json`) translations** — Full translation of the 203 plugin keys to align with the now-6-language Flatboard standard (fr/en/de/pt/zh/pl). The Polish (`pl.json`) file was contributed by [@nononsense](https://flatboard.org/u/nononsense) via [forum thread #177](https://flatboard.org/d/177-pakiet-jzyka-polskiego-the-polish-language-pack).
  *Files changed:* `langs/pt.json` (new), `langs/zh.json` (new).

---

## 2.3.9 — 2026-05-17

### Fixed

- **Tables broken when content is saved with CRLF line endings** — Same root cause as TUIEditor 1.3.8: `\r` before each `\n` matched `[^|\n]` in the injection regex, inserting blank lines between every table row. Fixed by normalising `\r\n` → `\n` before any preprocessing.
  *Files changed:* `libs/EasyMDEHelper.php`.

---

## 2.3.8 — 2026-05-17

### Fixed

- **Tables still broken after 2.3.7 — blank lines already stored in content** — The 2.3.7 trailing-spaces fix prevented new bad injections, but posts saved by earlier buggy versions already had blank lines between every table row baked into the stored Markdown. Parsedown treats pipe rows separated by blank lines as standalone paragraphs, so the table was silently discarded. Fixed by collapsing existing blank lines between table rows (`(\|[^\n]*)\n\n+(\|)`) before the injection step, so both old and new content is normalised at render time.
  *Files changed:* `libs/EasyMDEHelper.php`.

---

## 2.3.7 — 2026-05-16

### Fixed

- **Tables broken when rows have trailing spaces** — The blank-line injection regex `([^|\n])\n(\|)` checks the character immediately before `\n`. If a table row ends with `| ` (pipe + trailing space), that character is a space, not `|`, so the injection fires between every row — inserting blank lines that cause Parsedown to treat each row as a standalone paragraph. Fixed by stripping trailing spaces and tabs from pipe-terminated lines before the injection step.
  *Files changed:* `libs/EasyMDEHelper.php`.

---

## 2.3.6 — 2026-04-28

### Fixed

- **Blank-line injection broke tables (2.3.5 regression)** — The 2.3.5 regex `([^\n])\n(\|)` also matched the `|` at the end of a table header row, inserting a blank line between the header and the separator. Parsedown then treated the separator as a standalone paragraph and silently discarded the entire table. Fixed by changing the preceding-character class to `[^|\n]` so the injection only fires when the previous line does not itself end with `|`.
  *Files changed:* `libs/EasyMDEHelper.php`.

---

## 2.3.5 — 2026-04-27

### Fixed

- **Markdown tables not rendered when immediately preceded by a paragraph** — Parsedown requires a blank line before a table block; without it the header row is absorbed into the preceding paragraph and the table is silently discarded. Added blank-line injection before table openers (`([^\n])\n(\|)`) matching the existing code-fence normalisation pattern.
  *Files changed:* `libs/EasyMDEHelper.php`.

---

## 2.3.4 — 2026-04-10

### Fixed
- Draft auto-save was completely broken: `getEditorValue()` hook was missing a `return` statement, causing the JS function in `markdown-editor.php` to return `undefined` instead of the editor content. Auto-save sent null/empty content to the server on every save cycle. Fixed by returning `editor.value()` directly (same fix as TuiEditor v10).

## 2.3.2 — 2026-03-28

### Changed
- Added `update_url` and `changelog_url` fields to `plugin.json`. Flatboard now detects available updates and displays them in **Admin Panel > Tools > Updates**. The `changelog_url` links to the plugin's resource page on [flatboard.org](https://flatboard.org).
- Updated minimum Flatboard requirement from `>=5.0.0` to `>=5.2.0` in `plugin.json`.
