from owrx.form.error import FormError from owrx.form.input import Input from typing import List class Section(object): def __init__(self, title, *inputs): self.title = title self.inputs = inputs def render_input(self, input, data, errors): return input.render(data, errors) def render_inputs(self, data, errors): return "".join([self.render_input(i, data, errors) for i in self.inputs]) def classes(self): return ["col-12", "settings-section"] def render(self, data, errors): return """

{title}

{inputs}
""".format( classes=" ".join(self.classes()), title=self.title, inputs=self.render_inputs(data, errors) ) def parse(self, data): parsed_data = {} errors = [] for i in self.inputs: try: parsed_data.update(i.parse(data)) except FormError as e: errors.append(e) except Exception as e: errors.append(FormError(i.id, "{}: {}".format(type(e).__name__, e))) return parsed_data, errors class OptionalSection(Section): def __init__(self, title, inputs: List[Input], mandatory, optional): super().__init__(title, *inputs) self.mandatory = mandatory self.optional = optional self.optional_inputs = [] def classes(self): classes = super().classes() classes.append("optional-section") return classes def _is_optional(self, input): return input.id in self.optional def render_optional_select(self): return """
""".format( options="".join( """ """.format( value=input.id, name=input.getLabel(), ) for input in self.optional_inputs ) ) def render_optional_inputs(self, data, errors): return """ """.format( inputs="".join(self.render_input(input, data, errors) for input in self.optional_inputs) ) def render_inputs(self, data, errors): return ( super().render_inputs(data, errors) + self.render_optional_select() + self.render_optional_inputs(data, errors) ) def render(self, data, errors): indexed_inputs = {input.id: input for input in self.inputs} visible_keys = set(self.mandatory + [k for k in self.optional if k in data]) optional_keys = set(k for k in self.optional if k not in data) self.inputs = [input for k, input in indexed_inputs.items() if k in visible_keys] for input in self.inputs: if self._is_optional(input): input.setRemovable() self.optional_inputs = [input for k, input in indexed_inputs.items() if k in optional_keys] for input in self.optional_inputs: input.setRemovable() input.setDisabled() return super().render(data, errors) def parse(self, data): data, errors = super().parse(data) # filter out errors for optional fields errors = [e for e in errors if e.getKey() not in self.optional or e.getKey() in data] # remove optional keys if they have been removed from the form by setting them to None for k in self.optional: if k not in data: data[k] = None return data, errors