## Implementation Plan: Paste-to-Upload for Comment Textbox ### Summary Add a JavaScript `paste` event listener to the existing `AppUpload` component that extracts file objects from the clipboard and reuses the component’s built-in `handleFiles()` method. This enables pasting images or other allowed file types directly into the comment form’s textarea without any backend changes. The feature can be optionally gated via a `paste` boolean attribute on the `` element. ### Files to Modify 1. `static/js/components/AppUpload.js` – Add paste handler in the `build()` method. 2. `templates/_comment_form.html` – Add the `paste` attribute to the `` tag (if the feature should be restricted to comment forms; otherwise this change is optional). ### Detailed Changes #### 1. `static/js/components/AppUpload.js` - **Location**: Inside the `build()` method, immediately after the existing drag‑and‑drop (`drop`) event handler (around line 78). - **Action**: Insert a `paste` event listener scoped to the comment form’s textarea. - **Implementation** (exact code to add): ```js document.addEventListener("paste", (e) => { // Only respond when the paste target is the comment textarea if (!e.target.closest(".comment-form textarea")) return; if (!e.clipboardData || !e.clipboardData.items) return; const files = []; for (const item of e.clipboardData.items) { if (item.kind === "file") { const file = item.getAsFile(); if (file) files.push(file); } } if (files.length) { this.handleFiles(files); } }); ``` - **Rationale**: No `e.preventDefault()` is used, so textual paste continues to work. The listener only activates when the paste occurs inside `.comment-form textarea`. The `handleFiles()` method already runs validation (`validate()`) and upload (`upload()`), and updates the hidden `attachment_uids` input, so all existing behaviour is reused. #### 2. `templates/_comment_form.html` (optional gating) - **Location**: The `` opening tag (line 8–11). - **Action**: Add the attribute `paste` to enable the feature on this form. Example change: ```html ``` - **Note**: If no gating is desired (i.e., paste‑to‑upload should be available for all `` instances), skip this step and remove the `if (this.pasteEnabled)` early return from the paste listener (or remove the attribute check entirely). The investigation suggests using the attribute for scoped control, but the plan can default to always active on comment forms. #### No other files require changes Routes, models, backend logic, tests, or configuration remain untouched. ### Definition of Done - [ ] The `paste` event listener is added to `static/js/components/AppUpload.js` as described above. - [ ] (If gating is desired) The `paste` attribute is present on the `` element in `templates/_comment_form.html`. - [ ] In a browser, after reloading the application, pasting an allowed file (e.g., an image) into the comment textarea results in the file being uploaded and an upload chip appearing, exactly as if the file had been selected via the file picker or dropped via drag‑and‑drop. - [ ] The hidden `attachment_uids` input is automatically populated with the upload’s UID, and submitting the comment successfully links the attachment to the comment. - [ ] Normal text paste continues to work inside the textarea; file paste does not prevent text paste. - [ ] All existing unit tests pass: `pip install -e '.[dev]' -q && make test-unit` exits with code 0. - [ ] No new linting issues are introduced: `pip install -q ruff && ruff check .` exits with code 0 (no warnings or errors). - [ ] A Playwright e2e test is added (file `tests/e2e/comments/paste_upload.py` or similar) that: - Creates a `DataTransfer` containing a mock image file. - Fires a `paste` event on the comment textarea. - Asserts the upload chip appears and the hidden `attachment_uids` field is updated. - Submits the form and verifies the comment and attachment are linked.