github-actions[bot] commited on
Commit
daa082c
·
1 Parent(s): aee641e

Integrate compact bound placeholder display

Browse files
.github/workflows/bound_placeholder_display_compaction.yml DELETED
@@ -1,64 +0,0 @@
1
- name: Bound placeholder display compaction
2
-
3
- on:
4
- pull_request:
5
- branches:
6
- - main
7
-
8
- permissions:
9
- contents: write
10
-
11
- jobs:
12
- implement-and-test:
13
- runs-on: ubuntu-latest
14
- env:
15
- PYTHONPATH: ${{ github.workspace }}
16
-
17
- steps:
18
- - name: Checkout repository
19
- uses: actions/checkout@v4
20
- with:
21
- fetch-depth: 0
22
-
23
- - name: Apply display-only UI integration
24
- shell: bash
25
- run: |
26
- set -euo pipefail
27
- git checkout -B scrub-bound-placeholder-display-compaction origin/scrub-bound-placeholder-display-compaction
28
- python - <<'PY'
29
- from pathlib import Path
30
- path = Path("ops/implement_bound_placeholder_display_compaction.py")
31
- text = path.read_text(encoding="utf-8")
32
- start_marker = '''patch(\n "side_by_side_review_panel_ui.py",\n """.sp-side-by-side-highlight-token'''
33
- end_marker = '''\n\npatch(\n "side_by_side_review_panel_ui.py",\n \'\'\'def _highlighted_processed_inner_html'''
34
- start = text.find(start_marker)
35
- end = text.find(end_marker, start)
36
- if start < 0 or end < 0:
37
- raise SystemExit("CSS patch block anchors not found")
38
- path.write_text(text[:start] + text[end + 2 :], encoding="utf-8")
39
- PY
40
- python ops/implement_bound_placeholder_display_compaction.py
41
- git config user.name "github-actions[bot]"
42
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
43
- git add -A
44
- git diff --cached --check
45
- git commit -m "Integrate compact bound placeholder display"
46
- git push origin HEAD:scrub-bound-placeholder-display-compaction
47
-
48
- - name: Run frontend display and component tests
49
- run: |
50
- node --test tests/frontend/bound_placeholder_display.test.js
51
- node --test tests/frontend/processed_text_selection_component_core.test.js
52
-
53
- - name: Set up Python
54
- uses: actions/setup-python@v5
55
- with:
56
- python-version: "3.10"
57
-
58
- - name: Install test dependencies
59
- run: |
60
- python -m pip install --upgrade pip
61
- python -m pip install pytest presidio-analyzer click==8.1.8 python-docx pymupdf reportlab pypdf
62
-
63
- - name: Run full regression
64
- run: python -m pytest -q tests
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/processed_text_selection_component/component.js CHANGED
@@ -19,6 +19,8 @@
19
  let currentArgs = {};
20
  let processedText = "";
21
  let highlightSpans = [];
 
 
22
  let currentSelection = null;
23
  let lastMenuPosition = { x: 16, y: 16 };
24
  let lastRenderedInspectionToken = "";
@@ -39,18 +41,28 @@
39
 
40
  function renderProcessedText(text, spans) {
41
  clearElement(processedPane);
42
- Core.buildTextSegments(text, spans).forEach(function (segment) {
43
- if (segment.marked) {
44
- const marker = document.createElement("mark");
45
- marker.className = "sp-highlight";
46
- marker.setAttribute("aria-label", "gemarkeerde vervanging");
47
- marker.dataset.startUtf16 = String(segment.start_utf16);
48
- marker.dataset.endUtf16 = String(segment.end_utf16);
49
- appendSafeText(marker, segment.text);
50
- processedPane.appendChild(marker);
51
- } else {
52
- appendSafeText(processedPane, segment.text);
 
 
 
 
 
53
  }
 
 
 
 
 
54
  });
55
  }
56
 
@@ -85,10 +97,34 @@
85
  if (!nodeWithin(rootElement, container)) {
86
  throw new Error("selection endpoint is outside processed text");
87
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  const range = document.createRange();
89
- range.selectNodeContents(rootElement);
90
  range.setEnd(container, offset);
91
- return range.toString().length;
 
 
 
 
92
  }
93
 
94
  function readProcessedSelection() {
@@ -108,7 +144,7 @@
108
  } catch (_error) {
109
  return null;
110
  }
111
- return Core.selectionFromOffsets(processedText, highlightSpans, start, end);
112
  }
113
 
114
  function updateSelectionState() {
@@ -358,9 +394,18 @@
358
 
359
  renderPlainText(sourcePane, currentArgs.source_text);
360
  renderProcessedText(processedText, highlightSpans);
361
- processedLegend.textContent = highlightSpans.length
362
- ? "Geel = vervangen of gemaskeerde waarde"
363
- : "Verwerkte tekst";
 
 
 
 
 
 
 
 
 
364
 
365
  const restoreSource = currentArgs.restore_source_scroll_ratio;
366
  const restoreProcessed = currentArgs.restore_processed_scroll_ratio;
 
19
  let currentArgs = {};
20
  let processedText = "";
21
  let highlightSpans = [];
22
+ let renderedProcessedSegments = [];
23
+ let selectionProtectedSpans = [];
24
  let currentSelection = null;
25
  let lastMenuPosition = { x: 16, y: 16 };
26
  let lastRenderedInspectionToken = "";
 
41
 
42
  function renderProcessedText(text, spans) {
43
  clearElement(processedPane);
44
+ renderedProcessedSegments = Core.buildDisplayTextSegments(text, spans);
45
+ selectionProtectedSpans = Core.protectedSpansFromDisplaySegments(renderedProcessedSegments);
46
+ renderedProcessedSegments.forEach(function (segment, index) {
47
+ const element = document.createElement(segment.marked ? "mark" : "span");
48
+ element.className = segment.marked
49
+ ? "sp-highlight sp-processed-segment"
50
+ : "sp-processed-segment";
51
+ if (segment.compacted) {
52
+ element.classList.add("sp-compact-placeholder");
53
+ element.title = `Volledige gebonden placeholder: ${segment.full_placeholder}`;
54
+ element.setAttribute(
55
+ "aria-label",
56
+ `Gebonden placeholder, compact weergegeven als ${segment.display_text}`,
57
+ );
58
+ } else if (segment.marked) {
59
+ element.setAttribute("aria-label", "gemarkeerde vervanging");
60
  }
61
+ element.dataset.segmentIndex = String(index);
62
+ element.dataset.startUtf16 = String(segment.start_utf16);
63
+ element.dataset.endUtf16 = String(segment.end_utf16);
64
+ appendSafeText(element, segment.display_text);
65
+ processedPane.appendChild(element);
66
  });
67
  }
68
 
 
97
  if (!nodeWithin(rootElement, container)) {
98
  throw new Error("selection endpoint is outside processed text");
99
  }
100
+ if (container === rootElement) {
101
+ if (!Number.isInteger(offset) || offset < 0 || offset > rootElement.childNodes.length) {
102
+ throw new Error("selection endpoint is outside processed text");
103
+ }
104
+ if (offset === 0) {
105
+ return 0;
106
+ }
107
+ if (offset >= renderedProcessedSegments.length) {
108
+ return processedText.length;
109
+ }
110
+ return renderedProcessedSegments[offset - 1].end_utf16;
111
+ }
112
+ const candidate = container.nodeType === Node.TEXT_NODE ? container.parentElement : container;
113
+ const segmentElement = candidate && candidate.closest
114
+ ? candidate.closest("[data-segment-index]")
115
+ : null;
116
+ if (!segmentElement || !rootElement.contains(segmentElement)) {
117
+ throw new Error("selection endpoint has no source segment");
118
+ }
119
+ const segmentIndex = Number(segmentElement.dataset.segmentIndex);
120
  const range = document.createRange();
121
+ range.selectNodeContents(segmentElement);
122
  range.setEnd(container, offset);
123
+ return Core.utf16OffsetFromDisplaySegments(
124
+ renderedProcessedSegments,
125
+ segmentIndex,
126
+ range.toString().length,
127
+ );
128
  }
129
 
130
  function readProcessedSelection() {
 
144
  } catch (_error) {
145
  return null;
146
  }
147
+ return Core.selectionFromOffsets(processedText, selectionProtectedSpans, start, end);
148
  }
149
 
150
  function updateSelectionState() {
 
394
 
395
  renderPlainText(sourcePane, currentArgs.source_text);
396
  renderProcessedText(processedText, highlightSpans);
397
+ const compactedCount = renderedProcessedSegments.filter(function (segment) {
398
+ return segment.compacted;
399
+ }).length;
400
+ if (highlightSpans.length && compactedCount) {
401
+ processedLegend.textContent = "Geel = vervangen; documentcode compact weergegeven";
402
+ } else if (highlightSpans.length) {
403
+ processedLegend.textContent = "Geel = vervangen of gemaskeerde waarde";
404
+ } else if (compactedCount) {
405
+ processedLegend.textContent = "Documentcode compact weergegeven";
406
+ } else {
407
+ processedLegend.textContent = "Verwerkte tekst";
408
+ }
409
 
410
  const restoreSource = currentArgs.restore_source_scroll_ratio;
411
  const restoreProcessed = currentArgs.restore_processed_scroll_ratio;
ops/implement_bound_placeholder_display_compaction.py DELETED
@@ -1,83 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pathlib import Path
4
-
5
- ROOT = Path(__file__).resolve().parents[1]
6
-
7
-
8
- def patch(path: str, old: str, new: str) -> None:
9
- target = ROOT / path
10
- text = target.read_text(encoding="utf-8")
11
- if old not in text:
12
- raise RuntimeError(f"Required anchor missing in {path}: {old[:120]!r}")
13
- target.write_text(text.replace(old, new, 1), encoding="utf-8")
14
-
15
-
16
- patch(
17
- "frontend/processed_text_selection_component/component.js",
18
- """ let processedText = \"\";\n let highlightSpans = [];\n let currentSelection = null;\n""",
19
- """ let processedText = \"\";\n let highlightSpans = [];\n let renderedProcessedSegments = [];\n let selectionProtectedSpans = [];\n let currentSelection = null;\n""",
20
- )
21
-
22
- patch(
23
- "frontend/processed_text_selection_component/component.js",
24
- """ function renderProcessedText(text, spans) {\n clearElement(processedPane);\n Core.buildTextSegments(text, spans).forEach(function (segment) {\n if (segment.marked) {\n const marker = document.createElement(\"mark\");\n marker.className = \"sp-highlight\";\n marker.setAttribute(\"aria-label\", \"gemarkeerde vervanging\");\n marker.dataset.startUtf16 = String(segment.start_utf16);\n marker.dataset.endUtf16 = String(segment.end_utf16);\n appendSafeText(marker, segment.text);\n processedPane.appendChild(marker);\n } else {\n appendSafeText(processedPane, segment.text);\n }\n });\n }\n""",
25
- """ function renderProcessedText(text, spans) {\n clearElement(processedPane);\n renderedProcessedSegments = Core.buildDisplayTextSegments(text, spans);\n selectionProtectedSpans = Core.protectedSpansFromDisplaySegments(renderedProcessedSegments);\n renderedProcessedSegments.forEach(function (segment, index) {\n const element = document.createElement(segment.marked ? \"mark\" : \"span\");\n element.className = segment.marked\n ? \"sp-highlight sp-processed-segment\"\n : \"sp-processed-segment\";\n if (segment.compacted) {\n element.classList.add(\"sp-compact-placeholder\");\n element.title = `Volledige gebonden placeholder: ${segment.full_placeholder}`;\n element.setAttribute(\n \"aria-label\",\n `Gebonden placeholder, compact weergegeven als ${segment.display_text}`,\n );\n } else if (segment.marked) {\n element.setAttribute(\"aria-label\", \"gemarkeerde vervanging\");\n }\n element.dataset.segmentIndex = String(index);\n element.dataset.startUtf16 = String(segment.start_utf16);\n element.dataset.endUtf16 = String(segment.end_utf16);\n appendSafeText(element, segment.display_text);\n processedPane.appendChild(element);\n });\n }\n""",
26
- )
27
-
28
- patch(
29
- "frontend/processed_text_selection_component/component.js",
30
- """ function domUtf16Offset(rootElement, container, offset) {\n if (!nodeWithin(rootElement, container)) {\n throw new Error(\"selection endpoint is outside processed text\");\n }\n const range = document.createRange();\n range.selectNodeContents(rootElement);\n range.setEnd(container, offset);\n return range.toString().length;\n }\n""",
31
- """ function domUtf16Offset(rootElement, container, offset) {\n if (!nodeWithin(rootElement, container)) {\n throw new Error(\"selection endpoint is outside processed text\");\n }\n if (container === rootElement) {\n if (!Number.isInteger(offset) || offset < 0 || offset > rootElement.childNodes.length) {\n throw new Error(\"selection endpoint is outside processed text\");\n }\n if (offset === 0) {\n return 0;\n }\n if (offset >= renderedProcessedSegments.length) {\n return processedText.length;\n }\n return renderedProcessedSegments[offset - 1].end_utf16;\n }\n const candidate = container.nodeType === Node.TEXT_NODE ? container.parentElement : container;\n const segmentElement = candidate && candidate.closest\n ? candidate.closest(\"[data-segment-index]\")\n : null;\n if (!segmentElement || !rootElement.contains(segmentElement)) {\n throw new Error(\"selection endpoint has no source segment\");\n }\n const segmentIndex = Number(segmentElement.dataset.segmentIndex);\n const range = document.createRange();\n range.selectNodeContents(segmentElement);\n range.setEnd(container, offset);\n return Core.utf16OffsetFromDisplaySegments(\n renderedProcessedSegments,\n segmentIndex,\n range.toString().length,\n );\n }\n""",
32
- )
33
-
34
- patch(
35
- "frontend/processed_text_selection_component/component.js",
36
- """ return Core.selectionFromOffsets(processedText, highlightSpans, start, end);\n""",
37
- """ return Core.selectionFromOffsets(processedText, selectionProtectedSpans, start, end);\n""",
38
- )
39
-
40
- patch(
41
- "frontend/processed_text_selection_component/component.js",
42
- """ processedLegend.textContent = highlightSpans.length\n ? \"Geel = vervangen of gemaskeerde waarde\"\n : \"Verwerkte tekst\";\n""",
43
- """ const compactedCount = renderedProcessedSegments.filter(function (segment) {\n return segment.compacted;\n }).length;\n if (highlightSpans.length && compactedCount) {\n processedLegend.textContent = \"Geel = vervangen; documentcode compact weergegeven\";\n } else if (highlightSpans.length) {\n processedLegend.textContent = \"Geel = vervangen of gemaskeerde waarde\";\n } else if (compactedCount) {\n processedLegend.textContent = \"Documentcode compact weergegeven\";\n } else {\n processedLegend.textContent = \"Verwerkte tekst\";\n }\n""",
44
- )
45
-
46
- patch(
47
- "side_by_side_review_panel_ui.py",
48
- """import streamlit.components.v1 as components\n\nfrom processed_text_selection_component import (\n""",
49
- """import streamlit.components.v1 as components\n\nfrom bound_placeholder_display import build_bound_placeholder_display_segments\nfrom processed_text_selection_component import (\n""",
50
- )
51
-
52
- patch(
53
- "side_by_side_review_panel_ui.py",
54
- """.sp-side-by-side-highlight-token {\n background: #fef3c7;\n border: 1px solid #f59e0b;\n border-radius: 0.25rem;\n padding: 0.05rem 0.15rem;\n}\n""",
55
- """.sp-side-by-side-highlight-token {\n background: #fef3c7;\n border: 1px solid #f59e0b;\n border-radius: 0.25rem;\n padding: 0.05rem 0.15rem;\n}\n.sp-compact-placeholder {\n border-bottom: 1px dotted #94a3b8;\n cursor: help;\n}\n""",
56
- )
57
-
58
- patch(
59
- "side_by_side_review_panel_ui.py",
60
- '''def _highlighted_processed_inner_html(\n processed_text: str,\n highlight_spans: list[tuple[int, int]],\n) -> str:\n """Return escaped inner HTML for the static fallback processed pane."""\n\n parts: list[str] = []\n cursor = 0\n for start, end in highlight_spans:\n parts.append(escape(processed_text[cursor:start]))\n parts.append(\n '<mark class="sp-side-by-side-highlight-token" aria-label="gemarkeerde vervanging">'\n f"{escape(processed_text[start:end])}"\n "</mark>"\n )\n cursor = end\n parts.append(escape(processed_text[cursor:]))\n return "".join(parts)\n''',
61
- '''def _highlighted_processed_inner_html(\n processed_text: str,\n highlight_spans: list[tuple[int, int]],\n) -> str:\n """Return lossless compact display HTML for the static fallback pane."""\n\n parts: list[str] = []\n for segment in build_bound_placeholder_display_segments(processed_text, highlight_spans):\n display_text = escape(str(segment["display_text"]))\n full_placeholder = str(segment["full_placeholder"])\n compact_attributes = ""\n compact_class = ""\n if segment["compacted"]:\n compact_class = " sp-compact-placeholder"\n compact_attributes = (\n f' title="Volledige gebonden placeholder: {escape(full_placeholder)}"'\n f' aria-label="Gebonden placeholder, compact weergegeven als {display_text}"'\n )\n if segment["highlighted"]:\n parts.append(\n f'<mark class="sp-side-by-side-highlight-token{compact_class}"'\n f'{compact_attributes}>{display_text}</mark>'\n )\n elif segment["compacted"]:\n parts.append(\n f'<span class="sp-compact-placeholder"{compact_attributes}>'\n f'{display_text}</span>'\n )\n else:\n parts.append(display_text)\n return "".join(parts)\n''',
62
- )
63
-
64
- patch(
65
- "side_by_side_review_panel_ui.py",
66
- """ processed_legend = \"Geel = vervangen of gemaskeerde waarde\" if show_markers else \"Verwerkte tekst\"\n""",
67
- """ compacted = any(\n segment[\"compacted\"]\n for segment in build_bound_placeholder_display_segments(processed_text, [])\n )\n if show_markers and compacted:\n processed_legend = \"Geel = vervangen; documentcode compact weergegeven\"\n elif show_markers:\n processed_legend = \"Geel = vervangen of gemaskeerde waarde\"\n elif compacted:\n processed_legend = \"Documentcode compact weergegeven\"\n else:\n processed_legend = \"Verwerkte tekst\"\n""",
68
- )
69
-
70
- patch(
71
- "side_by_side_review_panel_ui.py",
72
- """ processed_html = (\n _highlighted_processed_inner_html(processed_text, highlight_spans)\n if show_markers and highlight_spans\n else escape(processed_text)\n )\n""",
73
- """ processed_html = _highlighted_processed_inner_html(\n processed_text,\n highlight_spans if show_markers else [],\n )\n""",
74
- )
75
-
76
- patch(
77
- "side_by_side_review_panel_ui.py",
78
- """ \"component_environment_switch\": INTERACTIVE_COMPONENT_ENV,\n \"pane_height\": SIDE_BY_SIDE_REVIEW_PANE_HEIGHT,\n""",
79
- """ \"component_environment_switch\": INTERACTIVE_COMPONENT_ENV,\n \"bound_placeholder_display_compaction\": True,\n \"bound_placeholder_source_tokens_unchanged\": True,\n \"bound_placeholder_binding_entropy_changed\": False,\n \"pane_height\": SIDE_BY_SIDE_REVIEW_PANE_HEIGHT,\n""",
80
- )
81
-
82
- (ROOT / "ops/implement_bound_placeholder_display_compaction.py").unlink()
83
- (ROOT / ".github/workflows/bound_placeholder_display_compaction.yml").unlink()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
side_by_side_review_panel_ui.py CHANGED
@@ -15,6 +15,7 @@ from typing import Any, Mapping
15
  import streamlit as st
16
  import streamlit.components.v1 as components
17
 
 
18
  from processed_text_selection_component import (
19
  render_processed_text_selection_component,
20
  )
@@ -96,19 +97,32 @@ def _highlighted_processed_inner_html(
96
  processed_text: str,
97
  highlight_spans: list[tuple[int, int]],
98
  ) -> str:
99
- """Return escaped inner HTML for the static fallback processed pane."""
100
 
101
  parts: list[str] = []
102
- cursor = 0
103
- for start, end in highlight_spans:
104
- parts.append(escape(processed_text[cursor:start]))
105
- parts.append(
106
- '<mark class="sp-side-by-side-highlight-token" aria-label="gemarkeerde vervanging">'
107
- f"{escape(processed_text[start:end])}"
108
- "</mark>"
109
- )
110
- cursor = end
111
- parts.append(escape(processed_text[cursor:]))
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  return "".join(parts)
113
 
114
 
@@ -122,7 +136,18 @@ def _side_by_side_sync_scroll_html(
122
  """Build escaped HTML for the synchronized static fallback."""
123
 
124
  source_html = escape(source_text)
125
- processed_legend = "Geel = vervangen of gemaskeerde waarde" if show_markers else "Verwerkte tekst"
 
 
 
 
 
 
 
 
 
 
 
126
  return f"""
127
  {_SYNC_SCROLL_COMPONENT_CSS}
128
  <div class="sp-sync-scroll-wrapper">
@@ -195,10 +220,9 @@ def _render_static_fallback(
195
  highlight_spans: list[tuple[int, int]],
196
  show_markers: bool,
197
  ) -> None:
198
- processed_html = (
199
- _highlighted_processed_inner_html(processed_text, highlight_spans)
200
- if show_markers and highlight_spans
201
- else escape(processed_text)
202
  )
203
  components.html(
204
  _side_by_side_sync_scroll_html(
@@ -352,6 +376,9 @@ def render_side_by_side_review_panel(
352
  "static_fallback_used": static_fallback_used,
353
  "component_error": component_error,
354
  "component_environment_switch": INTERACTIVE_COMPONENT_ENV,
 
 
 
355
  "pane_height": SIDE_BY_SIDE_REVIEW_PANE_HEIGHT,
356
  "compact_legend": compact_legend,
357
  "model": model,
 
15
  import streamlit as st
16
  import streamlit.components.v1 as components
17
 
18
+ from bound_placeholder_display import build_bound_placeholder_display_segments
19
  from processed_text_selection_component import (
20
  render_processed_text_selection_component,
21
  )
 
97
  processed_text: str,
98
  highlight_spans: list[tuple[int, int]],
99
  ) -> str:
100
+ """Return lossless compact display HTML for the static fallback pane."""
101
 
102
  parts: list[str] = []
103
+ for segment in build_bound_placeholder_display_segments(processed_text, highlight_spans):
104
+ display_text = escape(str(segment["display_text"]))
105
+ full_placeholder = str(segment["full_placeholder"])
106
+ compact_attributes = ""
107
+ compact_class = ""
108
+ if segment["compacted"]:
109
+ compact_class = " sp-compact-placeholder"
110
+ compact_attributes = (
111
+ f' title="Volledige gebonden placeholder: {escape(full_placeholder)}"'
112
+ f' aria-label="Gebonden placeholder, compact weergegeven als {display_text}"'
113
+ )
114
+ if segment["highlighted"]:
115
+ parts.append(
116
+ f'<mark class="sp-side-by-side-highlight-token{compact_class}"'
117
+ f'{compact_attributes}>{display_text}</mark>'
118
+ )
119
+ elif segment["compacted"]:
120
+ parts.append(
121
+ f'<span class="sp-compact-placeholder"{compact_attributes}>'
122
+ f'{display_text}</span>'
123
+ )
124
+ else:
125
+ parts.append(display_text)
126
  return "".join(parts)
127
 
128
 
 
136
  """Build escaped HTML for the synchronized static fallback."""
137
 
138
  source_html = escape(source_text)
139
+ compacted = any(
140
+ segment["compacted"]
141
+ for segment in build_bound_placeholder_display_segments(processed_text, [])
142
+ )
143
+ if show_markers and compacted:
144
+ processed_legend = "Geel = vervangen; documentcode compact weergegeven"
145
+ elif show_markers:
146
+ processed_legend = "Geel = vervangen of gemaskeerde waarde"
147
+ elif compacted:
148
+ processed_legend = "Documentcode compact weergegeven"
149
+ else:
150
+ processed_legend = "Verwerkte tekst"
151
  return f"""
152
  {_SYNC_SCROLL_COMPONENT_CSS}
153
  <div class="sp-sync-scroll-wrapper">
 
220
  highlight_spans: list[tuple[int, int]],
221
  show_markers: bool,
222
  ) -> None:
223
+ processed_html = _highlighted_processed_inner_html(
224
+ processed_text,
225
+ highlight_spans if show_markers else [],
 
226
  )
227
  components.html(
228
  _side_by_side_sync_scroll_html(
 
376
  "static_fallback_used": static_fallback_used,
377
  "component_error": component_error,
378
  "component_environment_switch": INTERACTIVE_COMPONENT_ENV,
379
+ "bound_placeholder_display_compaction": True,
380
+ "bound_placeholder_source_tokens_unchanged": True,
381
+ "bound_placeholder_binding_entropy_changed": False,
382
  "pane_height": SIDE_BY_SIDE_REVIEW_PANE_HEIGHT,
383
  "compact_legend": compact_legend,
384
  "model": model,