From 628a5b684339bcfd8278aa6b7a0acb635d0a4d8a Mon Sep 17 00:00:00 2001 From: laffra Date: Thu, 16 Nov 2023 11:05:39 +0100 Subject: [PATCH] Remember the selected tab in the url --- kitchen.js | 13 +++++++--- kitchen.py | 48 ++++++++++++++++++++++-------------- ltk/jquery.py | 11 +++++++-- ltk/widgets.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 113 insertions(+), 25 deletions(-) diff --git a/kitchen.js b/kitchen.js index 1175c3a..3558e9a 100644 --- a/kitchen.js +++ b/kitchen.js @@ -1,14 +1,19 @@ -const runtime = document.location.hash == "#py" ? "py" : "mpy"; +const search = new URLSearchParams(window.location.search); +const runtime = search.get("runtime") || "mpy"; const start = new Date().getTime(); function setupRuntime() { - document.location.hash = runtime; + search.set("runtime", runtime); document.write(``) } function toggleRuntime() { - document.location.hash = runtime == "mpy" ? "py" : "mpy"; - document.location.reload() + setSearchParameter("runtime", runtime == "mpy" ? "py" : "mpy"); +} + +function setSearchParameter(key, value) { + search.set(key, value) + window.location.search = search.toString(); } function setupToggle() { diff --git a/kitchen.py b/kitchen.py index 6d5d6a1..b630437 100644 --- a/kitchen.py +++ b/kitchen.py @@ -24,25 +24,36 @@ def setsource(src): ltk.find("#title").append(f" took {js.startTime() / 1000}s to load") +tabs = ltk.Tabs( + ltk.HBox( + example.css("width", "40%"), + ltk.VBox( + ltk.H2("The source:"), + ltk.TextArea(getsource(file)) + .attr("file", file) + .css("height", 800) + .css("border-width", 0) + .css("font-family", "Courier") + ) + .css("width", "60%") + .css("padding-left", 24) + .css("border-left", "2px solid lightgray"), + ).attr("name", example.attr("name")) + for file, example in examples.items +) + + +def activate_tab(event, ui=None): + index = tabs.active() + ltk.set_url_parameter("tab", index, False) + +tabs.activate(ltk.get_url_parameter("tab") or 0) + ltk.body.append( ltk.Div( - ltk.Tabs( - ltk.HBox( - example.css("width", "40%"), - ltk.VBox( - ltk.H2("The source:"), - ltk.TextArea(getsource(file)) - .attr("file", file) - .css("height", 800) - .css("border-width", 0) - .css("font-family", "Courier") - ) - .css("width", "60%") - .css("padding-left", 24) - .css("border-left", "2px solid lightgray"), - ).attr("name", example.attr("name")) - for file, example in examples.items - ).css("margin-bottom", 24), + tabs.css("margin-bottom", 24) + .attr("id", "examples") + .on("tabsactivate", ltk.proxy(activate_tab)), ltk.Link( "https://github.com/laffra/ltk", ltk.HBox( @@ -53,4 +64,5 @@ def setsource(src): ) .css("width", 1300) .css("margin", "auto") -) \ No newline at end of file +) + diff --git a/ltk/jquery.py b/ltk/jquery.py index 90e582d..f6021e2 100644 --- a/ltk/jquery.py +++ b/ltk/jquery.py @@ -76,12 +76,19 @@ def proxy(function): def get_url_parameter(key): return js.URLSearchParams.new(js.document.location.search).get(key) -def set_url_parameter(key, value): - js.document.location = f"?{key}={value}" +def set_url_parameter(key, value, reload=True): + search = js.URLSearchParams.new(js.window.location.search) + search.set(key, value) + url = f"{js.window.location.href.split('?')[0]}?{search.toString()}" + if reload: + js.document.location = url + else: + push_state(url) def push_state(url): js.history.pushState(None, "", url) + injected = set() def inject(modulepath, *files): diff --git a/ltk/widgets.py b/ltk/widgets.py index 80ddf4b..2dac136 100644 --- a/ltk/widgets.py +++ b/ltk/widgets.py @@ -21,6 +21,7 @@ class Widget(object): + """Base class for LTK widgets.""" classes = [] instances = {} element = None @@ -35,11 +36,28 @@ def __init__(self, *args): self.handle_css(args) def handle_css(self, args): + """Apply CSS styles passed in the args to the widget. + + Iterates through the args and checks for any that are dicts, + treating them as CSS style definitions to apply to the widget. + """ for arg in filter(lambda arg: isinstance(arg, dict), args): for key, value in arg.items(): self.css(key, value) def flatten(self, children): + """Flatten a list of child widgets into a flat list. + + Arguments: + children (list): A list of child widgets. + Each child can be a Widget, a jQuery element. + Also allowed is a list or a generator of widgets. + Finally, if one of the children is a dict, it is used to set CSS values on the receiver + + Returns: + list: A flat list containing the child widgets and any + grandchildren widgets. + """ result = [] for child in children: if isinstance(child, dict): @@ -59,32 +77,38 @@ def __getattr__(self, name): class HBox(Widget): - """ HBox is a widget that lays out its child widgets horizontally """ + """ Lays out its child widgets horizontally """ classes = [ "ltk-hbox" ] class VBox(Widget): + """ Lays out its child widgets vertically """ classes = [ "ltk-vbox" ] class Div(Widget): + """ Wraps a
""" classes = [ "ltk-div" ] class Container(Widget): + """ Wraps a
""" classes = [ "ltk-container" ] class Card(Container): + """ A container with special styling looking like a card """ classes = [ "ltk-card" ] class Preformatted(Widget): + """ Wraps an HTML
 element """
     classes = [ "ltk-pre" ]
     tag = "pre"
 
 
 class Text(Widget):
+    """ A 
to hold text """ classes = [ "ltk-text" ] def __init__(self, html="", style=DEFAULT_CSS): @@ -93,6 +117,7 @@ def __init__(self, html="", style=DEFAULT_CSS): class Input(Widget): + """ Wraps an """ classes = [ "ltk-input" ] tag = "input" @@ -102,6 +127,7 @@ def __init__(self, value="", style=DEFAULT_CSS): class Button(Widget): + """ Wraps