Added first controls

This commit is contained in:
2025-11-26 20:53:12 +01:00
parent 459c89bae2
commit ce5328fe34
68 changed files with 37849 additions and 87048 deletions

439
docs/Mouse Support.md Normal file
View File

@@ -0,0 +1,439 @@
# Mouse Support - Documentation
## Overview
The mouse support library provides keyboard-like binding capabilities for mouse actions. It supports simple clicks, modified clicks (with Ctrl/Shift/Alt), and sequences of clicks with smart timeout logic.
## Features
### Supported Mouse Actions
**Basic Actions**:
- `click` - Left click
- `right_click` (or `rclick`) - Right click (contextmenu)
**Modified Actions**:
- `ctrl+click` (or `ctrl+rclick`) - Ctrl+Click (or Cmd+Click on Mac)
- `shift+click` (or `shift+rclick`) - Shift+Click
- `alt+click` (or `alt+rclick`) - Alt+Click
- `ctrl+shift+click` - Multiple modifiers
- Any combination of modifiers
**Sequences**:
- `click right_click` (or `click rclick`) - Click then right-click within 500ms
- `click click` - Double click sequence
- `ctrl+click click` - Ctrl+click then normal click
- Any sequence of actions
**Note**: `rclick` is an alias for `right_click` and can be used interchangeably.
### Smart Timeout Logic
Same as keyboard support:
- If **any element** has a longer sequence possible, **all matching elements wait**
- Timeout is 500ms between actions
- Immediate trigger if no longer sequences exist
### Multiple Element Support
Multiple elements can listen to the same mouse action and all will trigger simultaneously.
## Configuration Format
Uses HTMX configuration objects (same as keyboard support):
```javascript
const combinations = {
"click": {
"hx-post": "/handle-click",
"hx-target": "#result"
},
"ctrl+click": {
"hx-post": "/handle-ctrl-click",
"hx-swap": "innerHTML"
},
"rclick": { // Alias for right_click
"hx-post": "/context-menu"
},
"click rclick": { // Can use rclick in sequences too
"hx-post": "/sequence-action",
"hx-vals": {"type": "sequence"}
}
};
add_mouse_support('my-element', JSON.stringify(combinations));
```
## API Reference
### add_mouse_support(elementId, combinationsJson)
Adds mouse support to an element.
**Parameters**:
- `elementId` (string): ID of the HTML element
- `combinationsJson` (string): JSON string of combinations with HTMX configs
**Returns**: void
**Example**:
```javascript
add_mouse_support('button1', JSON.stringify({
"click": {"hx-post": "/click"},
"ctrl+click": {"hx-post": "/ctrl-click"}
}));
```
### remove_mouse_support(elementId)
Removes mouse support from an element.
**Parameters**:
- `elementId` (string): ID of the HTML element
**Returns**: void
**Side effects**:
- If last element: detaches global event listeners and cleans up all state
**Example**:
```javascript
remove_mouse_support('button1');
```
## Automatic Parameters
The library automatically adds these parameters to every HTMX request:
- `combination` - The mouse combination that triggered the action (e.g., "ctrl+click")
- `has_focus` - Boolean indicating if the element had focus when clicked
- `is_inside` - Boolean indicating if the click was inside the element
- For `click`: `true` if clicked inside element, `false` if clicked outside
- For `right_click`: always `true` (only triggers when clicking on element)
- `has_focus` - Boolean indicating if the element had focus when the action triggered
- `clicked_inside` - Boolean indicating if the click was inside the element or outside
### Parameter Details
**`has_focus`**:
- `true` if the registered element currently has focus
- `false` otherwise
- Useful for knowing if the element was the active element
**`clicked_inside`**:
- For `click` actions: `true` if clicked on/inside the element, `false` if clicked outside
- For `right_click` actions: always `true` (since right-click only triggers on the element)
- Useful for "click outside to close" logic
**Example values sent**:
```javascript
// User clicks inside a modal
{
combination: "click",
has_focus: true,
clicked_inside: true
}
// User clicks outside the modal (modal still gets triggered because click is global)
{
combination: "click",
has_focus: false,
clicked_inside: false // Perfect for closing the modal!
}
// User right-clicks on an item
{
combination: "right_click",
has_focus: false,
clicked_inside: true // Always true for right_click
}
```
## Python Integration
### Basic Usage
```python
combinations = {
"click": {
"hx-post": "/item/select"
},
"ctrl+click": {
"hx-post": "/item/select-multiple",
"hx-vals": json.dumps({"mode": "multi"})
},
"right_click": {
"hx-post": "/item/context-menu",
"hx-target": "#context-menu",
"hx-swap": "innerHTML"
}
}
f"add_mouse_support('{element_id}', '{json.dumps(combinations)}')"
```
### Sequences
```python
combinations = {
"click": {
"hx-post": "/single-click"
},
"click click": {
"hx-post": "/double-click-sequence"
},
"click right_click": {
"hx-post": "/click-then-right-click"
}
}
```
### Multiple Elements
```python
# Item 1
item1_combinations = {
"click": {"hx-post": f"/item/1/select"},
"ctrl+click": {"hx-post": f"/item/1/toggle"}
}
f"add_mouse_support('item-1', '{json.dumps(item1_combinations)}')"
# Item 2
item2_combinations = {
"click": {"hx-post": f"/item/2/select"},
"ctrl+click": {"hx-post": f"/item/2/toggle"}
}
f"add_mouse_support('item-2', '{json.dumps(item2_combinations)}')"
```
## Behavior Details
### Click vs Right-Click Behavior
**IMPORTANT**: The library handles `click` and `right_click` differently:
**`click` (global detection)**:
- Triggers for ALL registered elements, regardless of where you click
- Useful for "click outside to close" functionality (modals, dropdowns, popups)
- Example: Modal registered with `click` → clicking anywhere on the page triggers the modal's click action
**`right_click` (element-specific detection)**:
- Triggers ONLY when you right-click on (or inside) the registered element
- Right-clicking outside the element does nothing and shows browser's context menu
- This preserves normal browser behavior while adding custom actions on your elements
**Example use case**:
```javascript
// Modal that closes when clicking anywhere
add_mouse_support('modal', JSON.stringify({
"click": {"hx-post": "/close-modal"} // Triggers even if you click outside modal
}));
// Context menu that only appears on element
add_mouse_support('item', JSON.stringify({
"right_click": {"hx-post": "/item-menu"} // Only triggers when right-clicking the item
}));
```
### Modifier Keys (Cross-Platform)
- **Windows/Linux**: `ctrl+click` uses Ctrl key
- **Mac**: `ctrl+click` uses Cmd (⌘) key OR Ctrl key
- This follows standard web conventions for cross-platform compatibility
### Input Context Protection
Mouse actions are **disabled** when clicking in input fields:
- `<input>` elements
- `<textarea>` elements
- Any `contenteditable` element
This ensures normal text selection and interaction works in forms.
### Right-Click Menu
The contextmenu (right-click menu) is prevented with `preventDefault()` when:
- A `right_click` action is configured for the element
- The element is NOT an input/textarea/contenteditable
### Event Bubbling
The library checks if the click target OR any parent element is registered:
```html
<div id="container">
<button>Click me</button>
</div>
```
If `container` is registered, clicking the button will trigger the container's actions.
## Examples
### Using Aliases
You can use `rclick` instead of `right_click` anywhere:
```javascript
// These are equivalent
const config1 = {
"right_click": {"hx-post": "/menu"}
};
const config2 = {
"rclick": {"hx-post": "/menu"} // Shorter alias
};
// Works in sequences too
const config3 = {
"click rclick": {"hx-post": "/sequence"}
};
// Works with modifiers
const config4 = {
"ctrl+rclick": {"hx-post": "/ctrl-right-click"}
};
```
### Context Menu
```javascript
const combinations = {
"right_click": {
"hx-post": "/show-context-menu",
"hx-target": "#menu",
"hx-swap": "innerHTML"
}
};
```
### Close Modal/Popup on Click Outside
Since `click` is detected globally (anywhere on the page), it's perfect for "click outside to close":
```javascript
// Modal element
const modalCombinations = {
"click": {
"hx-post": "/close-modal",
"hx-target": "#modal",
"hx-swap": "outerHTML"
}
};
add_mouse_support('modal', JSON.stringify(modalCombinations));
// Now clicking ANYWHERE on the page will trigger the handler
// Your backend receives:
// - clicked_inside: true (if clicked on modal) → maybe keep it open
// - clicked_inside: false (if clicked outside) → close it!
```
**Backend example (Python/Flask)**:
```python
@app.route('/close-modal', methods=['POST'])
def close_modal():
clicked_inside = request.form.get('clicked_inside') == 'true'
if clicked_inside:
# User clicked inside the modal - keep it open
return render_template('modal_content.html')
else:
# User clicked outside - close the modal
return '' # Empty response removes the modal
```
**Note**: The click handler on the modal element will trigger for all clicks on the page, not just clicks on the modal itself. Use the `clicked_inside` parameter to determine the appropriate action.
### Multi-Select List
```javascript
const combinations = {
"click": {
"hx-post": "/select-item",
"hx-vals": {"mode": "single"}
},
"ctrl+click": {
"hx-post": "/select-item",
"hx-vals": {"mode": "toggle"}
},
"shift+click": {
"hx-post": "/select-range",
"hx-vals": {"mode": "range"}
}
};
```
### Interactive Canvas/Drawing
```javascript
const combinations = {
"click": {
"hx-post": "/draw-point"
},
"ctrl+click": {
"hx-post": "/draw-special"
},
"click click": {
"hx-post": "/confirm-action"
}
};
```
### Drag-and-Drop Alternative
```javascript
const combinations = {
"click": {
"hx-post": "/select-source"
},
"click click": {
"hx-post": "/set-destination"
}
};
```
## Troubleshooting
### Clicks not detected
- Verify the element exists and has the correct ID
- Check browser console for errors
- Ensure HTMX is loaded before mouse_support.js
### Right-click menu still appears
- Check if element is in input context (input/textarea)
- Verify the combination is configured correctly
- Check browser console for configuration errors
### Sequences not working
- Ensure clicks happen within 500ms timeout
- Check if longer sequences exist (causes waiting)
- Verify the combination string format (space-separated)
## Technical Details
### Architecture
- **Global listeners** on `document` for `click` and `contextmenu` events
- **Tree-based matching** using prefix trees (same as keyboard support)
- **Single timeout** for all elements (sequence-based, not element-based)
- **Independent from keyboard support** (separate registry and timeouts)
### Performance
- Single event listener regardless of number of elements
- O(n) matching where n is sequence length
- Efficient memory usage with automatic cleanup
### Browser Compatibility
- Modern browsers (ES6+ required)
- Chrome, Firefox, Safari, Edge
- Requires HTMX library
## Notes
- Timeout value is the same as keyboard support (500ms) but in separate variable
- Can be used independently or alongside keyboard support
- Does not interfere with normal mouse behavior in inputs
- Element must exist in DOM when `add_mouse_support()` is called
- **Alias**: `rclick` can be used interchangeably with `right_click` for shorter syntax