mirror of
https://github.com/PR0M3TH3AN/unredact.git
synced 2026-10-27 08:40:29 +00:00
feat: add inline-edit.js and sync popover with inline inputs
Missed files from the inline text editing task — adds the inline-edit module and wires up bidirectional sync between popover text bar and inline canvas inputs. Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
1 parent
3d07faadc8
commit
e9ec2ff7f3
2 files changed
+106
No files matched your search
@@ -0,0 +1,102 @@
|
||||
// @ts-check
|
||||
/**
|
||||
* Inline text editing — HTML inputs positioned on the canvas at
|
||||
* the left/right text locations so users edit directly on the document.
|
||||
*/
|
||||
import { state } from './state.js';
|
||||
import { renderCanvas } from './canvas.js';
|
||||
|
||||
const layer = document.getElementById("inline-edit-layer");
|
||||
|
||||
let leftInput = null;
|
||||
let rightInput = null;
|
||||
|
||||
/**
|
||||
* Show inline text inputs for the active redaction.
|
||||
* @param {string} id - Redaction ID
|
||||
*/
|
||||
export function showInlineEdit(id) {
|
||||
hideInlineEdit();
|
||||
|
||||
const r = state.redactions[id];
|
||||
if (!r?.analysis || !r?.overrides) return;
|
||||
|
||||
const a = r.analysis;
|
||||
const o = r.overrides;
|
||||
const fontSize = o.fontSize || a.font.size;
|
||||
const offsetX = o.offsetX || 0;
|
||||
const offsetY = o.offsetY || 0;
|
||||
const lineX = a.line.x + offsetX;
|
||||
const lineY = a.line.y + offsetY;
|
||||
const gapWidth = o.gapWidth || a.gap.w;
|
||||
|
||||
const leftText = o.leftText || "";
|
||||
const rightText = o.rightText || "";
|
||||
|
||||
// Left input: positioned at the start of the line, width up to the gap
|
||||
const leftWidth = Math.max(30, r.x - lineX);
|
||||
leftInput = _createInput(leftText, lineX, lineY, leftWidth, a.line.h, fontSize);
|
||||
leftInput.style.textAlign = "right";
|
||||
leftInput.addEventListener("input", () => {
|
||||
r.overrides.leftText = leftInput.value;
|
||||
renderCanvas();
|
||||
_syncTextEditBar(r);
|
||||
});
|
||||
|
||||
// Right input: positioned after the gap
|
||||
const rightX = r.x + gapWidth;
|
||||
const rightW = Math.max(50, (a.line.x + a.line.w) - rightX + 20);
|
||||
rightInput = _createInput(rightText, rightX, lineY, rightW, a.line.h, fontSize);
|
||||
rightInput.addEventListener("input", () => {
|
||||
r.overrides.rightText = rightInput.value;
|
||||
renderCanvas();
|
||||
_syncTextEditBar(r);
|
||||
});
|
||||
|
||||
layer.appendChild(leftInput);
|
||||
layer.appendChild(rightInput);
|
||||
}
|
||||
|
||||
/** Remove all inline edit inputs. */
|
||||
export function hideInlineEdit() {
|
||||
if (leftInput) { leftInput.remove(); leftInput = null; }
|
||||
if (rightInput) { rightInput.remove(); rightInput = null; }
|
||||
}
|
||||
|
||||
/** Update input values from state (e.g., after text reset or popover bar edit). */
|
||||
export function syncInlineEdit(id) {
|
||||
const r = state.redactions[id];
|
||||
if (!r?.overrides) return;
|
||||
if (leftInput) leftInput.value = r.overrides.leftText;
|
||||
if (rightInput) rightInput.value = r.overrides.rightText;
|
||||
}
|
||||
|
||||
function _syncTextEditBar(r) {
|
||||
// Keep the bottom text edit bar in sync
|
||||
const leftEl = document.getElementById("left-text-input");
|
||||
const rightEl = document.getElementById("right-text-input");
|
||||
if (leftEl) leftEl.value = r.overrides.leftText;
|
||||
if (rightEl) rightEl.value = r.overrides.rightText;
|
||||
}
|
||||
|
||||
function _createInput(value, x, y, w, h, fontSize) {
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.value = value;
|
||||
Object.assign(input.style, {
|
||||
position: "absolute",
|
||||
left: x + "px",
|
||||
top: y + "px",
|
||||
width: Math.max(30, w) + "px",
|
||||
height: h + "px",
|
||||
fontSize: fontSize + "px",
|
||||
background: "rgba(255,255,255,0.7)",
|
||||
border: "1px solid rgba(0,180,0,0.5)",
|
||||
padding: "0 2px",
|
||||
pointerEvents: "auto",
|
||||
boxSizing: "border-box",
|
||||
outline: "none",
|
||||
fontFamily: "sans-serif",
|
||||
});
|
||||
return input;
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
solveMode, filterLabel,
|
||||
} from './dom.js';
|
||||
import { renderCanvas } from './canvas.js';
|
||||
import { syncInlineEdit } from './inline-edit.js';
|
||||
|
||||
/** @type {(() => void)|null} */
|
||||
let _onClose = null;
|
||||
@@ -140,6 +141,7 @@ export function initPopover() {
|
||||
if (!r?.overrides) return;
|
||||
r.overrides.leftText = leftTextInput.value;
|
||||
renderCanvas();
|
||||
syncInlineEdit(state.activeRedaction);
|
||||
});
|
||||
|
||||
rightTextInput.addEventListener("input", () => {
|
||||
@@ -147,6 +149,7 @@ export function initPopover() {
|
||||
if (!r?.overrides) return;
|
||||
r.overrides.rightText = rightTextInput.value;
|
||||
renderCanvas();
|
||||
syncInlineEdit(state.activeRedaction);
|
||||
});
|
||||
|
||||
textReset.addEventListener("click", () => {
|
||||
@@ -158,6 +161,7 @@ export function initPopover() {
|
||||
leftTextInput.value = r.overrides.leftText;
|
||||
rightTextInput.value = r.overrides.rightText;
|
||||
renderCanvas();
|
||||
syncInlineEdit(state.activeRedaction);
|
||||
});
|
||||
|
||||
solveTolerance.addEventListener("input", () => {
|
||||
|
||||
Reference in new issue
Block a user