Exemple #1
0
    def render_checkbox(
        self,
        varname: str,
        deflt: bool = False,
        label: HTMLContent = "",
        id_: Optional[str] = None,
        **add_attr: HTMLTagAttributeValue,
    ) -> HTML:
        # Problem with checkboxes: The browser will add the variable
        # only to the URL if the box is checked. So in order to detect
        # whether we should add the default value, we need to detect
        # if the form is printed for the first time. This is the
        # case if "filled_in" is not set.
        value = self.get_checkbox(varname)
        if value is None:  # form not yet filled in
            value = deflt

        error = user_errors.get(varname)
        if id_ is None:
            id_ = "cb_%s" % varname

        add_attr["id"] = id_
        add_attr["CHECKED"] = "" if value else None

        code = self.render_input(name=varname, type_="checkbox", **add_attr) + self.render_label(
            label, for_=id_
        )
        code = HTMLWriter.render_span(code, class_="checkbox")

        if error:
            code = HTMLWriter.render_x(code, class_="inputerror")

        self.form_vars.append(varname)
        return code
Exemple #2
0
 def upload_file(self, varname: str) -> None:
     error = user_errors.get(varname)
     if error:
         self.open_x(class_="inputerror")
     self.input(name=varname, type_="file")
     if error:
         self.close_x()
     self.form_vars.append(varname)
Exemple #3
0
    def text_area(
        self,
        varname: str,
        deflt: str = "",
        rows: int = 4,
        cols: int = 30,
        try_max_width: bool = False,
        **attrs: HTMLTagAttributeValue,
    ) -> None:

        value = self.request.get_str_input(varname, deflt)
        error = user_errors.get(varname)

        self.form_vars.append(varname)
        if error:
            self.set_focus(varname)

        if try_max_width:
            style = "min-width: %d.8ex;" % cols
            cssclass = "try_max_width"

            if "class" in attrs:
                if isinstance(attrs["class"], list):
                    cssclass = " ".join([cssclass, *attrs["class"]])
                elif isinstance(attrs["class"], str):
                    cssclass += " " + attrs["class"]
            attrs["class"] = cssclass
        else:
            style = "width: %d.8ex;" % cols

        attrs["style"] = style
        attrs["rows"] = str(rows)
        attrs["cols"] = str(cols)
        attrs["name"] = varname

        # Fix handling of leading newlines (https://www.w3.org/TR/html5/syntax.html#element-restrictions)
        #
        # """
        # A single newline may be placed immediately after the start tag of pre
        # and textarea elements. This does not affect the processing of the
        # element. The otherwise optional newline must be included if the
        # element’s contents themselves start with a newline (because otherwise
        # the leading newline in the contents would be treated like the
        # optional newline, and ignored).
        # """
        if value and value.startswith("\n"):
            value = "\n" + value

        if error:
            self.open_x(class_="inputerror")
        self.write_html(render_element("textarea", value, **attrs))
        if error:
            self.close_x()
Exemple #4
0
    def dropdown(
        self,
        varname: str,
        choices: Union[Iterable[Choice], Iterable[ChoiceGroup]],
        locked_choice: Optional[ChoiceText] = None,
        deflt: ChoiceId = "",
        ordered: bool = False,
        label: Optional[str] = None,
        class_: Optional[CSSSpec] = None,
        size: int = 1,
        read_only: bool = False,
        **attrs: HTMLTagAttributeValue,
    ) -> None:
        current = self.request.get_str_input(varname, deflt)
        error = user_errors.get(varname)
        if varname:
            self.form_vars.append(varname)

        # Normalize all choices to grouped choice structure
        grouped: GroupedChoices = []
        ungrouped_group = ChoiceGroup(title="", choices=[])
        grouped.append(ungrouped_group)
        for e in choices:
            if not isinstance(e, ChoiceGroup):
                ungrouped_group.choices.append(e)
            else:
                grouped.append(e)

        if error:
            self.open_x(class_="inputerror")

        if read_only:
            attrs["disabled"] = "disabled"
            self.hidden_field(varname, current, add_var=False)

        if label:
            self.label(label, for_=varname)

        # Do not enable select2 for select fields that allow multiple
        # selections like the dual list choice valuespec
        css_classes = (
            []
            if "multiple" in attrs or (isinstance(class_, list) and "ajax-vals" in class_)
            else ["select2-enable"]
        )

        if isinstance(class_, list):
            css_classes.extend(class_)
        elif class_ is not None:
            css_classes.append(class_)

        self.open_select(
            name=varname, id_=varname, label=label, class_=css_classes, size=str(size), **attrs
        )

        for group in grouped:
            if group.title:
                self.open_optgroup(label=group.title)

            for value, text in (
                group.choices if not ordered else sorted(group.choices, key=lambda a: a[1].lower())
            ):
                # if both the default in choices and current was '' then selected depended on the order in choices
                selected = (value == current) or (not value and not current)
                self.option(
                    text,
                    value=value if value else "",
                    selected="" if selected else None,
                )

            if locked_choice:
                self.option(locked_choice, value="", disabled="")

            if group.title:
                self.close_optgroup()

        self.close_select()
        if error:
            self.close_x()
Exemple #5
0
    def text_input(
        self,
        varname: str,
        default_value: str = "",
        cssclass: str = "text",
        size: Union[None, str, int] = None,
        label: Optional[str] = None,
        id_: Optional[str] = None,
        submit: Optional[str] = None,
        try_max_width: bool = False,
        read_only: bool = False,
        autocomplete: Optional[str] = None,
        style: Optional[str] = None,
        type_: Optional[str] = None,
        onkeyup: Optional[str] = None,
        onblur: Optional[str] = None,
        placeholder: Optional[str] = None,
        data_world: Optional[str] = None,
        data_max_labels: Optional[int] = None,
        required: bool = False,
        title: Optional[str] = None,
    ) -> None:

        # Model
        error = user_errors.get(varname)
        value = self.request.get_str_input(varname, default_value)
        if not value:
            value = ""
        if error:
            self.set_focus(varname)
        self.form_vars.append(varname)

        # View
        # TODO: Move styling away from py code
        # Until we get there: Try to simplify these width stylings and put them in a helper function
        # that's shared by text_input and text_area
        style_size: list[str] = []
        field_size: Optional[str] = None

        if size is not None:
            if try_max_width:
                assert isinstance(size, int)
                style_size = ["min-width: %d.8ex;" % size]
                cssclass += " try_max_width"
            else:
                if size == "max":
                    style_size = ["width: 100%;"]
                else:
                    assert isinstance(size, int)
                    field_size = "%d" % (size + 1)
                    if (style is None or "width:" not in style) and not self.mobile:
                        style_size = ["width: %d.8ex;" % size]

        attributes: HTMLTagAttributes = {
            "class": cssclass,
            "id": ("ti_%s" % varname) if (submit or label) and not id_ else id_,
            "style": style_size + ([] if style is None else [style]),
            "size": field_size,
            "autocomplete": autocomplete,
            "readonly": "true" if read_only else None,
            "value": value,
            "onblur": onblur,
            "onkeyup": onkeyup,
            "onkeydown": ("cmk.forms.textinput_enter_submit(event, %s);" % json.dumps(submit))
            if submit
            else None,
            "placeholder": placeholder,
            "data-world": data_world,
            "data-max-labels": None if data_max_labels is None else str(data_max_labels),
            "required": "" if required else None,
            "title": title,
        }

        if error:
            self.open_x(class_="inputerror")

        if label:
            assert id_ is not None
            self.label(label, for_=id_, class_="required" if required else None)

        input_type = "text" if type_ is None else type_
        assert isinstance(input_type, str)
        self.write_html(self.render_input(varname, type_=input_type, **attributes))

        if error:
            self.close_x()