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 &lt;input type="submit"&gt; or &lt;input
> type="image"&gt;, 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

Reply via email to