Text-Editor: Style-Picker focus-restore + Runs-Round-Trip beim Reopen
User-Bugs:
1. Stil-Picker setzt Toolbar-State aber Editor zeigt alle Texte gleich
2. Beim Reopen (Doppelklick auf DOSSIER-Text) ist Editor leer/unformatiert
Fix 1 — applyStyle focus-restore:
Style-Picker stiehlt Focus → savedRange ist da, aber execCommand
ohne Focus auf editable schreibt nichts. Fix: editorRef.focus() +
restoreSelection() VOR execCommand. Plus Size jetzt via inline-span
(execCommand fontSize geht nur 1-7 Scale, kein Pixel).
Fix 2 — Runs persistieren als UserString fuer Round-Trip:
- _commit: runs als JSON in attrs.SetUserString("dossier_text_runs")
abgelegt zusammen mit dem dossier_text-Tag
- open_for_edit: liest UserString, parsed JSON → initial_runs
- Bridge INIT: sendet initialRuns mit
- Frontend onMessage INIT: wenn initialRuns vorhanden → runsToHtml()
baut HTML mit spans (font-family, font-size, color) + Tags (b/i/u/
sup/sub) — Editor zeigt jetzt beim Reopen das tatsaechliche reiche
Format statt PlainText im Default-Helvetica
runsToHtml: pro run text/style-Splittung per \n → <br>. Escaping fuer
&<> damit kein XSS / Parse-Fehler.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+22
-2
@@ -84,7 +84,7 @@ def _on_idle_check_pending_edit(sender, e):
|
||||
|
||||
class TextEditorBridge(panel_base.BaseBridge):
|
||||
def __init__(self, frame_data, settings, fonts,
|
||||
edit_obj_id=None, initial_text=""):
|
||||
edit_obj_id=None, initial_text="", initial_runs=None):
|
||||
panel_base.BaseBridge.__init__(self, "text_editor")
|
||||
self._frame = frame_data # (origin, width, height, p1, p2)
|
||||
self._initial_settings = settings
|
||||
@@ -92,6 +92,7 @@ class TextEditorBridge(panel_base.BaseBridge):
|
||||
self._form_ref = None
|
||||
self._edit_obj_id = edit_obj_id # bei Doppelklick-Edit gesetzt
|
||||
self._initial_text = initial_text
|
||||
self._initial_runs = initial_runs # rich-format-Runs falls vorhanden
|
||||
|
||||
def set_form(self, form):
|
||||
self._form_ref = form
|
||||
@@ -106,6 +107,7 @@ class TextEditorBridge(panel_base.BaseBridge):
|
||||
"fonts": self._fonts,
|
||||
"styles": styles,
|
||||
"initialText": self._initial_text,
|
||||
"initialRuns": self._initial_runs,
|
||||
"editMode": bool(self._edit_obj_id),
|
||||
})
|
||||
|
||||
@@ -219,6 +221,15 @@ class TextEditorBridge(panel_base.BaseBridge):
|
||||
except Exception as ex:
|
||||
print("[TEXT-EDITOR] color:", ex)
|
||||
attrs.SetUserString("dossier_text", "1")
|
||||
# Runs als JSON persistieren — beim Re-Open kann der Editor
|
||||
# die ganze Struktur (Fonts/Sizes/Styles pro Segment) wieder
|
||||
# herstellen statt nur PlainText zu zeigen.
|
||||
if runs:
|
||||
try:
|
||||
import json
|
||||
attrs.SetUserString("dossier_text_runs", json.dumps(runs))
|
||||
except Exception as ex:
|
||||
print("[TEXT-EDITOR] runs persist:", ex)
|
||||
|
||||
# Edit-Mode: bestehenden TextEntity ersetzen statt neu hinzu
|
||||
if self._edit_obj_id is not None:
|
||||
@@ -439,6 +450,14 @@ def open_for_edit(obj):
|
||||
initial_text = ""
|
||||
try: initial_text = te.PlainText or ""
|
||||
except Exception: pass
|
||||
# Runs aus UserString lesen (gespeichert beim letzten Save)
|
||||
initial_runs = None
|
||||
try:
|
||||
import json
|
||||
rj = obj.Attributes.GetUserString("dossier_text_runs")
|
||||
if rj: initial_runs = json.loads(rj)
|
||||
except Exception as ex:
|
||||
print("[TEXT-EDITOR] read runs:", ex)
|
||||
|
||||
# Frame aus dem Text-BBox ableiten (fuer Dialog-Positionierung)
|
||||
p1 = te.Plane.Origin
|
||||
@@ -461,7 +480,8 @@ def open_for_edit(obj):
|
||||
(origin, width, height, p1, p2),
|
||||
settings, fonts,
|
||||
edit_obj_id=obj.Id,
|
||||
initial_text=initial_text)
|
||||
initial_text=initial_text,
|
||||
initial_runs=initial_runs)
|
||||
sc.sticky["text_editor_bridge"] = bridge
|
||||
|
||||
form = panel_base.open_satellite_window(
|
||||
|
||||
Reference in New Issue
Block a user