NOTE: This is outdated information that applies only to Tapestry 4.

PopupLinkSubmit

This is a solution for submitting a form and at the same time open a popup with an external link. It is a little lousy since it requires alot of copy paste from Tapestry code. I hope this can look better with future Tapestry versions.

Example

<a href="#" jwcid="@PopupLinkSubmit" parameters="ognl:article" listener="listener:acheterArticle" popuppage="PopupPanier" popupparameters="ognl:article.AR_Design">Acheter</a>

PopupLinkSubmit.jwc

<!DOCTYPE component-specification PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN" "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
<component-specification class="actualis.web.tapestry.components.PopupLinkSubmit" allow-body="yes" allow-informal-parameters="yes" deprecated="no">

  <description>
  Creates a hyperlink that submits its enclosing form using JavaScript.
  </description>

  <parameter name="disabled"/>
  <parameter name="selected"/>
  <parameter name="tag"/>
  <parameter name="id" property="idParameter" default-value="id"/>

  <parameter name="listener">
      <description>
          A listener that is notified if this component is triggered.
      </description>
  </parameter>
  <parameter name="action">
      <description>
          A listener that is notified if this component is triggered
          just before the form's listener, after all components
          enclosed by the Form have had a chance to update their properties.
      </description>
  </parameter>
  <parameter name="parameters">
    <description>
    An object, or list of objects, gathered when the link is triggered and
    made available as listener parameters in the request cycle, making
    the parameters available to a deferred listener.
    </description>
  </parameter>

  <parameter name="popuppage" property="popupPage" required="yes"/>

  <parameter name="popupparameters" property="popupParameters" required="no"/>

  <reserved-parameter name="name"/>
  <reserved-parameter name="href"/>

  <inject property="listenerInvoker" object="infrastructure:listenerInvoker"/>
  <inject property="script" type="script" object="PopupLinkSubmit.script"/>

</component-specification>

PopupLinkSubmit.script

<?xml version="1.0"?>
<!DOCTYPE script PUBLIC
        "-//Apache Software Foundation//Tapestry Script Specification 3.0//EN"
        "http://jakarta.apache.org/tapestry/dtd/Script_3_0.dtd">
<script>

<input-symbol key="name" class="java.lang.String" required="yes"/>
<input-symbol key="popupLink" class="java.lang.String" required="yes"/>
<input-symbol key="form" class="org.apache.tapestry.IForm" required="yes"/>

<let key="href">
  javascript:submitPopupLink('${form.name}', '${name}','${popupLink}');
</let>

</script>

package actualis.web.tapestry.components;

import java.util.HashMap;
import java.util.Map;

import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.service.BodyBuilder;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.IScript;
import org.apache.tapestry.PageRenderSupport;
import org.apache.tapestry.TapestryUtils;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.engine.ExternalServiceParameter;
import org.apache.tapestry.engine.IEngineService;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.form.FormConstants;
import org.apache.tapestry.link.DirectLink;

import actualis.web.tapestry.components.form.FormMessages;

/**
 * Implements a component that submits its enclosing form via a JavaScript link. [<a
 * href="../../../../../ComponentReference/LinkSubmit.html">Component Reference</a>]
 *
 * @author Richard Lewis-Shell
 * @version $Id$
 */

public abstract class PopupLinkSubmit extends CustomSubmit {
  /**
   * The name of an {@link org.apache.tapestry.IRequestCycle}attribute in which
   * the current submit link is stored. LinkSubmits do not nest.
   */

  public static final String ATTRIBUTE_NAME = "actualis.web.tapestry.PopupLinkSubmit";

  public static final String ATTRIBUTE_NAME_SCRIPT = "actualis.web.tapestry.PopupLinkSubmitScript";

  /**
   * The name of an {@link org.apache.tapestry.IRequestCycle}attribute in which
   * the link submit component that generates the javascript function is stored.
   * The function is only required once per page (containing a form with a
   * non-disabled LinkSubmit)
   */
  public static final String ATTRIBUTE_FUNCTION_NAME = "actualis.web.tapestry.PopupLinkSubmit_function";

  @InjectObject("engine-service:external")
  public abstract IEngineService getExternalService();

  /**
   * Checks the submit name ({@link FormConstants#SUBMIT_NAME_PARAMETER}) to
   * see if it matches this LinkSubmit's assigned element name.
   */
  protected boolean isClicked(IRequestCycle cycle, String name) {
    String value = cycle.getParameter(FormConstants.SUBMIT_NAME_PARAMETER);

    return name.equals(value);
  }

  public ILink getLink(IRequestCycle cycle) {
    Object[] pageParameters = DirectLink.constructServiceParameters(getPopupParameters());
    ExternalServiceParameter esp = new ExternalServiceParameter(getPopupPage(),
        pageParameters);

    return getExternalService().getLink(false, esp);
  }

  public abstract Object getPopupParameters();

  public abstract String getPopupPage();

  /**
   * @see org.apache.tapestry.form.AbstractFormComponent#renderFormComponent(org.apache.tapestry.IMarkupWriter,
   *      org.apache.tapestry.IRequestCycle)
   */
  @Override
  protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle) {
    boolean disabled = isDisabled();

    if (!disabled) {
      PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle,
          this);

      if (cycle.getAttribute(ATTRIBUTE_NAME_SCRIPT) == null) {
        BodyBuilder builder = new BodyBuilder();

        builder.addln("function {0}(form, elementId, url)", "submitPopupLink");
        builder.begin();
        builder.addln("var form = document.getElementById(form);");
        builder.addln("form.events.submit(elementId);");
        builder.addln("aWindow = window.open(url, '" + PopupDirectLink.POPUP_WINDOWNAME
            + "', " + PopupDirectLink.POPUP_FEATURES + ", false);");
        builder.addln("aWindow.focus();");
        builder.end();

        pageRenderSupport.addBodyScript(builder.toString());
        cycle.setAttribute(ATTRIBUTE_NAME_SCRIPT, this);
      }

      IForm form = getForm();

      String slink = getLink(cycle).getURL(null, true);
      Map symbols = new HashMap();
      symbols.put("form", form);
      symbols.put("name", getName());
      symbols.put("popupLink", slink);

      getScript().execute(cycle, pageRenderSupport, symbols);

      writer.begin("a");
      writer.attribute("href", (String) symbols.get("href"));

    }

    renderBody(writer, cycle);

    if (!disabled)
      writer.end();
  }

  public abstract IScript getScript();

  /**
   * @see org.apache.tapestry.AbstractComponent#prepareForRender(org.apache.tapestry.IRequestCycle)
   */
  protected void prepareForRender(IRequestCycle cycle) {
    IComponent outer = (IComponent) cycle.getAttribute(ATTRIBUTE_NAME);

    if (outer != null)
      throw new ApplicationRuntimeException(FormMessages
          .linkSubmitMayNotNest(this, outer), this, getLocation(), null);

    cycle.setAttribute(ATTRIBUTE_NAME, this);
  }

  /**
   * @see org.apache.tapestry.AbstractComponent#cleanupAfterRender(org.apache.tapestry.IRequestCycle)
   */
  protected void cleanupAfterRender(IRequestCycle cycle) {
    cycle.removeAttribute(ATTRIBUTE_NAME);
  }

  /**
   * Links can not take focus, ever.
   */
  protected boolean getCanTakeFocus() {
    return false;
  }

  /**
   * Returns true; the LinkSubmit's body should render during a rewind, even if
   * the component is itself disabled.
   */
  protected boolean getRenderBodyOnRewind() {
    return true;
  }

}

AbstractSubmit has package visibility! So you need to copy/paste the whole thing.

package actualis.web.tapestry.components;

import java.util.Collection;

import org.apache.tapestry.IActionListener;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.listener.ListenerInvoker;

/**
 * Copy of AbstractSubmit
 */
public abstract class CustomSubmit extends AbstractFormComponent {

  /**
   * Determine if this submit component was clicked.
   *
   * @param cycle
   * @param name
   * @return true if this submit was clicked
   */
  protected abstract boolean isClicked(IRequestCycle cycle, String name);

  /**
   * @see org.apache.tapestry.form.AbstractFormComponent#rewindFormComponent(org.apache.tapestry.IMarkupWriter, org.apache.tapestry.IRequestCycle)
   */
  protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle)
  {
      if (isClicked(cycle, getName()))
          handleClick(cycle, getForm());
  }

  void handleClick(final IRequestCycle cycle, IForm form)
  {
      if (isParameterBound("selected"))
          setSelected(getTag());

      final IActionListener listener = getListener();
      final IActionListener action = getAction();

      if (listener == null && action == null)
          return;

      final ListenerInvoker listenerInvoker = getListenerInvoker();

      Object parameters = getParameters();
      if (parameters != null)
      {
          if (parameters instanceof Collection)
          {
              cycle.setListenerParameters(((Collection) parameters).toArray());
          }
          else
          {
              cycle.setListenerParameters(new Object[]
              { parameters });
          }
      }

      // Invoke 'listener' now, but defer 'action' for later
      if (listener != null)
        listenerInvoker.invokeListener(listener, CustomSubmit.this, cycle);

      if (action != null) {
            Runnable notify = new Runnable()
            {
                public void run()
                {
                    listenerInvoker.invokeListener(action, CustomSubmit.this, cycle);
                }
            };

          form.addDeferredRunnable(notify);
      }
  }

  /** parameter */
  public abstract IActionListener getListener();

  /** parameter */
  public abstract IActionListener getAction();

  /** parameter */
  public abstract Object getTag();

  /** parameter */
  public abstract void setSelected(Object tag);

  /** parameter */
  public abstract boolean getDefer();

  /** parameter */
  public abstract Object getParameters();

  /** Injected */
  public abstract ListenerInvoker getListenerInvoker();
}

PopupLinkSubmit (last edited 2011-01-02 15:48:23 by BobHarner)