Added mouse selection

This commit is contained in:
2026-02-09 23:46:31 +01:00
parent b0d565589a
commit 79c37493af
7 changed files with 659 additions and 11 deletions

View File

@@ -19,11 +19,62 @@ class Mouse(MultipleInstance):
- Both (named params override command): mouse.add("click", command, hx_target="#other")
For dynamic hx_vals, use "js:functionName()" to call a client-side function.
Supported base actions:
- ``click`` - Left mouse click (detected globally)
- ``right_click`` (or alias ``rclick``) - Right mouse click (detected on element only)
- ``mousedown>mouseup`` - Left mouse press-and-release (captures data at both phases)
- ``rmousedown>mouseup`` - Right mouse press-and-release
Modifiers can be combined with ``+``: ``ctrl+click``, ``shift+mousedown>mouseup``.
Sequences use space separation: ``click right_click``, ``click mousedown>mouseup``.
For ``mousedown>mouseup`` actions with ``hx_vals="js:functionName()"``, the JS function
is called at both mousedown and mouseup. Results are suffixed: ``key_mousedown`` and
``key_mouseup`` in the server request.
"""
VALID_ACTIONS = {
'click', 'right_click', 'rclick',
'mousedown>mouseup', 'rmousedown>mouseup'
}
VALID_MODIFIERS = {'ctrl', 'shift', 'alt'}
def __init__(self, parent, _id=None, combinations=None):
super().__init__(parent, _id=_id)
self.combinations = combinations or {}
def _validate_sequence(self, sequence: str):
"""
Validate a mouse event sequence string.
Checks that all elements in the sequence use valid action names and modifiers.
Args:
sequence: Mouse event sequence string (e.g., "click", "ctrl+mousedown>mouseup")
Raises:
ValueError: If any action or modifier is invalid.
"""
elements = sequence.strip().split()
for element in elements:
parts = element.split('+')
# Last part should be the action, others are modifiers
action = parts[-1].lower()
modifiers = [p.lower() for p in parts[:-1]]
if action not in self.VALID_ACTIONS:
raise ValueError(
f"Invalid action '{action}' in sequence '{sequence}'. "
f"Valid actions: {', '.join(sorted(self.VALID_ACTIONS))}"
)
for mod in modifiers:
if mod not in self.VALID_MODIFIERS:
raise ValueError(
f"Invalid modifier '{mod}' in sequence '{sequence}'. "
f"Valid modifiers: {', '.join(sorted(self.VALID_MODIFIERS))}"
)
def add(self, sequence: str, command: Command = None, *,
hx_post: str = None, hx_get: str = None, hx_put: str = None,
hx_delete: str = None, hx_patch: str = None,
@@ -32,7 +83,11 @@ class Mouse(MultipleInstance):
Add a mouse combination with optional command and HTMX parameters.
Args:
sequence: Mouse event sequence (e.g., "click", "ctrl+click", "click right_click")
sequence: Mouse event sequence string. Supports:
- Simple actions: ``"click"``, ``"right_click"``, ``"mousedown>mouseup"``
- Modifiers: ``"ctrl+click"``, ``"shift+mousedown>mouseup"``
- Sequences: ``"click right_click"``, ``"click mousedown>mouseup"``
- Aliases: ``"rclick"`` for ``"right_click"``
command: Optional Command object for server-side action
hx_post: HTMX post URL (overrides command)
hx_get: HTMX get URL (overrides command)
@@ -41,11 +96,17 @@ class Mouse(MultipleInstance):
hx_patch: HTMX patch URL (overrides command)
hx_target: HTMX target selector (overrides command)
hx_swap: HTMX swap strategy (overrides command)
hx_vals: HTMX values dict or "js:functionName()" for dynamic values
hx_vals: HTMX values dict or "js:functionName()" for dynamic values.
For mousedown>mouseup actions, the JS function is called at both
mousedown and mouseup, with results suffixed ``_mousedown`` and ``_mouseup``.
Returns:
self for method chaining
Raises:
ValueError: If the sequence contains invalid actions or modifiers.
"""
self._validate_sequence(sequence)
self.combinations[sequence] = {
"command": command,
"hx_post": hx_post,