Jul 24 - Update Rich-text editor to enhance table editor

This commit is contained in:
2026-07-24 10:42:22 -04:00
parent 10a8658b67
commit db2d1795b4
10 changed files with 125 additions and 85 deletions
+23 -15
View File
@@ -113,21 +113,29 @@ shows only `is_published` topics (sections with no published topics are hidden).
shows the editor). If Quill fails to load, the textarea stays usable and a save
never wipes the body. The submit handler keeps the body when it contains an
`img`/`table` even though `getText()` is empty for embed-only content.
- **Images & tables:** the custom `#editor-toolbar` has a `ql-image` button and a
`.ql-table-op` button group. Images upload via `POST /admin/upload`
(`login_required`, CSRF via `X-CSRFToken` header): extension allowlist +
magic-byte sniff (`_sniff_image`, SVG excluded), 8 MB cap, saved as a random
`uuid4().hex.<ext>` under `static/uploads/`, returns `{url}`; the handler
`insertEmbed`s it (no base64 → DB stays small). Tables use Quill 2's *built-in*
`table: true` module (`getModule('table')` → insertTable/insertRow…/deleteTable) —
no third-party plugin. Table buttons `preventDefault` on mousedown to keep the
cell selection; cell-dependent ops are wrapped in try/catch.
- **Images:** the custom `#editor-toolbar` has a `ql-image` button. Images upload
via `POST /admin/upload` (`login_required`, CSRF via `X-CSRFToken` header):
extension allowlist + magic-byte sniff (`_sniff_image`, SVG excluded), 8 MB cap,
saved as a random `uuid4().hex.<ext>` under `static/uploads/`, returns `{url}`;
the handler `insertEmbed`s it (no base64 → DB stays small).
- **Tables:** `quill-table-better` 1.2.3 vendored (`static/vendor/quill-table-better.js`
+ `.css`, UMD → reads global `Quill`, exposes `QuillTableBetter`; self-contained,
no CDN/CSP issues). Registered as `modules/table-better`; Quill 2's basic
`table` module is disabled (`table: false`). The `ql-table-better` toolbar button
opens a size picker to insert; **column/row drag-resize** and a floating **cell
menu (alignment, borders, background, merge/split)** are the module's own UI — no
custom wiring. Init is guarded by `typeof QuillTableBetter` so a failed vendor
load still leaves a working editor + textarea. Registration and keyboard bindings
(`QuillTableBetter.keyboardBindings`) live in `topic_form.html`.
- **Sanitize on save:** `sanitize_html()` (bleach) runs on every `body_html`
write — allowlist `ALLOWED_TAGS`/`ALLOWED_ATTRS` (now includes `img` + table
tags + `data-row`), `strip=True`; bleach restricts URL protocols on both `href`
and `img src` to http/https/mailto, blocking `javascript:` and `data:` (uploads
are relative `/static` paths). Empty / `<p><br></p>` editor content is stored as
NULL. The public page renders `body_html` via `Markup`, sanitized at the source.
write — `ALLOWED_TAGS`/`ALLOWED_ATTRS` cover `img` + full table tags with
`colspan/rowspan/data-*/style`; a `CSSSanitizer` (bleach[css] + `tinycss2`)
filters inline `style` to `ALLOWED_CSS_PROPS` (width/height/padding/text-align/
vertical-align/background-color/border*) so the table editor's sizing & alignment
survive but `position`, `behavior`, `url(javascript:)` etc. are stripped. bleach
also restricts URL protocols on `href`/`img src` to http/https/mailto (blocks
`javascript:`/`data:`; uploads are relative `/static` paths). Empty / `<p><br></p>`
is stored NULL. Public renders `body_html` via `Markup`, sanitized at the source.
- **Draft/publish:** `topic.is_published` (default 1, so existing rows stay
live). Public route filters to `Section.published_topics` and drops sections
with none. Admin: per-topic `/topic/<id>/toggle` (quick button) + a Published
@@ -150,7 +158,7 @@ shows only `is_published` topics (sections with no published topics are hidden).
sudo mysql < add_admin.sql # audit_log (existing DBs)
sudo mysql < add_publish.sql # topic.is_published (existing DBs)
# .env: SECRET_KEY, ADMIN_USERNAME, ADMIN_PASSWORD_HASH, SESSION_COOKIE_SECURE=1
sudo ./venv/bin/pip install -r requirements.txt # includes bleach
sudo ./venv/bin/pip install -r requirements.txt # bleach[css] + tinycss2 (CSS sanitize)
sudo -u jqc mkdir -p static/uploads # in-body image uploads (writable)
sudo systemctl restart jqc-features # Quill 2 assets are static — no other step
# fail2ban: