From eaec291da09b717af03fb9dd6a6b7fe89d9a5c9a Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Fri, 14 Jul 2023 11:02:23 +0200 Subject: [PATCH] HTMLFormElement.addClass: Improve removal of duplicates. It's now possible to add multiple classes as whitespace separated string and still detect class duplicates. --- CHANGES.rst | 4 +++ src/z3c/form/browser/widget.py | 21 +++++++------ src/z3c/form/browser/widget.rst | 52 +++++++++++++++++++++++++++++++++ src/z3c/form/tests/test_doc.py | 5 ++++ 4 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 src/z3c/form/browser/widget.rst diff --git a/CHANGES.rst b/CHANGES.rst index 3cf7d0a..a3fc52a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,6 +11,10 @@ Changelog - Drop deprecated support for ``python setup.py test``. +- HTMLFormElement.addClass: Improve removal of duplicates. It's now possible to + add multiple classes as whitespace separated string and still detect class + duplicates. + 4.3 (2022-03-24) ---------------- diff --git a/src/z3c/form/browser/widget.py b/src/z3c/form/browser/widget.py index 9dd2b92..531076e 100644 --- a/src/z3c/form/browser/widget.py +++ b/src/z3c/form/browser/widget.py @@ -142,21 +142,20 @@ class HTMLFormElement(WidgetLayoutSupport): # layout support css = FieldProperty(interfaces.IHTMLFormElement['css']) - def addClass(self, klass): - """See interfaces.IHTMLFormElement""" + def addClass(self, klass: str): + """Add a class to the HTML element. + + See interfaces.IHTMLFormElement. + """ if not self.klass: self.klass = str(klass) else: # make sure items are not repeated - parts = self.klass.split() + [str(klass)] - seen = {} - unique = [] - for item in parts: - if item in seen: - continue - seen[item] = 1 - unique.append(item) - self.klass = ' '.join(unique) + parts = self.klass.split() + klass.split() + # Remove duplicates and keep order. + # Dictionaries are ordered in Python 3.7+ + parts = list(dict.fromkeys(parts)) + self.klass = " ".join(parts) def update(self): """See z3c.form.interfaces.IWidget""" diff --git a/src/z3c/form/browser/widget.rst b/src/z3c/form/browser/widget.rst new file mode 100644 index 0000000..f9fb7b5 --- /dev/null +++ b/src/z3c/form/browser/widget.rst @@ -0,0 +1,52 @@ +Widget base classes +=================== + +HTMLFormElement +--------------- +The widget base class. +:: + + >>> from z3c.form.browser.widget import HTMLFormElement + >>> form = HTMLFormElement() + + +addClass +........ + +Widgets based on :code:`HTMLFormElement` also have the :code:`addClass` method which can be used to add CSS classes to the widget. + +The :code:`klass` attribute is used because :code:`class` is a reserved keyword in Python. +It's empty per default:: + + >>> form = HTMLFormElement() + >>> form.klass + + +After adding a class it shows up in :code:`klass`:: + + >>> form.addClass("my-css-class") + >>> form.klass + 'my-css-class' + + +:code:`addClass` prevents adding the same class twice:: + + >>> form.addClass("my-css-class") + >>> form.klass + 'my-css-class' + + >>> form.addClass("another-class") + >>> form.klass + 'my-css-class another-class' + + >>> form.addClass("another-class third-class") + >>> form.klass + 'my-css-class another-class third-class' + + +The duplicate removal also keeps the original order of CSS classes:: + + >>> form.addClass("third-class another-class") + >>> form.klass + 'my-css-class another-class third-class' + diff --git a/src/z3c/form/tests/test_doc.py b/src/z3c/form/tests/test_doc.py index d424270..6ac5dd2 100644 --- a/src/z3c/form/tests/test_doc.py +++ b/src/z3c/form/tests/test_doc.py @@ -144,6 +144,11 @@ def test_suite(): '../hint.rst', setUp=setUp, tearDown=testing.tearDown, optionflags=flags, checker=testing.outputChecker, + ), + doctest.DocFileSuite( + '../browser/widget.rst', + setUp=setUp, tearDown=testing.tearDown, + optionflags=flags, checker=testing.outputChecker, )) for setUp in setups)