All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.larmic.butterfaces.component.renderkit.html_basic.text.AbstractTextRenderer Maven / Gradle / Ivy

package de.larmic.butterfaces.component.renderkit.html_basic.text;

import de.larmic.butterfaces.component.html.HtmlInputComponent;
import de.larmic.butterfaces.component.html.HtmlTooltip;
import de.larmic.butterfaces.component.html.InputComponentFacet;
import de.larmic.butterfaces.component.html.text.part.HtmlAutoComplete;
import de.larmic.butterfaces.component.partrenderer.*;

import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import java.io.IOException;

public abstract class AbstractTextRenderer extends de.larmic.butterfaces.component.renderkit.html_basic.HtmlBasicRenderer {

    @Override
    public void encodeBegin(final FacesContext context, final UIComponent component) throws IOException {
        this.encodeBegin(context, component, "");
    }

    public void encodeBegin(final FacesContext context, final UIComponent component, final String additionalStyleClass) throws IOException {
        if (!component.isRendered()) {
            return;
        }

        super.encodeBegin(context, component);

        final T htmlComponent = (T) component;

        final ResponseWriter writer = context.getResponseWriter();

        // Open outer component wrapper div
        new OuterComponentWrapperPartRenderer().renderComponentBegin(component, writer, additionalStyleClass);

        // Render label if components label attribute is set
        new LabelPartRenderer().renderLabel(component, writer);

        this.encodeBeginInnerWrapper(component, writer);
        this.encodeReadonly(htmlComponent, writer);
    }

    @Override
    public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException {
        if (!component.isRendered()) {
            return;
        }

        final T htmlComponent = (T) component;
        final ResponseWriter writer = context.getResponseWriter();

        if (!htmlComponent.isReadonly()) {
            this.encodeEndContent(context, component, htmlComponent, writer);
        }

        this.encodeInnerEnd(component, writer);

        this.encodeEndInnerWrapper(component, writer);

        renderTooltipIfNecessary(context, component);

        this.encodeEnd(component, writer);

        // Open outer component wrapper div
        new OuterComponentWrapperPartRenderer().renderComponentEnd(writer);
    }

    protected void renderTooltipIfNecessary(final FacesContext context, final UIComponent component) throws IOException {
        for (UIComponent uiComponent : component.getChildren()) {
            if (uiComponent instanceof HtmlTooltip) {
                uiComponent.encodeAll(context);
                if (uiComponent.isRendered()) {
                    break;
                }
            }
        }

        new TooltipPartRenderer().renderTooltipIfNecessary(context, component);
    }

    protected void encodeEndContent(FacesContext context, UIComponent component, HtmlInputComponent htmlComponent, ResponseWriter writer) throws IOException {
        final UIComponent inputGroupAddonLeftFacet = component.getFacet(InnerComponentWrapperPartRenderer.INPUT_GROUP_ADDON_LEFT);
        final UIComponent inputGroupAddonRightFacet = component.getFacet(InnerComponentWrapperPartRenderer.INPUT_GROUP_ADDON_RIGHT);
        final UIComponent inputGroupBtnLeftFacet = component.getFacet(InnerComponentWrapperPartRenderer.INPUT_GROUP_BTN_LEFT);
        final UIComponent inputGroupBtnRightFacet = component.getFacet(InnerComponentWrapperPartRenderer.INPUT_GROUP_BTN_RIGHT);
        if (htmlComponent.getSupportedFacets().contains(InputComponentFacet.BOOTSTRAP_INPUT_GROUP_LEFT_ADDON) && inputGroupAddonLeftFacet != null) {
            writer.startElement("span", component);
            writer.writeAttribute("class", "input-group-addon", null);
            inputGroupAddonLeftFacet.encodeAll(context);
            writer.endElement("span");
        }
        if (htmlComponent.getSupportedFacets().contains(InputComponentFacet.BOOTSTRAP_INPUT_GROUP_LEFT_BTN) && inputGroupBtnLeftFacet != null) {
            writer.startElement("span", component);
            writer.writeAttribute("class", "input-group-btn", null);
            inputGroupBtnLeftFacet.encodeAll(context);
            writer.endElement("span");
        }
        super.encodeEnd(context, component);
        this.postEncodeInput(context, component);
        if (htmlComponent.getSupportedFacets().contains(InputComponentFacet.BOOTSTRAP_INPUT_GROUP_LEFT_ADDON) && inputGroupAddonRightFacet != null) {
            writer.startElement("span", component);
            writer.writeAttribute("class", "input-group-addon", null);
            inputGroupAddonRightFacet.encodeAll(context);
            writer.endElement("span");
        }
        if (htmlComponent.getSupportedFacets().contains(InputComponentFacet.BOOTSTRAP_INPUT_GROUP_LEFT_BTN) && inputGroupBtnRightFacet != null) {
            writer.startElement("span", component);
            writer.writeAttribute("class", "input-group-btn", null);
            inputGroupBtnRightFacet.encodeAll(context);
            writer.endElement("span");
        }
    }

    protected void postEncodeInput(final FacesContext context, final UIComponent component) throws IOException {

    }

    /**
     * @return true if normal readonly render option should be used. False is custom readonly option is created by renderer implementation.
     */
    protected boolean encodeReadonly() {
        return true;
    }

    protected void encodeReadonly(T htmlComponent, ResponseWriter writer) throws IOException {
        if (encodeReadonly()) {
            // Render readonly span if components readonly attribute is set
            new ReadonlyPartRenderer().renderReadonly(htmlComponent, writer);
        }
    }

    protected void encodeEndInnerWrapper(UIComponent component, ResponseWriter writer) throws IOException {
        // Close inner component wrapper div
        new InnerComponentWrapperPartRenderer().renderInnerWrapperEnd(component, writer);
    }

    protected void encodeBeginInnerWrapper(UIComponent component, ResponseWriter writer) throws IOException {
        // Open inner component wrapper div
        new InnerComponentWrapperPartRenderer().renderInnerWrapperBegin(component, writer);
    }

    protected void encodeInnerEnd(final UIComponent component, final ResponseWriter writer) throws IOException {
        // override me
    }

    protected void encodeEnd(final UIComponent component, final ResponseWriter writer) throws IOException {
        // override me
    }

    /**
     * Helper to call super end from sub classes without calling encodeEnd of this class. This is not nice but is works at this time.
     * TODO fix it.
     */
    protected void encodeSuperEnd(final FacesContext context, final UIComponent component) throws IOException {
        super.encodeEnd(context, component);
    }

    /**
     * Method copied from super class to add html features.
     */
    @Override
    protected void getEndTextToRender(final FacesContext context,
                                      final UIComponent component,
                                      final String currentValue) throws IOException {
        final ResponseWriter writer = context.getResponseWriter();

        if (component instanceof UIInput) {
            writer.startElement("input", component);

            writer.writeAttribute("name", (component.getClientId(context)), "clientId");

            if (currentValue != null) {
                writer.writeAttribute("value", currentValue, "value");
            }

            // default
            this.renderBooleanValue(component, writer, "disabled");
            this.renderBooleanValue(component, writer, "ismap");
            this.renderBooleanValue(component, writer, "readonly");

            // html 5
            this.renderStringValue(component, writer, "autocomplete", "off");
            this.renderStringValue(component, writer, "placeholder");
            this.renderBooleanValue(component, writer, "autoFocus");
            this.renderBooleanValue(component, writer, "pattern");
            this.renderStringValue(component, writer, "min");
            this.renderStringValue(component, writer, "max");

            // html
            this.renderStringValue(component, writer, "alt");
            this.renderStringValue(component, writer, "dir");
            this.renderStringValue(component, writer, "lang");
            this.renderStringValue(component, writer, "maxlength");
            this.renderStringValue(component, writer, "role");
            this.renderStringValue(component, writer, "size");
            this.renderStringValue(component, writer, "style");
            this.renderStringValue(component, writer, "tabindex");
            this.renderStringValue(component, writer, "title");

            // events
            this.renderEventValue(component, writer, "onblur", "blur");
            this.renderEventValue(component, writer, "onclick", "click");
            this.renderEventValue(component, writer, "ondblclick", "dblclick");
            this.renderEventValue(component, writer, "onfocus", "focus");
            this.renderEventValue(component, writer, "onkeydown", "keydown");
            this.renderEventValue(component, writer, "onkeypress", "keypress");
            this.renderEventValue(component, writer, "onkeyup", "keyup");
            this.renderEventValue(component, writer, "onmousedown", "mousedown");
            this.renderEventValue(component, writer, "onmousemove", "mousemove");
            this.renderEventValue(component, writer, "onmouseout", "mouseout");
            this.renderEventValue(component, writer, "onmouseover", "mouseover");
            this.renderEventValue(component, writer, "onmouseup", "mouseup");
            this.renderEventValue(component, writer, "onselect", "select");
            this.renderEventValue(component, writer, "onchange", "change");

            this.renderInputStyleClass((HtmlInputComponent) component, writer);

            this.renderStringValue(component, writer, "type");

            this.renderAdditionalInputAttributes(context, component, writer);

            writer.endElement("input");
        }
    }

    /**
     * When using {@link AbstractTextRenderer} input component will be wrapped. Component style class will be set to
     * component wrapper. This method renders inner input component bootstrap classes and validation markers.
     */
    protected void renderInputStyleClass(final HtmlInputComponent component,
                                         final ResponseWriter writer) throws IOException {
        final String validationMarkerClass = !component.isValid() ? Constants.INVALID_STYLE_CLASS : null;
        final String styleClass = StringUtils.concatWithSpace(
                Constants.INPUT_COMPONENT_MARKER,
                Constants.BOOTSTRAP_FORM_CONTROL,
                validationMarkerClass);
        writer.writeAttribute("class", styleClass, "styleClass");
    }

    protected void renderAdditionalInputAttributes(final FacesContext context,
                                                   final UIComponent component,
                                                   final ResponseWriter writer) throws IOException {
    }

    @Override
    public void encodeChildren(final FacesContext context,
                               final UIComponent component) throws IOException {
        if (!component.isRendered()) {
            return;
        }

        if (component.getChildCount() > 0) {
            for (UIComponent child : component.getChildren()) {
                // ignore tooltips (will be rendered before)
                if (!(child instanceof HtmlTooltip) && !(child instanceof HtmlAutoComplete)) {
                    encodeRecursive(context, child);
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy