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

Reply via email to