We usually just style the various Tapestry link components to get buttons
with the desired behavior.

-- 
Chris

On Wed, Sep 11, 2019 at 1:45 PM Luca Arzeni <l.arz...@iname.com> wrote:

> Hi there,
> I googled a little around, but I was not able to find a tapestry component
> that generates a button.
>
> 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
>
>

Reply via email to