From 1cfa4216999549441c2e55ba854d7815a7ab7132 Mon Sep 17 00:00:00 2001 From: Zamy846692 <133600041+Zamy846692@users.noreply.github.com> Date: Sun, 8 Feb 2026 19:56:26 +0000 Subject: [PATCH 01/20] Will now "load" mailto links if request_func is specified --- tkinterweb/htmlwidgets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tkinterweb/htmlwidgets.py b/tkinterweb/htmlwidgets.py index 3ee9ec3..b5b2215 100755 --- a/tkinterweb/htmlwidgets.py +++ b/tkinterweb/htmlwidgets.py @@ -524,6 +524,7 @@ def load_url(self, url, decode=None, force=False): :type force: bool, optional""" ### TODO: Maybe consider merging load_url, load_file, and load_website into one ### One could use the checker from the sample web browser + if url.startswith("mailto") and not self._html.request_func: return # Don't try to load emails! if not self._current_url == url: self._previous_url = self._current_url if url in utilities.BUILTIN_PAGES: From 486c31459a95fe7f261b9d5fc6964416d0edef9a Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Mon, 9 Feb 2026 18:13:45 +0000 Subject: [PATCH 02/20] Rename parsed URI bindings --- tkinterweb/bindings.py | 11 +++++------ tkinterweb/handlers.py | 12 +++--------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/tkinterweb/bindings.py b/tkinterweb/bindings.py index bb8762b..808a07b 100644 --- a/tkinterweb/bindings.py +++ b/tkinterweb/bindings.py @@ -1750,8 +1750,7 @@ def escape_uri(self, uri, query=False): """Returns the decoded data. New in version 4.19.""" - a = "-query" if query else "" - return self.tk.call("::tkhtml::escape_uri", a, uri) + return self.tk.call("::tkhtml::escape_uri", "-query" if query else "", uri) class TkHtmlParsedURI: """Bindings for the Tkhtml URI parsing system. @@ -1777,19 +1776,19 @@ def uri(self, uri): "Returns name of parsed uri to be used in methods below." return self._html.tk.call("::tkhtml::uri", uri) - def tkhtml_uri_decode(self, uri, base64=False): + def decode(self, uri, base64=False): "This command is designed to help scripts process data: URIs. It is completely separate from the html widget" return self._html.tkhtml_uri_decode(uri, base64) - def tkhtml_uri_encode(self, uri): + def encode(self, uri): "Encodes the uri." return self._html.tkhtml_uri_encode(uri) - def tkhtml_uri_escape(self, uri, query=False): + def escape(self, uri, query=False): "Returns the decoded data." return self._html.tkhtml_uri_escape(uri, query) - def uri_resolve(self, uri): + def resolve(self, uri): "Resolve a uri." return self._html.tk.call(self.parsed, "resolve", uri) diff --git a/tkinterweb/handlers.py b/tkinterweb/handlers.py index a99e3b4..7dea951 100644 --- a/tkinterweb/handlers.py +++ b/tkinterweb/handlers.py @@ -297,20 +297,14 @@ def _handle_form_submission(self, node, event=None): continue elif nodetype == "file": for value in nodevalue: - data.append( - (nodeattrname, value), - ) + data.append((nodeattrname, value),) else: - data.append( - (nodeattrname, nodevalue), - ) + data.append((nodeattrname, nodevalue),) if not event: nodeattrname = self.html.get_node_attribute(node, "name") nodevalue = self.html.get_node_attribute(node, "value") if nodeattrname and nodevalue: - data.append( - (nodeattrname, nodevalue), - ) + data.append((nodeattrname, nodevalue),) data = urlencode(data) From 48f1dfb8c17effb2063462b9cc325613f28558cc Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Tue, 10 Feb 2026 01:28:32 +0000 Subject: [PATCH 03/20] "details" and "progress" are now loaded for experimental --- tkinterweb/bindings.py | 3 +-- tkinterweb/handlers.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tkinterweb/bindings.py b/tkinterweb/bindings.py index 808a07b..6c60215 100644 --- a/tkinterweb/bindings.py +++ b/tkinterweb/bindings.py @@ -297,7 +297,7 @@ def _setup_handlers(self): self.register_lazy_handler("node", "base", "node_manager") self.register_lazy_handler("attribute", "a", "node_manager") - if not self.using_tkhtml30: + if not self.using_tkhtml30 or self.experimental: #self.register_lazy_handler("node", "details", "node_manager") self.register_lazy_handler("node", "progress", "node_manager") self.register_lazy_handler("attribute", "progress", "node_manager") @@ -676,7 +676,6 @@ def _parse(self, html): self.script_manager._submit_deferred_scripts() self.event_manager.send_onload() - #if self.using_tkhtml30: # Handle unsupported tags self.node_manager._handle_load_finish() def _handle_load_finish(self, post_event=True): diff --git a/tkinterweb/handlers.py b/tkinterweb/handlers.py index 7dea951..51cdf00 100644 --- a/tkinterweb/handlers.py +++ b/tkinterweb/handlers.py @@ -159,7 +159,7 @@ def _update_details(self, node, display): def _set_open(self, node, display): self.html.set_node_attribute(node, "open", "" if display else "false") - if self.html.using_tkhtml30: + if self.html.using_tkhtml30 and not self.html.experimental: # In Tkhtml 3.1+ we add an attribute handler, which does this for us self._update_details(node, display) @@ -204,7 +204,7 @@ def _handle_summary_click(self, node): open = not self._is_open(details) self._set_open(details, open) - if open and self.html.using_tkhtml30: + if open and self.html.using_tkhtml30 or not self.html.experimental: self._close_other_details(details) def _on_progress(self, node): From d3c0fceb3f91dc8c1a77b2dfbd60ea19172e0e5b Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Thu, 12 Feb 2026 23:04:01 +0000 Subject: [PATCH 04/20] HtmlLabel ttk style options are now dynamic converted to CSS rules. Removed .cget style --- tkinterweb/htmlwidgets.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tkinterweb/htmlwidgets.py b/tkinterweb/htmlwidgets.py index b5b2215..e2f88cd 100755 --- a/tkinterweb/htmlwidgets.py +++ b/tkinterweb/htmlwidgets.py @@ -1586,18 +1586,20 @@ def __init__(self, master, *, text="", **kwargs): def load_html(self, *args, _relayout=True, **kwargs): "" - # Match the ttk theme - style_type = self.cget("style") - bg = self._style.lookup(style_type, 'background') - fg = self._style.lookup(style_type, 'foreground') - style = self._html.default_style + \ - (self._html.dark_style if self._html.dark_theme_enabled else "") +\ - f"BODY {{ background-color: {bg}; color: {fg}; }}" - self._html.configure(defaultstyle=style) - # Load the HTML super().load_html(*args, **kwargs) + # Match the ttk theme + style_type = self.cget("style") + options = { + 'background-color': 'background', + 'color': 'foreground', + } + css = "BODY {" + ";".join( + f"{p}:{self._style.lookup(style_type, v)}" for p, v in options.items() + ) + "}" + self.add_css(css) + # This stops infinite flickering when tables are present # My computer was having this bug for a while but now I don't experience it # But this doesn't seem to have any major side effects @@ -1620,13 +1622,9 @@ def cget(self, key): "" if "text" == key: return "".join(self._html.serialize_node(0).splitlines()) - elif "style" == key: - return "".join(self._html.serialize_node_style(0).splitlines()) return super().cget(key) - def config(self, **kwargs): - "" - self.configure(**kwargs) + config = configure class HtmlText(HtmlFrame): """The :class:`HtmlText` widget is a text-like HTML widget. It inherits from the :class:`HtmlFrame` class. From f41e0540e443a3c1f0255f16b96e2a7f8b1d9ef5 Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Fri, 13 Feb 2026 15:43:29 +0000 Subject: [PATCH 05/20] HtmlLabel class's ttk style can now be changed after initialization and is cached --- tkinterweb/htmlwidgets.py | 11 ++--------- tkinterweb/utilities.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/tkinterweb/htmlwidgets.py b/tkinterweb/htmlwidgets.py index e2f88cd..7c1de7a 100755 --- a/tkinterweb/htmlwidgets.py +++ b/tkinterweb/htmlwidgets.py @@ -1590,15 +1590,7 @@ def load_html(self, *args, _relayout=True, **kwargs): super().load_html(*args, **kwargs) # Match the ttk theme - style_type = self.cget("style") - options = { - 'background-color': 'background', - 'color': 'foreground', - } - css = "BODY {" + ";".join( - f"{p}:{self._style.lookup(style_type, v)}" for p, v in options.items() - ) + "}" - self.add_css(css) + self.add_css(utilities.ttk_style_css(self, self.cget("style"))) # This stops infinite flickering when tables are present # My computer was having this bug for a while but now I don't experience it @@ -1615,6 +1607,7 @@ def configure(self, **kwargs): if "style" in kwargs: utilities.warn("Since version 4.14 the style keyword no longer sets the HtmlLabel's CSS code. Please use the add_css() method instead.") + self.add_css(utilities.ttk_style_css(self, kwargs.pop("style"))) if kwargs: super().configure(**kwargs) diff --git a/tkinterweb/utilities.py b/tkinterweb/utilities.py index 62cc9c5..875ac6b 100644 --- a/tkinterweb/utilities.py +++ b/tkinterweb/utilities.py @@ -909,6 +909,17 @@ def check_download(url, data="", method="GET", decode=None, insecure=False, cafi return lru_cache.check(url, data, method, decode, insecure, cafile, headers, timeout) +@lru_cache() +def ttk_style_css(self, style_type): + options = { + 'background-color': 'background', + 'color': 'foreground', + } + return "BODY {" + ";".join( + f"{p}:{self._style.lookup(style_type, v)}" for p, v in options.items() + ) + "}" + + def shorten(string): "Shorten text to avoid overloading the terminal" if len(string) > 100: From b143d1b4dd3665f06eb7456ee44194142049c3e7 Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Fri, 13 Feb 2026 17:12:29 +0000 Subject: [PATCH 06/20] Moved ttk_style_css to be a method of HtmlLabel --- tkinterweb/htmlwidgets.py | 13 +++++++++++-- tkinterweb/utilities.py | 11 ----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/tkinterweb/htmlwidgets.py b/tkinterweb/htmlwidgets.py index 7c1de7a..e8eae3c 100755 --- a/tkinterweb/htmlwidgets.py +++ b/tkinterweb/htmlwidgets.py @@ -1590,7 +1590,7 @@ def load_html(self, *args, _relayout=True, **kwargs): super().load_html(*args, **kwargs) # Match the ttk theme - self.add_css(utilities.ttk_style_css(self, self.cget("style"))) + self.add_css(self._ttk_style_css(self.cget("style"))) # This stops infinite flickering when tables are present # My computer was having this bug for a while but now I don't experience it @@ -1600,6 +1600,15 @@ def load_html(self, *args, _relayout=True, **kwargs): self.update_idletasks() self._html.relayout() + @utilities.lru_cache() + def _ttk_style_css(self, style_type): + options = { + 'background-color': 'background', 'color': 'foreground', + } + return "BODY {" + ";".join( + f"{p}:{self._style.lookup(style_type, v)}" for p, v in options.items() + ) + "}" + def configure(self, **kwargs): "" if "text" in kwargs: @@ -1607,7 +1616,7 @@ def configure(self, **kwargs): if "style" in kwargs: utilities.warn("Since version 4.14 the style keyword no longer sets the HtmlLabel's CSS code. Please use the add_css() method instead.") - self.add_css(utilities.ttk_style_css(self, kwargs.pop("style"))) + self.add_css(self._ttk_style_css(kwargs.pop("style"))) if kwargs: super().configure(**kwargs) diff --git a/tkinterweb/utilities.py b/tkinterweb/utilities.py index 875ac6b..62cc9c5 100644 --- a/tkinterweb/utilities.py +++ b/tkinterweb/utilities.py @@ -909,17 +909,6 @@ def check_download(url, data="", method="GET", decode=None, insecure=False, cafi return lru_cache.check(url, data, method, decode, insecure, cafile, headers, timeout) -@lru_cache() -def ttk_style_css(self, style_type): - options = { - 'background-color': 'background', - 'color': 'foreground', - } - return "BODY {" + ";".join( - f"{p}:{self._style.lookup(style_type, v)}" for p, v in options.items() - ) + "}" - - def shorten(string): "Shorten text to avoid overloading the terminal" if len(string) > 100: From 6d585192dc7b83f086fb1de22bf1de22b7051bdb Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Thu, 5 Mar 2026 18:14:06 +0000 Subject: [PATCH 07/20] Revert to using the default stylesheet when adding ttk styles to CSS --- tkinterweb/htmlwidgets.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tkinterweb/htmlwidgets.py b/tkinterweb/htmlwidgets.py index e8eae3c..44acdf0 100755 --- a/tkinterweb/htmlwidgets.py +++ b/tkinterweb/htmlwidgets.py @@ -1577,7 +1577,11 @@ def __init__(self, master, *, text="", **kwargs): self._style = Style() + # Match the ttk theme + self._ttk_style_css(kwargs["style"]) + if text: self.load_html(text) + # I'd like to just make this an else statement to prevent the widget from being a massive white screen when text="" elif self.unshrink or (not self._html.using_tkhtml30 and not self._html.cget("textwrap")): # A fellow in issue 145 mentioned layout issues when this was used @@ -1589,9 +1593,6 @@ def load_html(self, *args, _relayout=True, **kwargs): # Load the HTML super().load_html(*args, **kwargs) - # Match the ttk theme - self.add_css(self._ttk_style_css(self.cget("style"))) - # This stops infinite flickering when tables are present # My computer was having this bug for a while but now I don't experience it # But this doesn't seem to have any major side effects @@ -1600,23 +1601,22 @@ def load_html(self, *args, _relayout=True, **kwargs): self.update_idletasks() self._html.relayout() - @utilities.lru_cache() def _ttk_style_css(self, style_type): - options = { - 'background-color': 'background', 'color': 'foreground', - } - return "BODY {" + ";".join( - f"{p}:{self._style.lookup(style_type, v)}" for p, v in options.items() - ) + "}" + bg = self._style.lookup(style_type, 'background') + fg = self._style.lookup(style_type, 'foreground') + style = self._html.default_style +\ + (self._html.dark_style if self._html.dark_theme_enabled else "") +\ + f"BODY {{ background-color: {bg}; color: {fg}; }}" + self._html.configure(defaultstyle=style) def configure(self, **kwargs): - "" + "Sets the default value of the specified option(s) in Label/HTML." if "text" in kwargs: self.load_html(kwargs.pop("text")) if "style" in kwargs: utilities.warn("Since version 4.14 the style keyword no longer sets the HtmlLabel's CSS code. Please use the add_css() method instead.") - self.add_css(self._ttk_style_css(kwargs.pop("style"))) + self._ttk_style_css(kwargs["style"]) if kwargs: super().configure(**kwargs) From f09b6d0370e592300421b6eb5906462cf5614c90 Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Mon, 16 Mar 2026 22:00:28 +0000 Subject: [PATCH 08/20] Fix undefined window variable --- tkinterweb/dom.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tkinterweb/dom.py b/tkinterweb/dom.py index 411bdb3..58e6250 100644 --- a/tkinterweb/dom.py +++ b/tkinterweb/dom.py @@ -411,9 +411,9 @@ def textContent(self, contents): # Ditto self.html.widget_manager.set_node_widget(node, None) self.html.safe_tk_eval(""" - set html %s set node %s set textnode %s + if {$textnode eq ""} {error "$node is empty"} if {[$node tag] eq "html"} {error "textContent cannot be set on <$tag> elements"} $node remove [$node children] @@ -422,8 +422,8 @@ def textContent(self, contents): # Ditto } $node insert $textnode - if {[winfo ismapped $html]} {update} ; # This must be done to see changes on-screen - """ % (self.html, extract_nested(self.node), self.document.createTextNode(contents).node) + if {[winfo ismapped .]} {update} ; # This must be done to see changes on-screen + """ % (extract_nested(self.node), self.document.createTextNode(contents).node) ) else: self.html.set_node_text(self.node, contents) From 20eebf9e4673565fb289e930ef8c3c98bbb5cbcf Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Mon, 16 Mar 2026 22:09:08 +0000 Subject: [PATCH 09/20] Simplified indexing syntax-like get/set --- tkinterweb/htmlwidgets.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tkinterweb/htmlwidgets.py b/tkinterweb/htmlwidgets.py index 44acdf0..f4845a1 100755 --- a/tkinterweb/htmlwidgets.py +++ b/tkinterweb/htmlwidgets.py @@ -1543,11 +1543,10 @@ def unbind(self, sequence, *args, **kwargs): else: self._html.unbind(sequence, *args, **kwargs) - def __getitem__(self, key): - return self.cget(key) + def __setitem__(self, k, v): self.configure({k: v}) + + __getitem__ = cget - def __setitem__(self, key, value): - self.configure(**{key: value}) class HtmlLabel(HtmlFrame): From cf77225b5e6e6834f759ebf778243b8144d9ae09 Mon Sep 17 00:00:00 2001 From: Zamy846692 Date: Mon, 30 Mar 2026 00:16:54 +0100 Subject: [PATCH 10/20] and are added automatically by TkHTML; so removed them here --- examples/TkinterWebBrowser.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/TkinterWebBrowser.py b/examples/TkinterWebBrowser.py index 1dd4a14..ffa6331 100755 --- a/examples/TkinterWebBrowser.py +++ b/examples/TkinterWebBrowser.py @@ -267,8 +267,7 @@ def __init__(self, master, *args, **kwargs): self.sidebar.javascript.register("frame", frame) - self.sidebar.load_html(f""" - + self.sidebar.load_html(f"""