"""
Text Display Type
Renders plain text or HTML content for display in the annotation interface.
Supports span annotation targeting when used with span annotation schemes.
"""
import html
from typing import Dict, Any, List
from .base import BaseDisplay
class TextDisplay(BaseDisplay):
"""
Display type for text content.
Supports both plain text (with HTML escaping) and sanitized HTML content.
Can be used as a target for span annotations.
"""
name = "text"
required_fields = ["key"]
optional_fields = {
"collapsible": False,
"max_height": None,
"preserve_whitespace": True,
}
description = "Plain text content display"
supports_span_target = True
def __init__(self, allow_html: bool = False):
"""
Initialize the text display.
Args:
allow_html: If True, render as sanitized HTML. If False, escape all HTML.
"""
self.allow_html = allow_html
if allow_html:
self.name = "html"
self.description = "HTML content display (sanitized)"
self.supports_span_target = False
def render(self, field_config: Dict[str, Any], data: Any) -> str:
"""
Render text content as HTML.
Args:
field_config: The field configuration
data: The text content to display
Returns:
HTML string for the text content
"""
if data is None:
return 'No content'
# Convert to string if needed
text = str(data)
# Get display options
options = self.get_display_options(field_config)
preserve_whitespace = options.get("preserve_whitespace", True)
collapsible = options.get("collapsible", False)
max_height = options.get("max_height")
# Process the text
if self.allow_html:
# Sanitize HTML but allow safe tags
from potato.server_utils.html_sanitizer import sanitize_html
content = str(sanitize_html(text))
else:
# Escape all HTML for plain text
content = html.escape(text)
# Convert newlines to
for display
if preserve_whitespace:
content = content.replace('\n', '
')
# Build the content wrapper
wrapper_classes = ["text-display-content"]
wrapper_style = []
if preserve_whitespace and not self.allow_html:
wrapper_classes.append("preserve-whitespace")
if max_height:
wrapper_style.append(f"max-height: {max_height}px")
wrapper_style.append("overflow-y: auto")
# Check if this is a span target - add special wrapper for span annotations
is_span_target = field_config.get("span_target", False)
if is_span_target:
wrapper_classes.append("span-target-text")
# Add data attribute for original text (used by span manager)
field_key = field_config.get("key", "")
content = f'