/******************************************************************************* * Copyright (c) 2015 Development Gateway, Inc and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the MIT License (MIT) * which accompanies this distribution, and is available at * https://opensource.org/licenses/MIT * * Contributors: * Development Gateway - initial API and implementation *******************************************************************************/ package org.devgateway.toolkit.forms.wicket.components.form; import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig; import de.agilecoders.wicket.core.markup.html.bootstrap.form.FormGroup; import de.agilecoders.wicket.core.markup.html.bootstrap.form.InputBehavior; import de.agilecoders.wicket.core.markup.html.bootstrap.form.InputBehavior.Size; import de.agilecoders.wicket.core.util.Attributes; import org.apache.log4j.Logger; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.event.IEvent; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckGroup; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.RadioGroup; import org.apache.wicket.model.IModel; import org.apache.wicket.model.ResourceModel; import org.devgateway.toolkit.forms.models.SubComponentWrapModel; import org.devgateway.toolkit.forms.models.ViewModeConverterModel; import org.devgateway.toolkit.forms.wicket.components.ComponentUtil; import org.devgateway.toolkit.forms.wicket.components.FieldPanel; import org.devgateway.toolkit.forms.wicket.components.TooltipLabel; /** * @author mpostelnicu * */ public abstract class GenericBootstrapFormComponent<TYPE, FIELD extends FormComponent<TYPE>> extends FieldPanel<TYPE> { private static final long serialVersionUID = -7051128382707812456L; protected static Logger logger = Logger.getLogger(GenericBootstrapFormComponent.class); protected FormGroup border; protected FIELD field; protected Label viewModeField; protected InputBehavior sizeBehavior; private TooltipConfig.OpenTrigger configWithTrigger = TooltipConfig.OpenTrigger.hover; protected TooltipLabel tooltipLabel; protected IModel<String> labelModel; @Override public void onEvent(final IEvent<?> event) { ComponentUtil.enableDisableEvent(this, event); } @SuppressWarnings("unchecked") protected IModel<TYPE> initFieldModel() { if (getDefaultModel() == null) { return new SubComponentWrapModel<TYPE>(this); } return (IModel<TYPE>) getDefaultModel(); } /** * use this behavior for choices/groups that are not one component in the * html but many. */ protected void getAjaxFormChoiceComponentUpdatingBehavior() { updatingBehaviorComponent().add(new AjaxFormChoiceComponentUpdatingBehavior() { private static final long serialVersionUID = 1L; @Override protected void onUpdate(final AjaxRequestTarget target) { GenericBootstrapFormComponent.this.onUpdate(target); } }); } /** * This is the component that has to be updated with the * {@link #getAjaxFormChoiceComponentUpdatingBehavior()} or with * {@link #getAjaxFormComponentUpdatingBehavior()}. It usuall is the field, * but the field may be a wrapper, in which case you should override this * and provide the wrapped field. * * @return */ protected FormComponent<TYPE> updatingBehaviorComponent() { return field; } protected void getAjaxFormComponentUpdatingBehavior() { updatingBehaviorComponent().add(new AjaxFormComponentUpdatingBehavior(getUpdateEvent()) { private static final long serialVersionUID = -2696538086634114609L; @Override protected void onUpdate(final AjaxRequestTarget target) { target.add(border); GenericBootstrapFormComponent.this.onUpdate(target); } @Override protected void onError(final AjaxRequestTarget target, final RuntimeException e) { target.add(border); } }); } public String getUpdateEvent() { return "blur"; } public GenericBootstrapFormComponent<TYPE, FIELD> type(final Class<?> clazz) { field.setType(clazz); return this; } public GenericBootstrapFormComponent<TYPE, FIELD> size(final Size size) { sizeBehavior.size(size); return this; } public GenericBootstrapFormComponent(final String id) { this(id, null); } public String getLabelKey() { return this.getId() + ".label"; } public GenericBootstrapFormComponent(final String id, final IModel<TYPE> model) { this(id, new ResourceModel(id + ".label"), model); } public GenericBootstrapFormComponent(final String id, final IModel<String> labelModel, final IModel<TYPE> model) { super(id, model); this.labelModel = labelModel; setOutputMarkupId(true); setOutputMarkupPlaceholderTag(true); border = new FormGroup("enclosing-field-group"); border.setOutputMarkupId(true); add(border); field = inputField("field", model); field.setVisibilityAllowed(!ComponentUtil.isViewMode()); field.setOutputMarkupId(true); sizeBehavior = new InputBehavior(InputBehavior.Size.Medium); field.add(sizeBehavior); border.add(field); field.setLabel(labelModel); tooltipLabel = new TooltipLabel("tooltipLabel", id); border.add(tooltipLabel); } @Override protected void onComponentTag(final ComponentTag tag) { super.onComponentTag(tag); // add a new class for required fields if (field.isRequired()) { Attributes.addClass(tag, "required"); } } public GenericBootstrapFormComponent<TYPE, FIELD> hideLabel() { field.setLabel(null); return this; } protected abstract FIELD inputField(String id, IModel<TYPE> model); public GenericBootstrapFormComponent<TYPE, FIELD> required() { field.setRequired(true); return this; } protected void onUpdate(final AjaxRequestTarget target) { } public FIELD getField() { return field; } /* * (non-Javadoc) * * @see org.apache.wicket.Component#onConfigure() */ @Override protected void onInitialize() { super.onInitialize(); if ((field instanceof RadioGroup) || (field instanceof CheckGroup)) { getAjaxFormChoiceComponentUpdatingBehavior(); } else { getAjaxFormComponentUpdatingBehavior(); } viewModeField = new Label("viewModeField", new ViewModeConverterModel<TYPE>(getModel())); viewModeField.setEscapeModelStrings(false); viewModeField.setVisibilityAllowed(ComponentUtil.isViewMode()); border.add(viewModeField); tooltipLabel.setConfigWithTrigger(configWithTrigger); } /** * @return the border */ public FormGroup getBorder() { return border; } public TooltipConfig.OpenTrigger getConfigWithTrigger() { return configWithTrigger; } public void setConfigWithTrigger(final TooltipConfig.OpenTrigger configWithTrigger) { this.configWithTrigger = configWithTrigger; } }