Working on Dropdown. Removed dynamic_get
This commit is contained in:
@@ -446,9 +446,6 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mf-dropdown-wrapper:hover .mf-dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mf-dropdown {
|
||||
display: none;
|
||||
|
||||
@@ -270,7 +270,7 @@ function updateTabs(controllerId) {
|
||||
/**
|
||||
* Create keyboard bindings
|
||||
*/
|
||||
(function() {
|
||||
(function () {
|
||||
/**
|
||||
* Global registry to store keyboard shortcuts for multiple elements
|
||||
*/
|
||||
@@ -342,7 +342,7 @@ function updateTabs(controllerId) {
|
||||
* Create a new trie node
|
||||
* @returns {Object} - New trie node
|
||||
*/
|
||||
function createTrieNode() {
|
||||
function createTreeNode() {
|
||||
return {
|
||||
config: null,
|
||||
combinationStr: null,
|
||||
@@ -355,18 +355,19 @@ function updateTabs(controllerId) {
|
||||
* @param {Object} combinations - Map of combination strings to HTMX config objects
|
||||
* @returns {Object} - Root trie node
|
||||
*/
|
||||
function buildTrie(combinations) {
|
||||
const root = createTrieNode();
|
||||
function buildTree(combinations) {
|
||||
const root = createTreeNode();
|
||||
|
||||
for (const [combinationStr, config] of Object.entries(combinations)) {
|
||||
const sequence = parseCombination(combinationStr);
|
||||
console.log("Parsing combination", combinationStr, "=>", sequence);
|
||||
let currentNode = root;
|
||||
|
||||
for (const keySet of sequence) {
|
||||
const key = setToKey(keySet);
|
||||
|
||||
if (!currentNode.children.has(key)) {
|
||||
currentNode.children.set(key, createTrieNode());
|
||||
currentNode.children.set(key, createTreeNode());
|
||||
}
|
||||
|
||||
currentNode = currentNode.children.get(key);
|
||||
@@ -381,12 +382,12 @@ function updateTabs(controllerId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse the trie with the current snapshot history
|
||||
* @param {Object} trieRoot - Root of the trie
|
||||
* Traverse the tree with the current snapshot history
|
||||
* @param {Object} trieRoot - Root of the tree
|
||||
* @param {Array} snapshotHistory - Array of Sets representing pressed keys
|
||||
* @returns {Object|null} - Current node or null if no match
|
||||
*/
|
||||
function traverseTrie(trieRoot, snapshotHistory) {
|
||||
function traverseTree(trieRoot, snapshotHistory) {
|
||||
let currentNode = trieRoot;
|
||||
|
||||
for (const snapshot of snapshotHistory) {
|
||||
@@ -506,6 +507,7 @@ function updateTabs(controllerId) {
|
||||
|
||||
// Add key to current pressed keys
|
||||
KeyboardRegistry.currentKeys.add(key);
|
||||
console.debug("Received key", key);
|
||||
|
||||
// Create a snapshot of current keyboard state
|
||||
const snapshot = new Set(KeyboardRegistry.currentKeys);
|
||||
@@ -530,13 +532,14 @@ function updateTabs(controllerId) {
|
||||
const element = document.getElementById(elementId);
|
||||
if (!element) continue;
|
||||
|
||||
const trieRoot = data.trie;
|
||||
const treeRoot = data.tree;
|
||||
|
||||
// Traverse the trie with current snapshot history
|
||||
const currentNode = traverseTrie(trieRoot, KeyboardRegistry.snapshotHistory);
|
||||
// Traverse the tree with current snapshot history
|
||||
const currentNode = traverseTree(treeRoot, KeyboardRegistry.snapshotHistory);
|
||||
|
||||
if (!currentNode) {
|
||||
// No match in this trie, continue to next element
|
||||
// No match in this tree, continue to next element
|
||||
console.debug("No match in tree for event", key);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -645,19 +648,23 @@ function updateTabs(controllerId) {
|
||||
* @param {string} elementId - The ID of the element
|
||||
* @param {string} combinationsJson - JSON string of combinations mapping
|
||||
*/
|
||||
window.add_keyboard_support = function(elementId, combinationsJson) {
|
||||
window.add_keyboard_support = function (elementId, combinationsJson) {
|
||||
// Parse the combinations JSON
|
||||
const combinations = JSON.parse(combinationsJson);
|
||||
|
||||
// Build trie for this element
|
||||
const trie = buildTrie(combinations);
|
||||
// Build tree for this element
|
||||
const tree = buildTree(combinations);
|
||||
|
||||
// Get element reference
|
||||
const element = document.getElementById(elementId);
|
||||
if (!element) {
|
||||
console.error("Element with ID", elementId, "not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to registry
|
||||
KeyboardRegistry.elements.set(elementId, {
|
||||
trie: trie,
|
||||
tree: tree,
|
||||
element: element
|
||||
});
|
||||
|
||||
|
||||
@@ -1,19 +1,59 @@
|
||||
from fastcore.xml import FT
|
||||
from fasthtml.components import Div
|
||||
|
||||
from myfasthtml.controls.BaseCommands import BaseCommands
|
||||
from myfasthtml.controls.Keyboard import Keyboard
|
||||
from myfasthtml.core.commands import Command
|
||||
from myfasthtml.core.instances import MultipleInstance
|
||||
|
||||
|
||||
class Commands(BaseCommands):
|
||||
def toggle(self):
|
||||
return Command("Toggle", "Toggle Dropdown", self._owner.toggle).htmx(target=f"#{self._owner.get_id()}-content")
|
||||
|
||||
def close(self):
|
||||
return Command("Close", "Close Dropdown", self._owner.close).htmx(target=f"#{self._owner.get_id()}-content")
|
||||
|
||||
|
||||
class DropdownState:
|
||||
def __init__(self):
|
||||
self.opened = False
|
||||
|
||||
|
||||
class Dropdown(MultipleInstance):
|
||||
def __init__(self, parent, content, button=None, _id=None):
|
||||
def __init__(self, parent, content=None, button=None, _id=None):
|
||||
super().__init__(parent, _id=_id)
|
||||
self.button = button
|
||||
self.button = Div(button) if not isinstance(button, FT) else button
|
||||
self.content = content
|
||||
self.commands = Commands(self)
|
||||
self._state = DropdownState()
|
||||
self._toggle_command = self.commands.toggle()
|
||||
|
||||
# attach the command to the button
|
||||
self._toggle_command.bind_ft(self.button)
|
||||
|
||||
def toggle(self):
|
||||
self._state.opened = not self._state.opened
|
||||
return self._mk_content()
|
||||
|
||||
def close(self):
|
||||
self._state.opened = False
|
||||
return self._mk_content()
|
||||
|
||||
def _mk_content(self):
|
||||
return Div(self.content,
|
||||
cls=f"mf-dropdown {'is-visible' if self._state.opened else ''}",
|
||||
id=f"{self._id}-content"),
|
||||
|
||||
def render(self):
|
||||
return Div(
|
||||
Div(self.button) if self.button else Div("None"),
|
||||
Div(self.content, cls="mf-dropdown"),
|
||||
cls="mf-dropdown-wrapper"
|
||||
Div(
|
||||
Div(self.button) if self.button else Div("None"),
|
||||
self._mk_content(),
|
||||
cls="mf-dropdown-wrapper"
|
||||
),
|
||||
Keyboard(self, "_keyboard").add("esc", self.commands.close()),
|
||||
id=self._id
|
||||
)
|
||||
|
||||
def __ft__(self):
|
||||
|
||||
@@ -102,7 +102,7 @@ class TabsManager(MultipleInstance):
|
||||
tab_config = self._state.tabs[tab_id]
|
||||
if tab_config["component_type"] is None:
|
||||
return None
|
||||
return InstancesManager.dynamic_get(self, tab_config["component_type"], tab_config["component_id"])
|
||||
return InstancesManager.get(self._session, tab_config["component_id"])
|
||||
|
||||
@staticmethod
|
||||
def _get_tab_count():
|
||||
|
||||
@@ -2,10 +2,8 @@ import logging
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from dbengine.utils import get_class
|
||||
|
||||
from myfasthtml.controls.helpers import Ids
|
||||
from myfasthtml.core.utils import pascal_to_snake, snake_to_pascal
|
||||
from myfasthtml.core.utils import pascal_to_snake
|
||||
|
||||
logger = logging.getLogger("InstancesManager")
|
||||
|
||||
@@ -215,20 +213,6 @@ class InstancesManager:
|
||||
for key, instance in InstancesManager.instances.items()
|
||||
if key[0] != session_id
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def dynamic_get(parent: BaseInstance, component_type: str, instance_id: str):
|
||||
logger.debug(f"Dynamic get: {component_type=} {instance_id=}")
|
||||
cls = InstancesManager._get_class_name(component_type)
|
||||
fully_qualified_name = f"myfasthtml.controls.{cls}.{cls}"
|
||||
cls = get_class(fully_qualified_name)
|
||||
return cls(parent, instance_id)
|
||||
|
||||
@staticmethod
|
||||
def _get_class_name(component_type: str) -> str:
|
||||
component_type = component_type.replace("mf-", "")
|
||||
component_type = snake_to_pascal(component_type)
|
||||
return component_type
|
||||
|
||||
|
||||
RootInstance = SingleInstance(None, special_session, Ids.Root)
|
||||
|
||||
Reference in New Issue
Block a user