316 lines
9.2 KiB
Python
316 lines
9.2 KiB
Python
from __future__ import annotations
|
|
from enum import Enum
|
|
from typing import Callable, Dict, Any, Optional, Union, List, Tuple
|
|
from pyWebLayout.core.base import Interactable
|
|
|
|
|
|
class LinkType(Enum):
|
|
"""Enumeration of different types of links for classification purposes"""
|
|
INTERNAL = 1 # Links within the same document (e.g., chapter references, bookmarks)
|
|
EXTERNAL = 2 # Links to external resources (e.g., websites, other documents)
|
|
API = 3 # Links that trigger API calls (e.g., for settings management)
|
|
FUNCTION = 4 # Links that execute a specific function
|
|
|
|
|
|
class Link(Interactable):
|
|
"""
|
|
A link that can navigate to a location or execute a function.
|
|
Links can be used for navigation within a document, to external resources,
|
|
or to trigger API calls for functionality like settings management.
|
|
"""
|
|
|
|
def __init__(self,
|
|
location: str,
|
|
link_type: LinkType = LinkType.INTERNAL,
|
|
callback: Optional[Callable] = None,
|
|
params: Optional[Dict[str, Any]] = None,
|
|
title: Optional[str] = None):
|
|
"""
|
|
Initialize a link.
|
|
|
|
Args:
|
|
location: The target location or identifier for this link
|
|
link_type: The type of link (internal, external, API, function)
|
|
callback: Optional callback function to execute when the link is activated
|
|
params: Optional parameters to pass to the callback or API
|
|
title: Optional title/tooltip for the link
|
|
"""
|
|
super().__init__(callback)
|
|
self._location = location
|
|
self._link_type = link_type
|
|
self._params = params or {}
|
|
self._title = title
|
|
|
|
@property
|
|
def location(self) -> str:
|
|
"""Get the target location of this link"""
|
|
return self._location
|
|
|
|
@property
|
|
def link_type(self) -> LinkType:
|
|
"""Get the type of this link"""
|
|
return self._link_type
|
|
|
|
@property
|
|
def params(self) -> Dict[str, Any]:
|
|
"""Get the parameters for this link"""
|
|
return self._params
|
|
|
|
@property
|
|
def title(self) -> Optional[str]:
|
|
"""Get the title/tooltip for this link"""
|
|
return self._title
|
|
|
|
def execute(self) -> Any:
|
|
"""
|
|
Execute the link action based on its type.
|
|
|
|
For internal and external links, returns the location.
|
|
For API and function links, executes the callback with the provided parameters.
|
|
|
|
Returns:
|
|
The result of the link execution, which depends on the link type.
|
|
"""
|
|
if self._link_type in (LinkType.API, LinkType.FUNCTION) and self._callback:
|
|
return self._callback(self._location, **self._params)
|
|
else:
|
|
# For INTERNAL and EXTERNAL links, return the location
|
|
# The renderer/browser will handle the navigation
|
|
return self._location
|
|
|
|
|
|
class Button(Interactable):
|
|
"""
|
|
A button that can be clicked to execute an action.
|
|
Buttons are similar to function links but are rendered differently.
|
|
"""
|
|
|
|
def __init__(self,
|
|
label: str,
|
|
callback: Callable,
|
|
params: Optional[Dict[str, Any]] = None,
|
|
enabled: bool = True):
|
|
"""
|
|
Initialize a button.
|
|
|
|
Args:
|
|
label: The text label for the button
|
|
callback: The function to execute when the button is clicked
|
|
params: Optional parameters to pass to the callback
|
|
enabled: Whether the button is initially enabled
|
|
"""
|
|
super().__init__(callback)
|
|
self._label = label
|
|
self._params = params or {}
|
|
self._enabled = enabled
|
|
|
|
@property
|
|
def label(self) -> str:
|
|
"""Get the button label"""
|
|
return self._label
|
|
|
|
@label.setter
|
|
def label(self, label: str):
|
|
"""Set the button label"""
|
|
self._label = label
|
|
|
|
@property
|
|
def enabled(self) -> bool:
|
|
"""Check if the button is enabled"""
|
|
return self._enabled
|
|
|
|
@enabled.setter
|
|
def enabled(self, enabled: bool):
|
|
"""Enable or disable the button"""
|
|
self._enabled = enabled
|
|
|
|
@property
|
|
def params(self) -> Dict[str, Any]:
|
|
"""Get the button parameters"""
|
|
return self._params
|
|
|
|
def execute(self) -> Any:
|
|
"""
|
|
Execute the button's callback function if the button is enabled.
|
|
|
|
Returns:
|
|
The result of the callback function, or None if the button is disabled.
|
|
"""
|
|
if self._enabled and self._callback:
|
|
return self._callback(**self._params)
|
|
return None
|
|
|
|
|
|
class Form(Interactable):
|
|
"""
|
|
A form that can contain input fields and be submitted.
|
|
Forms can be used for user input and settings configuration.
|
|
"""
|
|
|
|
def __init__(self,
|
|
form_id: str,
|
|
action: Optional[str] = None,
|
|
callback: Optional[Callable] = None):
|
|
"""
|
|
Initialize a form.
|
|
|
|
Args:
|
|
form_id: The unique identifier for this form
|
|
action: The action URL or endpoint for form submission
|
|
callback: Optional callback function to execute on form submission
|
|
"""
|
|
super().__init__(callback)
|
|
self._form_id = form_id
|
|
self._action = action
|
|
self._fields: Dict[str, FormField] = {}
|
|
|
|
@property
|
|
def form_id(self) -> str:
|
|
"""Get the form ID"""
|
|
return self._form_id
|
|
|
|
@property
|
|
def action(self) -> Optional[str]:
|
|
"""Get the form action"""
|
|
return self._action
|
|
|
|
def add_field(self, field: FormField):
|
|
"""
|
|
Add a field to this form.
|
|
|
|
Args:
|
|
field: The FormField to add
|
|
"""
|
|
self._fields[field.name] = field
|
|
field.form = self
|
|
|
|
def get_field(self, name: str) -> Optional[FormField]:
|
|
"""
|
|
Get a field by name.
|
|
|
|
Args:
|
|
name: The name of the field to get
|
|
|
|
Returns:
|
|
The FormField with the specified name, or None if not found
|
|
"""
|
|
return self._fields.get(name)
|
|
|
|
def get_values(self) -> Dict[str, Any]:
|
|
"""
|
|
Get the current values of all fields in this form.
|
|
|
|
Returns:
|
|
A dictionary mapping field names to their current values
|
|
"""
|
|
return {name: field.value for name, field in self._fields.items()}
|
|
|
|
def execute(self) -> Any:
|
|
"""
|
|
Submit the form, executing the callback with the form values.
|
|
|
|
Returns:
|
|
The result of the callback function, or the form values if no callback is provided.
|
|
"""
|
|
values = self.get_values()
|
|
|
|
if self._callback:
|
|
return self._callback(self._form_id, values)
|
|
|
|
return values
|
|
|
|
|
|
class FormFieldType(Enum):
|
|
"""Enumeration of different types of form fields"""
|
|
TEXT = 1
|
|
PASSWORD = 2
|
|
CHECKBOX = 3
|
|
RADIO = 4
|
|
SELECT = 5
|
|
TEXTAREA = 6
|
|
NUMBER = 7
|
|
DATE = 8
|
|
TIME = 9
|
|
EMAIL = 10
|
|
URL = 11
|
|
COLOR = 12
|
|
RANGE = 13
|
|
HIDDEN = 14
|
|
|
|
|
|
class FormField:
|
|
"""
|
|
A field in a form that can accept user input.
|
|
"""
|
|
|
|
def __init__(self,
|
|
name: str,
|
|
field_type: FormFieldType,
|
|
label: Optional[str] = None,
|
|
value: Any = None,
|
|
required: bool = False,
|
|
options: Optional[List[Tuple[str, str]]] = None):
|
|
"""
|
|
Initialize a form field.
|
|
|
|
Args:
|
|
name: The name of this field
|
|
field_type: The type of this field
|
|
label: Optional label for this field
|
|
value: Initial value for this field
|
|
required: Whether this field is required
|
|
options: Options for select, radio, or checkbox fields (list of (value, label) tuples)
|
|
"""
|
|
self._name = name
|
|
self._field_type = field_type
|
|
self._label = label or name
|
|
self._value = value
|
|
self._required = required
|
|
self._options = options or []
|
|
self._form: Optional[Form] = None
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
"""Get the field name"""
|
|
return self._name
|
|
|
|
@property
|
|
def field_type(self) -> FormFieldType:
|
|
"""Get the field type"""
|
|
return self._field_type
|
|
|
|
@property
|
|
def label(self) -> str:
|
|
"""Get the field label"""
|
|
return self._label
|
|
|
|
@property
|
|
def value(self) -> Any:
|
|
"""Get the current field value"""
|
|
return self._value
|
|
|
|
@value.setter
|
|
def value(self, value: Any):
|
|
"""Set the field value"""
|
|
self._value = value
|
|
|
|
@property
|
|
def required(self) -> bool:
|
|
"""Check if the field is required"""
|
|
return self._required
|
|
|
|
@property
|
|
def options(self) -> List[Tuple[str, str]]:
|
|
"""Get the field options"""
|
|
return self._options
|
|
|
|
@property
|
|
def form(self) -> Optional[Form]:
|
|
"""Get the form containing this field"""
|
|
return self._form
|
|
|
|
@form.setter
|
|
def form(self, form: Form):
|
|
"""Set the form containing this field"""
|
|
self._form = form
|