Hi Thiago, I was trying to use html5 client validation. Tapestry docs says that you can enable it in AppModule, adding:
configuration.add(SymbolConstants.ENABLE_HTML5_SUPPORT, "true"); And this works fine, but then, at least in Chromium and Firefox, you need a <input type="submit"/> in the form to trigger it. You can't use a LinkSubmit (which generates an "<a>" tag), since the LinkSubmit calls only javascript validation, and not the Html5 form validation. But the <input type="submit"/> is severely limited when it comes to customization, as it cannot contain internal element, so you cannot use bootstrap glyphs to style it, for example. You could hide the <input type="submit"/> and workaround it's restrictions using some js, but this is too ugly to be a "real" solution. So I need to place a <button type="submit"> inside the form. The button can be styled at your wish using bootstrap, and, as side effect, you can place more than one button inside the form, so I can have a "save" and "save and new", which is one of my requirements. Thanks for your job, Luca > Sent: Thursday, September 12, 2019 at 3:05 AM > From: "Thiago H. de Paula Figueiredo" <thiag...@gmail.com> > To: "Tapestry users" <users@tapestry.apache.org> > Subject: Re: HTML5 Button Component for tapetry 5.4.x > > On Wed, Sep 11, 2019 at 8:45 AM Luca Arzeni <l.arz...@iname.com> wrote: > > > Hi there, > > > > Hello! > > > > I googled a little around, but I was not able to find a tapestry component > > that generates a button. > > > > What's exactly the use case you're thinking here? I cannot remember the > last time I used one and I'm not exactly an HTML expert nor a designer, so > I'm curious what you used it for. :) > > For submitting forms, if you have a single button, you don't even need to > use the Submit component. An ordinary <input type="submit"> suffices for > the From component. Submit's main reason to exist is when you have more > than one button, so it triggers an event so you know which one was used. > > Welcome to the Tapestry users mailing list! > > > > > > Here you can find a first attempt to create such component. > > It was shameless copied from the Submit component already present in > > tapestry. > > > > I would be happy if someone more expert than me could revise it and add to > > the core components. > > > > Regards, > > larzeni > > > > package org.apache.tapestry5.corelib.components; > > > > import org.apache.tapestry5.BindingConstants; > > import org.apache.tapestry5.ClientElement; > > import org.apache.tapestry5.ComponentAction; > > import org.apache.tapestry5.ComponentResources; > > import org.apache.tapestry5.EventConstants; > > import org.apache.tapestry5.MarkupWriter; > > import org.apache.tapestry5.TrackableComponentEventCallback; > > import org.apache.tapestry5.annotations.Environmental; > > import org.apache.tapestry5.annotations.Events; > > import org.apache.tapestry5.annotations.Import; > > import org.apache.tapestry5.annotations.Parameter; > > import org.apache.tapestry5.annotations.SupportsInformalParameters; > > import org.apache.tapestry5.corelib.SubmitMode; > > import org.apache.tapestry5.corelib.components.Form; > > import org.apache.tapestry5.corelib.components.Loop; > > import org.apache.tapestry5.internal.util.Holder; > > import org.apache.tapestry5.ioc.annotations.Inject; > > import org.apache.tapestry5.ioc.internal.util.InternalUtils; > > import org.apache.tapestry5.json.JSONArray; > > import org.apache.tapestry5.services.FormSupport; > > import org.apache.tapestry5.services.Heartbeat; > > import org.apache.tapestry5.services.Request; > > import org.apache.tapestry5.services.javascript.JavaScriptSupport; > > > > /** > > * Corresponds to <input type="submit"> or <input > > type="image">, a client-side element that can force the > > * enclosing form to submit. The submit responsible for the form > > submission will post a notification that allows the > > * application to know that it was the responsible entity. The > > notification is named > > * {@linkplain EventConstants#SELECTED selected}, by default, and has no > > context. > > * > > * @tapestrydoc > > */ > > @SupportsInformalParameters > > @Events(EventConstants.SELECTED + " by default, may be overridden") > > @Import(module="t5/core/forms") > > public class Html5Button implements ClientElement { > > > > /** > > * If true (the default), then any notification sent by the > > component will be deferred until the end of the form > > * submission (this is usually desirable). In general, this can be > > left as the default except when the Submit > > * component is rendering inside a {@link Loop}, in which case > > defer should be bound to false (otherwise, the > > * event context will always be the final value of the Loop). > > */ > > @Parameter > > private boolean defer = true; > > > > /** > > * The name of the event that will be triggered if this component > > is the cause of the form submission. The default > > * is {@link EventConstants#SELECTED}. > > */ > > @Parameter(allowNull = false, defaultPrefix = > > BindingConstants.LITERAL) > > private String event = EventConstants.SELECTED; > > > > /** > > * If true, then the field will render out with a disabled > > attribute > > * (to turn off client-side behavior). When the form is submitted, > > the > > * bound value is evaluated again and, if true, the field's value > > is > > * ignored (not even validated) and the component's events are not > > fired. > > */ > > @Parameter("false") > > private boolean disabled; > > > > @Parameter(defaultPrefix = BindingConstants.LITERAL) > > private String type; > > > > /** > > * The list of values that will be made available to event handler > > method of this component when the form is > > * submitted. > > * > > * @since 5.1.0.0 > > */ > > @Parameter > > private Object[] context; > > > > /** > > * Defines the mode, or client-side behavior, for the submit. The > > default is {@link SubmitMode#NORMAL}; clicking the > > * button submits the form with validation. {@link > > SubmitMode#CANCEL} indicates the form should be submitted as a cancel, > > * with no client-side validation. {@link > > SubmitMode#UNCONDITIONAL} bypasses client-side validation, but does not > > indicate > > * that the form was cancelled. > > * > > * @see EventConstants#CANCELED > > * @since 5.2.0 > > */ > > @Parameter(allowNull = false, defaultPrefix = > > BindingConstants.LITERAL) > > private SubmitMode mode = SubmitMode.NORMAL; > > > > /** > > * CSS class for the element. > > * > > * @since 5.4 > > */ > > @Parameter(name = "class", defaultPrefix = > > BindingConstants.LITERAL, value = > > "message:private-core-components.submit.class") > > private String cssClass; > > > > @Environmental > > private FormSupport formSupport; > > > > @Environmental > > private Heartbeat heartbeat; > > > > @Inject > > private ComponentResources resources; > > > > @Inject > > private Request request; > > > > @Inject > > private JavaScriptSupport javascriptSupport; > > > > @SuppressWarnings("rawtypes") > > @Environmental > > private TrackableComponentEventCallback eventCallback; > > > > private String clientId; > > > > @SuppressWarnings("serial") > > private static class ProcessSubmission implements > > ComponentAction<Html5Button> > > { > > private final String clientId, elementName; > > > > public ProcessSubmission(String clientId, String > > elementName) > > { > > this.clientId = clientId; > > this.elementName = elementName; > > } > > > > public void execute(Html5Button component) > > { > > component.processSubmission(clientId, elementName); > > } > > } > > > > public Html5Button() > > { > > } > > > > Html5Button(Request request) > > { > > this.request = request; > > } > > > > void beginRender(MarkupWriter writer) > > { > > clientId = javascriptSupport.allocateClientId(resources); > > > > String l_name = > > formSupport.allocateControlName(resources.getId()); > > > > // Save the element, to see if an id is later requested. > > > > writer.element("button", > > > > "type", type, > > > > "name", l_name, > > > > "data-submit-mode", > > mode.name().toLowerCase(), > > > > "class", cssClass, > > > > "id", clientId); > > > > if (disabled) > > { > > writer.attributes("disabled", "disabled"); > > } > > > > formSupport.store(this, new ProcessSubmission(clientId, > > l_name)); > > > > resources.renderInformalParameters(writer); > > } > > > > void afterRender(MarkupWriter writer) > > { > > writer.end(); > > } > > > > void processSubmission(String clientId, String elementName) > > { > > if (disabled || !selected(clientId, elementName)) > > return; > > > > // TAP5-1658: copy the context of the current Submit > > instance so we trigger the event with > > // the correct context later > > final Holder<Object[]> currentContextHolder = > > Holder.create(); > > if (context != null) > > { > > Object[] currentContext = new > > Object[context.length]; > > System.arraycopy(context, 0, currentContext, 0, > > context.length); > > currentContextHolder.put(currentContext); > > } > > > > Runnable sendNotification = new Runnable() > > { > > public void run() > > { > > // TAP5-1024: allow for navigation result > > from the event callback > > resources.triggerEvent(event, > > currentContextHolder.get(), eventCallback); > > } > > }; > > > > // When not deferred, don't wait, fire the event now > > (actually, at the end of the current > > // heartbeat). This is most likely because the Submit is > > inside a Loop and some contextual > > // information will change if we defer. > > > > if (defer) > > formSupport.defer(sendNotification); > > else > > heartbeat.defer(sendNotification); > > } > > > > private boolean selected(String clientId, String elementName) > > { > > // Case #1: via JavaScript, the client id is passed up. > > > > String raw = > > request.getParameter(Form.SUBMITTING_ELEMENT_ID); > > > > if (InternalUtils.isNonBlank(raw) && > > new > > JSONArray(raw).getString(0).equals(clientId)) > > { > > return true; > > } > > > > String name = elementName; > > > > String value = request.getParameter(name); > > > > return value != null; > > } > > > > /** > > * Returns the component's client id. This must be called after > > the component has rendered. > > * > > * @return client id for the component > > */ > > public String getClientId() > > { > > return clientId; > > } > > } > > > > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org > > For additional commands, e-mail: users-h...@tapestry.apache.org > > > > > > -- > Thiago > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org