From b57004d70d4ebf1fe33e20f3383058bfe2fc20a4 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sun, 5 Dec 2021 14:41:42 +0000 Subject: [PATCH] forms: Refactor classes Signed-off-by: Michael Tremer --- src/templates/modules/forms/fieldset.html | 2 +- src/templates/modules/forms/index.html | 6 +- src/westferry/ui/forms.py | 230 +++++++++------------- 3 files changed, 94 insertions(+), 144 deletions(-) diff --git a/src/templates/modules/forms/fieldset.html b/src/templates/modules/forms/fieldset.html index 0ea9469..c1ef4c0 100644 --- a/src/templates/modules/forms/fieldset.html +++ b/src/templates/modules/forms/fieldset.html @@ -9,5 +9,5 @@

{% end %} - {% module FormElements(fs) %} + {% module FormElements(fs.elements) %} diff --git a/src/templates/modules/forms/index.html b/src/templates/modules/forms/index.html index 1992ac2..34e7c3d 100644 --- a/src/templates/modules/forms/index.html +++ b/src/templates/modules/forms/index.html @@ -1,7 +1,7 @@ -
+ {% raw xsrf_form_html() %} - {% module FormElements(f) %} + {% module FormElements(form.elements) %} - +
diff --git a/src/westferry/ui/forms.py b/src/westferry/ui/forms.py index ec4bfcd..6f2f787 100644 --- a/src/westferry/ui/forms.py +++ b/src/westferry/ui/forms.py @@ -19,153 +19,125 @@ # # ############################################################################### -from ..backend import forms from . import base -class _Form(object): - def __init__(self, form): +class Form(object): + def __init__(self, handler, method="POST", action="", + form=None, label=None, help=None, disabled=False): + self.handler = handler + self.method = method + self.action = action self.form = form - self._elements = [] + self.label = label + self.help = help + + self.elements = [] # Is this form disabled? - self.disabled = False + self.disabled = disabled def __iter__(self): """ Iterating over a form will iterate over its elements. """ - return iter(self._elements) + for element in self.elements: + yield element - @property - def parent_form(self): - if self.form: - return self.form.parent_form + if isinstance(element, Form): + for e in element: + yield e + + def export(self): + """ + Returns a dictionary with all keys and values + of the form. + """ + ret = {} - return self + for element in self: + # Skip any sub-form elements + if isinstance(element, Form): + continue - @property - def elements(self): - for e in self._elements: - if isinstance(e, _Form): - for i in e._elements: - yield i + ret[element.name] = element.value + + return ret + + # Sub-Forms - else: - yield e + def _add_subform(self, cls, *args, **kwargs): + form = cls(self.handler, *args, form=self, **kwargs) + self.elements.append(form) - def _add_element(self, element): + return form + + def add_group(self, *args, **kwargs): + return self._add_subform(Group, *args, **kwargs) + + def add_fieldset(self, *args, **kwargs): + return self._add_subform(Fieldset, *args, **kwargs) + + # Elements + + def _add_element(self, cls, *args, **kwargs): """ Adds a new form element to this form. """ - assert isinstance(element, Element) - assert not element in self.elements - - self._elements.append(element) + element = cls(self, *args, **kwargs) + self.elements.append(element) - def _add_element_class(self, cls, *args, **kwargs): - e = cls(self, *args, **kwargs) - self._add_element(e) - - return e + return element def get_element_by_name(self, name): """ Returns the element with the given name (if any). """ - for e in self.elements: - if e.name == name: - return e + for element in self: + if element.name == name: + return element # Have a shortcut to find elements by their name quickly. - get = get_element_by_name + __getattr__ = get_element_by_name def add_text_input(self, *args, **kwargs): """ - Creates a new text input. + Creates a new text input """ - return self._add_element_class(TextInput, *args, **kwargs) + return self._add_element(TextInput, *args, **kwargs) def add_multiline_text_input(self, *args, **kwargs): """ - Creates a new multiline text input. + Creates a new multiline text input """ - return self._add_element_class(MultilineTextInput, *args, **kwargs) + return self._add_element(MultilineTextInput, *args, **kwargs) def add_password_input(self, *args, **kwargs): """ - Creates a new password input. + Creates a new password input """ - return self._add_element_class(PasswordInput, *args, **kwargs) + return self._add_element(PasswordInput, *args, **kwargs) def add_yesno_input(self, *args, **kwargs): """ - Creates a new yes/no input. + Creates a new yes/no input """ - return self._add_element_class(YesNoInput, *args, **kwargs) + return self._add_element(YesNoInput, *args, **kwargs) def add_single_choice_input(self, *args, **kwargs): """ - Creates a new single choice input. + Creates a new single choice input """ - return self._add_element_class(SingleChoiceInput, *args, **kwargs) + return self._add_element(SingleChoiceInput, *args, **kwargs) def add_multiple_choice_input(self, *args, **kwargs): """ - Creates a new multiple choice input. + Creates a new multiple choice input """ - return self._add_element_class(MultipleChoiceInput, *args, **kwargs) - - def _get_value(self, *args, **kwargs): - return self.parent_form._get_value(*args, **kwargs) + return self._add_element(MultipleChoiceInput, *args, **kwargs) -class FormGroupMixin(object): - def add_group(self, *args, **kwargs): - group = Group(self, *args, **kwargs) - self._elements.append(group) - - return group - - -class Form(_Form, FormGroupMixin): - def __init__(self, handler, method="POST", action=""): - _Form.__init__(self, None) - self.handler = handler - - self.method = method - self.action = action - - # Text that is shown on the submit button - self.submit_text = None - - def add_fieldset(self, *args, **kwargs): - fs = Fieldset(self, *args, **kwargs) - self._elements.append(fs) - - return fs - - def export(self): - """ - Returns a dictionary with all keys and values - of the form. - """ - ret = {} - - for e in self.elements: - ret[e.name] = e.value - - return ret - - def _get_value(self, name, default=None): - return self.handler.get_argument(name, default) - - -class Fieldset(_Form, FormGroupMixin): - def __init__(self, *args, label=None, help=None, **kwargs): - _Form.__init__(self, *args, **kwargs) - - self.label = label - self.help = help +class Fieldset(Form): + pass class FormFieldsetModule(base.BaseUIModule): @@ -173,19 +145,16 @@ class FormFieldsetModule(base.BaseUIModule): return self.render_string("modules/forms/fieldset.html", fs=fieldset) -class Group(_Form): - def __init__(self, *args, label=None, **kwargs): - _Form.__init__(self, *args, **kwargs) - - self.label = label - self.help = None +class Group(Form): + pass class Element(object): # The element type type = None - def __init__(self, form, name=None, label=None, default=None, **kwargs): + def __init__(self, form, name=None, label=None, default=None, + disabled=False, readonly=False, **kwargs): assert self.type self.form = form @@ -194,25 +163,16 @@ class Element(object): self.default = default # Is this element editable? - self.disabled = False - self.readonly = False + self.disabled = disabled + self.readonly = readonly # Help text self.help = None - # Set defaults for inheriting classes - self._set_defaults() - - # Set args - for k, v in kwargs.items(): - setattr(self, k, v) + # Call initializer for inheriting classes + self.initialize(**kwargs) - self.init(**kwargs) - - def _set_defaults(self): - pass - - def init(self, *args, **kwargs): + def initialize(self): pass @property @@ -220,10 +180,7 @@ class Element(object): """ Returns the value that the user entered for this element. """ - return self.get_value() - - def get_value(self): - return self.form._get_value(self.name, self.default) + return self.form.handler.get_argument(self.name, self.default) class SingleChoiceInput(Element): @@ -236,8 +193,7 @@ class MultipleChoiceInput(Element): class FormModule(base.BaseUIModule): def render(self, form): - return self.render_string("modules/forms/index.html", - f=form, forms=forms) + return self.render_string("modules/forms/index.html", form=form) class FormElementsModule(base.BaseUIModule): @@ -248,19 +204,11 @@ class FormElementsModule(base.BaseUIModule): class TextInput(Element): type = "text" - def _set_defaults(self): - self.prefix = None - self.suffix = None - - self._placeholder = None + def initialize(self, prefix=None, suffix=None, placeholder=None): + self.prefix = prefix + self.suffix = suffix - def get_placeholder(self): - return self._placeholder or self.label - - def set_placeholder(self, placeholder): - self._placeholder = placeholder - - placeholder = property(get_placeholder, set_placeholder) + self.placeholder = placeholder or self.label class TextInputModule(base.BaseUIModule): @@ -277,11 +225,13 @@ class PasswordInput(TextInput): class MultilineTextInput(TextInput): type = "multiline-text" - def _set_defaults(self): - TextInput._set_defaults(self) + DEFAULT_LINES = 3 + + def initialize(self, lines=DEFAULT_LINES, **kwargs): + super().initialize(**kwargs) + + self.lines = lines - # Default number of rows - self.lines = 3 class MultilineTextInputModule(base.BaseUIModule): @@ -294,8 +244,8 @@ class MultilineTextInputModule(base.BaseUIModule): class YesNoInput(Element): type = "yesno" - def _set_defaults(self): - self.description = None + def initialize(self, description=None): + self.description = description def get_value(self): value = Element.get_value(self) -- 2.47.3