Fix editor article#36
Merged
Merged
Conversation
…bn-panel to the mousedown skip list removing the uploadFile toggle from handleSelectionChange so the image upload tab stays visible and preventing the file panel from closing when clicking the upload button
…load for image blocks and only Embed for video blocks fixes UploadTab crash by passing setLoading and disables BlockNoteView’s filePanel while delegating to a child FilePanelController for correct tab filtering
…tentional clicks by cleaning up .ProseMirror-selectednode only when the cursor is on an image block fixing the border leak after inserting an image via slash command and keeping the border visible on video blocks for proper user feedback thanks to an early return when blockType is not image
…ugin by disabling gapCursor in useCreateBlockNote eliminates all gap‑cursor navigation and blinking underscores removes the old
…s using DOM‑based targeting replaces unreliable BlockNote detection with a keydown fallback uses elementFromPoint to avoid jumps between distant blocks hides the selected bn‑visual‑media-wrapper ghost via CSS and keeps console diagnostics for gap‑cursor debugging
…d‑block arrow navigation tracks arrow direction with arrowDirRef detects empty bn‑visual‑media-wrapper ghosts in RAF and jumps to the adjacent void block instead and removes leftover debug logs
…ast void blocks by scrolling before setTextCursorPosition adding a RAF fallback for void→text transitions reducing PM auto‑scroll with scrollThreshold/scrollMargin disabling gapCursor hiding bn‑visual‑media-wrapper ghosts via CSS and applying scroll‑margin‑top for consistent nav‑bar offset
…ast void blocks by scrolling before setTextCursorPosition so ProseMirror doesn’t override manual positioning and adds a fallback for void→text transitions where the ghost wrapper disappears before RAF runs updating only ArticleForm.jsx for scroll correction and fallback
…Replace popover by targeting the tab inside .bn-panel-popover so the tab disappears for image replacement while remaining visible for video insertion
… through createYouTubeVideoSpec so valid URLs render as 16/9 iframes with pointer‑events toggle while invalid URLs trigger a toast and are removed and the viewer hides them silently updating ArticleForm.jsx and ArticleViewer.jsx to use the factory and adding a dedicated test suite
…[data-content-type="video"] in BLOCK_SELECTOR so empty native video blocks without a bn‑visual‑media-wrapper also trigger gap‑click paragraph insertion updating useCodeBlockGapClick.js accordingly
… by injecting file_blocks.add_button_text.video in applyVideoDictOverrides and fixing initial render with a DOM post‑process then adds a focused test in video-dict.test.js for the new dictionary key
…ting Backspace in capture phase, collapsing any accidental non‑collapsed DOM range on an empty gap‑click paragraph to stop ProseMirror’s deleteSelection cascade, removing all debug logs and adding two Backspace‑interception tests plus a proper afterEach unmount to avoid stale listener leakage
…ideo blocks by keeping BlockNote’s native no‑URL render in view‑only mode while overriding the placeholder button text, with changes limited to video-override-spec.js
…to restore all block attributes, drop unused YouTube regex/helpers, add <meta name="author"> for Firefox Reader Mode, revert the reader‑fallback markup experiment and clean up CSS (italic .meta-author, remove dead reader blocks). Tests updated for props/attrs compatibility and E501 fixes
…/update by reading image UUIDs from BlockNote `props`, comparing them to stored files, and deleting any unreferenced ones. Add delete() to storage ports, implement delete_file() in file_service, call it from article_service, provide idempotent SQLAlchemy delete, inject file_service in app setup, and update tests for extraction, orphan cleanup and delegation
…edit page by rendering the article content as static HTML, hidden by default and revealed in Reader Mode. Include <meta name="author">, add the inline CSS + <noscript> override and reuse the same fallback pattern as article_detail.html
…edit page by rendering the article content as static HTML, hidden by default and revealed in Reader Mode. Include <meta name="author">, add the inline CSS + <noscript> override and reuse the same fallback pattern as article_detail.html
…, updating blog_comment_application.py and the security integration test accordingly
…mes, keep white (--on-primary) by default and override to --on-surface in dark mode so the trigger stays readable on dark Shiki backgrounds
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Cette PR couvre l'ensemble des corrections apportées à l'éditeur BlockNote, l'intégration vidéo YouTube, la navigation dans les blocs void, le fallback Firefox Reader Mode, le nettoyage des fichiers orphelins, la compatibilité BlockNote v0.51+ dans le convertisseur ProseMirror, et divers correctifs CSS/session.
Modifications
🎬 Blocs vidéo YouTube
video-override-spec.js: création decreateYouTubeVideoSpecqui force les URLs YouTube uniquement. Les URLs valides s'affichent en iframe 16:9 avec basculepointer-events, les URLs invalides déclenchent un toast et sont supprimées. Le viewer (ArticleViewer.jsx) les masque silencieusementArticleForm.jsx: surcharge du label du bouton d'ajout vidéo viaapplyVideoDictOverridesavec injectionfile_blocks.add_button_text.videoarticle.css: masquage de l'onglet YouTube URL dans la popover de remplacement d'image (ciblé via.bn-panel-popover)CustomFilePanel: affichage du bon panneau selon le type de bloc — Upload pour les images, Embed pour les vidéos. Correction du crashUploadTaben passantsetLoading, désactivation dufilePanelnatif BlockNoteView au profit d'unFilePanelControllerenfanthandleSelectionChange), ajout de.bn-panelà la liste d'exclusionmousedown🧭 Navigation dans les blocs void
gapCursordansuseCreateBlockNote, élimination complète de la navigation par curseur clignotantelementFromPoint, détection de direction avecarrowDirRef, saut vers le bloc void adjacent, masquage CSS des wrappers fantômes.bn-visual-media-wrapperscrollBefore setTextCursorPosition, RAF fallback pour les transitions void→texte,scrollThreshold/scrollMarginpour réduire l'auto-scroll PM,scroll-margin-toppour un offset nav-bar cohérentdeleteSelection[data-content-type="video"]dansBLOCK_SELECTORpour que les blocs vidéo vides déclenchent aussi l'insertion de paragraphe.ProseMirror-selectednodeuniquement quand le curseur est sur un bloc image, préservation de la bordure sur les blocs vidéo📖 Fallback Firefox Reader Mode
article_detail.htmletarticle_edit.html: rendu du contenu de l'article en HTML statique, masqué par défaut via CSS (position: absolute; left: -99999px), révélé dans Firefox Reader Mode qui ignore ces styles. Balise<meta name="author">pour l'affichage natif de l'auteurarticle.css: styles pour.article-static-content(titres, paragraphes, blockquote, code, images, tableaux)..meta-authoren italiqueArticleViewer.jsx: suppression du fallback statique au montage React viauseEffect<br>après</table>dans le convertisseur pour éviter le chevauchement entre éléments adjacents (blockquote, table) quand Reader Mode supprime tous les CSS🗑️ Nettoyage des fichiers orphelins
file_management.py/file_storage_repository.py: ajout dedelete(file_id)abstrait dans les portsfile_service.py: implémentation dedelete_file(file_id)qui délègue au storagearticle_service.py:_extract_image_uuids()(fonction module-level) qui parcourt l'arbre BlockNote et extrait les UUIDs depuisprops/attrs. Appelée dansdelete_article()etupdate_article()pour supprimer les fichiers non référencéssqlalchemy_file_storage_adapter.py:delete()idempotent🔄 Compatibilité BlockNote v0.51+
utils/prosemirror_to_html.py:contenten tant qu'objet avecrows/cells(BlockNote v0.51+) tout en conservant la rétrocompatibilité ProseMirror (liste detableRow)styles: {"bold": true}(objet booléen) en plus du format legacymarks: [{"type": "bold"}]"type": "quote"comme alias de"type": "blockquote"propsen priorité, fallbackattrs(compatibilité ascendante/descendante)🎨 CSS
frontend/static/css/article.css:color: var(--on-primary)(blanc) en light mode,color: var(--on-surface)(blanc cassé) en dark mode via[data-theme="dark"]. Rendu visible à 65% d'opacité en mode readonly sans hoverborder-collapse,padding: 0.5rem 0.75rem,border: 1px solid var(--outline), largeur 100% avec variables de thème.detail-body,.comment-reply-input,.article-form-actions)⏱️ Session
blog_comment_application.py: durée de session augmentée de 30 min → 12hFichiers modifiés
blog_comment_application.py
docker-compose.yml
frontend/core/tests/useCodeBlockGapClick.test.js
frontend/core/tests/video-dict.test.js
frontend/core/tests/video-override-spec.test.js
frontend/core/components/ArticleForm.jsx
frontend/core/components/ArticleViewer.jsx
frontend/core/hooks/useCodeBlockGapClick.js
frontend/core/utils/video-override-spec.js
frontend/static/css/article.css
frontend/templates/article_detail.html
frontend/templates/article_edit.html
src/application/input_ports/file_management.py
src/application/output_ports/file_storage_repository.py
src/application/services/article_service.py
src/application/services/file_service.py
src/infrastructure/output_adapters/sqlalchemy/sqlalchemy_file_storage_adapter.py
src/infrastructure/output_adapters/sqlalchemy/sqlalchemy_setup_database.py
tests/test_prosemirror_to_html.py
tests/tests_infrastructure/tests_input_adapters/tests_flask/flask_test_utils.py
tests/tests_integration/test_security_integration.py
tests/tests_services/test_article_service.py
tests/tests_services/test_file_service.py
utils/prosemirror_to_html.py
Notes techniques
--on-primaryvaut#3f008e(violet foncé) en dark mode → invisible sur fond sombre du code block. Override[data-theme="dark"]corrigestyle=""). Solution :<br>structural après</table>, contenu HTML statique enposition: absolute; left: -99999pxcontentcomme objet (pas une liste). Géré viaisinstance(content, dict)propsest le format BlockNote v0.51+,attrsest le format legacy ProseMirror. Les deux sont supportéselementFromPointDOM avec détection de direction