Maybe more independent of the component hierarchy is
the ParameterizedFakeAjaxEventBehavior:

/**
 *
 * Behavior which is added to parent react on {@link
ParameterizedFakeEventButton} trigger event.
 *
 */
public abstract class ParameterizedFakeAjaxEventBehavior extends
AjaxEventBehavior {
  /**
   * Copyright (c) Koodaripalvelut.com Finland 2008
   */
  public static abstract class FakeEventHandler implements Serializable {

    private Component targetComponent;

    /**
     * @param target
     */
    public abstract void onFakeEvent(AjaxRequestTarget target);

    /**
     * @return The Confirm Script Parameter
     */
    public String getConfirmScriptParameter() {
      return null;
    }

    /**
     * @return the targetComponent
     */
    public Component getTargetComponent() {
      return targetComponent;
    }

    /**
     * @param targetComponent
     *          the targetComponent to set
     */
    void setTargetComponent(Component targetComponent) {
      this.targetComponent = targetComponent;
    }
  }

  private static final String AJAX_LINK_ID = "aLMId";

  private final Map<String,
ParameterizedFakeAjaxEventBehavior.FakeEventHandler> handlers = new
HashMap<String, ParameterizedFakeAjaxEventBehavior.FakeEventHandler>();

  /**  */
  static final String PFEB_PREFIX = "pfeb_";
  /**  */
  static final String FAKE_EVENT_NAME = "fake";
  /**  */
  public static final boolean MARKUP_ID_IDENTIFIES_EVENT = true;

  /**
   */
  public ParameterizedFakeAjaxEventBehavior() {
    super(ParameterizedFakeAjaxEventBehavior.FAKE_EVENT_NAME);
  }

  /**
   * @see
org.apache.wicket.ajax.AjaxEventBehavior#onEvent(org.apache.wicket.ajax.AjaxRequestTarget)
   */
  @Override
  protected void onEvent(AjaxRequestTarget target) {
    String ajaxLinkMarkupId =
RequestCycle.get().getRequest().getParameter(AJAX_LINK_ID);
    ParameterizedFakeAjaxEventBehavior.FakeEventHandler handler =
handlers.get(ajaxLinkMarkupId);
    if (handler != null && handler.getTargetComponent().isVisible() &&
handler.getTargetComponent().isEnabled()) {
      handler.onFakeEvent(target);
    }
  }

  /**
   * @param markupId
   * @param handler
   */
  public void addEventHandler(final String markupId,
ParameterizedFakeAjaxEventBehavior.FakeEventHandler handler) {
    if (Utils.isEmpty(markupId)) {
      throw new NullPointerException("Markup id is required: " + handler);
    }

    final ParameterizedFakeAjaxEventBehavior.FakeEventHandler
existingFakeEventHandler = handlers.put(markupId, handler);

    if (existingFakeEventHandler != null) {
      throw new IllegalStateException("There already exists a " +
ParameterizedFakeAjaxEventBehavior.FakeEventHandler.class.getSimpleName() +
" with id: " + markupId);
    }
  }

  /**
   * @return Script for displaying "confirm alert". JS variable "param" is
available for deciding
   * which confirmation, if any, should be displayed.
   */
  protected abstract String getConfirmScript();

  /**
   * @see
org.apache.wicket.behavior.AbstractAjaxBehavior#getCallbackUrl(boolean)
   */
  @Override
  public CharSequence getCallbackUrl(boolean onlyTargetActivePage) {
    String callbackUrl = super.getCallbackUrl(onlyTargetActivePage) +
"&"+AJAX_LINK_ID+"='+markupId+'";
    return callbackUrl;
  }

  /**
   * @see
org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
   */
  @Override
  public void renderHead(IHeaderResponse response) {
    response.renderJavascriptReference(JavaScriptConstants.JS_JQUERY);
    {
      String functionName = ParameterizedFakeAjaxEventBehavior.PFEB_PREFIX
+ getComponent().getMarkupId();
      StringBuilder scriptBuilder = new StringBuilder();
      scriptBuilder.append("function ");
      scriptBuilder.append(functionName);
      scriptBuilder.append("(target, param) {\n");
      scriptBuilder.append("var markupId=target.id;\n");
      scriptBuilder.append(Utils.noNull(getConfirmScript()));
      scriptBuilder.append("\n");
      scriptBuilder.append(getCallbackScript());
      scriptBuilder.append("}\n");
      response.renderJavascript(scriptBuilder.toString(), functionName);
    }
    super.renderHead(response);
  }

  /**
   * @param parent
   * @param confirmScriptId
   * @param busySignal
   * @param iAjaxCallDecorator
   * @return String
   */
  public static String getOnClickScript(final Component parent, final
String confirmScriptId, final boolean busySignal,
      IAjaxCallDecorator iAjaxCallDecorator) {
    CharSequence onClickScript = PFEB_PREFIX + parent.getMarkupId() +
"(this,'"
        + JavascriptUtils.escapeQuotes(Utils.noNull(confirmScriptId)) +
"');return " + busySignal + ";";
    if (iAjaxCallDecorator != null) {
      onClickScript = iAjaxCallDecorator.decorateScript(onClickScript);
    }

    return onClickScript.toString();
  }

  /**
   * @param parent
   * @param markupId
   * @param handler
   */
  public static void attach(Component parent, String markupId,
ParameterizedFakeAjaxEventBehavior.FakeEventHandler handler) {
    for (final IBehavior behavior : parent.getBehaviors()) {
      if (behavior instanceof ParameterizedFakeAjaxEventBehavior) { // TODO
                                                                    // event
                                                                    //
handler
                                                                    // per
page? TODO Problem with refresh/repaint/appending handlers partially? Or
not?
        ((ParameterizedFakeAjaxEventBehavior)
behavior).addEventHandler(markupId, handler);
      }
    }
  }
}



With usage example:

public class ParameterizedFakeEventButton extends Button {
  private final Component parent;
  private final String parameter;
  private final boolean busySignal;

  /**
   * @param id
   * @param parent
   * @param handler
   * @param busySignal
   */
  public ParameterizedFakeEventButton(String id, Component parent,
ParameterizedFakeAjaxEventBehavior.FakeEventHandler handler, boolean
busySignal) {
    this(id, null, parent, handler, busySignal);
  }

  /**
   * @param id
   * @param model
   * @param parent
   * @param handler
   * @param busySignal
   */
  @SuppressWarnings("synthetic-access")
  public ParameterizedFakeEventButton(String id, Model<String> model,
Component parent, ParameterizedFakeAjaxEventBehavior.FakeEventHandler
handler, boolean busySignal) {
    super(id, model);
    this.busySignal = busySignal;

setOutputMarkupId(ParameterizedFakeAjaxEventBehavior.MARKUP_ID_IDENTIFIES_EVENT);
    setDefaultFormProcessing(false);
    ParameterizedFakeAjaxEventBehavior.attach(parent, getMarkupId(),
handler);
    this.parameter = handler.getConfirmScriptParameter();
    this.parent = parent;
    handler.setTargetComponent(this);
  }

  /**
   * @see org.apache.wicket.markup.html.form.Button#getOnClickScript()
   */
  @Override
  protected String getOnClickScript() {
    return ParameterizedFakeAjaxEventBehavior.getOnClickScript(parent,
parameter, busySignal, getDecorator());
  }

  /**
   * @see
org.apache.wicket.markup.html.form.Button#onComponentTag(org.apache.wicket.markup.ComponentTag)
   */
  @Override
  protected void onComponentTag(ComponentTag tag) {
    super.onComponentTag(tag);
    if (!busySignal) {
      tag.put(WebPageConstants.NOBUSY, "true");
    }
  }

  /**
   * Get decorator. Only {@link
IAjaxCallDecorator#decorateScript(CharSequence)}
   * is used here!
   *
   * @return {@link IAjaxCallDecorator}
   */
  protected IAjaxCallDecorator getDecorator() {
    return null;
  }
}


2015-01-10 7:47 GMT+02:00 Martin Makundi <[email protected]
>:

>
> Wicket 7.0.0 is about to be released so it's a bit late for ideas.
>>
>
> =) Is there a board for ideas for next one?
>
>
>> But what you describe sounds like what  wicketstuff-stateless project
>> already provides.
>>
>
> I looked at
> https://github.com/mafulafunk/wicketstuff-core/tree/master/jdk-1.6-parent/stateless-parent/stateless/src/main/java/org/wicketstuff/stateless
>
> It is not quite the same what I am discussing. I mean that if you call
> page.removeAll() and execute the event, it would still work.
>
> We have implemented things like:
>
>
> /**
>  *
>  * Listener that collects fake events.
>  *
>  */
> public class FakeEventListener implements IListener {
>
>   private static final MetaDataKey<FakeEventListener> DATA_KEY = new
> MetaDataKey<FakeEventListener>() {
>     private static final long serialVersionUID = 1L;
>   };
>
>   private ArrayList<String> scripts = new ArrayList<String>();
>
>   /**
>    * Constructor
>    *
>    */
>   private FakeEventListener() {
>   }
>
>   /**
>    * @see
> org.apache.wicket.ajax.AjaxRequestTarget.IListener#onBeforeRespond(java.util.Map,
>    *      org.apache.wicket.ajax.AjaxRequestTarget)
>    */
>   @Override
>   public void onBeforeRespond(Map<String, Component> map,
> AjaxRequestTarget target) {
>     // do nothing
>   }
>
>   /**
>    * @see
> org.apache.wicket.ajax.AjaxRequestTarget.IListener#onAfterRespond(java.util.Map,
>    *      org.apache.wicket.ajax.AjaxRequestTarget.IJavascriptResponse)
>    */
>   @Override
>   public void onAfterRespond(Map<String, Component> map,
> IJavascriptResponse response) {
>     StringBuilder builder = new StringBuilder();
>     builder.append("var fakeev_inin = function(event) {");
>     builder.append("if( typeof Tustor == 'undefined' || typeof
> Tustor.Events == 'undefined') { setTimeout(fakeev_inin, 10); } else {");
>     for (String parentMarkupId : scripts) {
>       builder.append("Tustor.Events.addFakeEventsClassName('.FACB");
>       builder.append(index(parentMarkupId));
>       builder.append("', '");
>       builder.append(parentMarkupId);
>       builder.append("');");
>     }
>     builder.append("}};");
>     builder.append("$(document).ready(function(){fakeev_inin();});");
>     response.addJavascript(builder.toString());
>     RequestCycle.get().setMetaData(DATA_KEY, null);
>   }
>
>   /**
>    * Adds script;
>    *
>    * @param parentMarkupId
>    *
>    */
>   public void addScript(String parentMarkupId) {
>     if(!scripts.contains(parentMarkupId)) {
>       scripts.add(parentMarkupId);
>     }
>   }
>
>   /**
>    *
>    * @param parentMarkupId
>    * @return index
>    */
>   public int index(String parentMarkupId) {
>     if(!scripts.contains(parentMarkupId)) {
>       scripts.add(parentMarkupId);
>     }
>     return scripts.indexOf(parentMarkupId);
>   }
>
>   /**
>    * Gets and creates if does not exists.
>    *
>    * @return DatePickerListener
>    */
>   public static FakeEventListener getCreate() {
>     FakeEventListener listener = RequestCycle.get().getMetaData(DATA_KEY);
>     if (listener == null) {
>       listener = new FakeEventListener();
>       RequestCycle.get().setMetaData(DATA_KEY, listener);
>     }
>     return listener;
>   }
>
>   /**
>    * Gets without create.
>    *
>    * @return {@link FakeEventListener}
>    */
>   public static FakeEventListener get() {
>     return RequestCycle.get().getMetaData(DATA_KEY);
>   }
>
> }
>
>
>
>
>
>
> /**
>  *
>  */
> package com.tustor.tuntinetti.view.reusables.components;
>
> import org.apache.wicket.AttributeModifier;
> import org.apache.wicket.Component;
> import org.apache.wicket.ajax.AjaxRequestTarget;
> import org.apache.wicket.ajax.IAjaxCallDecorator;
> import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
> import org.apache.wicket.behavior.AttributeAppender;
> import org.apache.wicket.markup.ComponentTag;
> import org.apache.wicket.markup.html.IHeaderContributor;
> import org.apache.wicket.markup.html.IHeaderResponse;
> import org.apache.wicket.model.AbstractReadOnlyModel;
> import org.apache.wicket.model.Model;
> import org.apache.wicket.util.string.JavascriptUtils;
>
> import com.tustor.common.wicket.constants.JavaScriptConstants;
> import
> com.tustor.tuntinetti.view.reusables.components.FakeEventButton.FakeAjaxEventBehavior;
>
> /**
>  * Fake event button which trigger fake event to parent. Parent need to
> have
>  * {@link FakeAjaxEventBehavior} attached.
>  *
>  *
>  */
> public abstract class FakeAjaxFormComponentUpdatingBehavior extends
> AjaxFormComponentUpdatingBehavior implements IHeaderContributor {
>   private static final String FAKE_EVENT_NAME = "fake";
>   private String parentMarkupId;
>   private final boolean busySignal;
>
>   private boolean isCollectString = false;
>
>   /**
>    * Construct.
>    *
>    * @param parentMarkupId
>    * @param busySignal
>    * @param isCollectString
>
>    */
>   public FakeAjaxFormComponentUpdatingBehavior(String parentMarkupId,
> boolean busySignal, boolean isCollectString) {
>     super("fake");
>
>     this.busySignal = busySignal;
>     this.parentMarkupId = parentMarkupId;
>     this.isCollectString  = isCollectString;
>   }
>
>   /**
>    * @see
> org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior#onBind()
>    */
>   @Override
>   protected void onBind() {
>     super.onBind();
>     if (AjaxRequestTarget.get() != null) {
>       getComponent().add(new AttributeAppender("class",true, new
> AbstractReadOnlyModel<String>() {
>         /**
>          * @see org.apache.wicket.model.AbstractReadOnlyModel#getObject()
>          */
>         @SuppressWarnings("synthetic-access")
>         @Override
>         public String getObject() {
>           if (FakeEventListener.get() == null) {
>
> AjaxRequestTarget.get().addListener(FakeEventListener.getCreate());
>           }
>           return "FACB"+
> FakeEventListener.get().index(FakeAjaxFormComponentUpdatingBehavior.this.parentMarkupId);
>         }
>       }, " "));
>       getComponent().add(new AttributeModifier("bs",true,
> Model.of(busySignal)));
>     }
>   }
>
>
>   /**
>    *
>    * @param target
>    */
>   public void fireOnEvent(AjaxRequestTarget target) {
>     onEvent(target);
>   }
>
>
>
>
>   /**
>    * @see
> org.apache.wicket.behavior.AbstractAjaxBehavior#onComponentRendered()
>    */
>   @Override
>   protected void onComponentRendered() {
>     super.onComponentRendered();
>     String event = getEvent();
>     Component component = getComponent();
>     if(!isCollectScripts()) {
>       onComponentRendered(event, component);
>     }
>   }
>
>   /**
>    * @see
> org.apache.wicket.ajax.AjaxEventBehavior#onComponentTag(org.apache.wicket.markup.ComponentTag)
>    */
>   @Override
>   protected void onComponentTag(ComponentTag tag) {
>     if(!isCollectScripts()) {
>       super.onComponentTag(tag);
>     }
>   }
>
>   /**
>    * @param event
>    * @param component
>    */
>   protected static void onComponentRendered(String event, Component
> component) {
>     JavascriptUtils.writeOpenTag(component.getResponse());
>     component.getResponse().write("$('#" + component.getMarkupId() +
> "').change(function() { eval($(this).attr('" + event + "')); });");
>     JavascriptUtils.writeCloseTag(component.getResponse());
>   }
>
>   /**
>    * @return Should scripts be collected.
>    */
>   protected final boolean isCollectScripts() {
>     return isCollectString;
>   }
>
>   /**
>    * @see
> org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
>    */
>   @Override
>   public void renderHead(IHeaderResponse response) {
>     super.renderHead(response);
>     response.renderJavascriptReference(JavaScriptConstants.JS_JQUERY);
>     if(isCollectScripts() && AjaxRequestTarget.get() != null) {
>       response.renderJavascriptReference(FakeAjaxCheckBox.JS);
>       if (FakeEventListener.get() == null) {
>         AjaxRequestTarget.get().addListener(FakeEventListener.getCreate());
>       }
>       FakeEventListener.get().addScript(parentMarkupId);
>     }
>   }
>
>   /**
>    *
>    * @param target
>    */
>   protected abstract void onUpdate(AjaxRequestTarget target);
>
>   /**
>    *
>    * @return Click script.
>    */
>   protected String getOnClickScript() {
>     CharSequence onClickScript = "$('#" + parentMarkupId + "').trigger('"
> + FAKE_EVENT_NAME + "', '" + getComponent().getMarkupId() + "'); return "
>         + busySignal + ";";
>     IAjaxCallDecorator decorator = getDecorator();
>     if (decorator != null) {
>       onClickScript = decorator.decorateScript(onClickScript);
>     } else if (AjaxRequestTarget.get() != null) {
>       return null;
>     }
>     return onClickScript.toString();
>   }
>
>
>
>   /**
>    * Get decorator. Only {@link
> IAjaxCallDecorator#decorateScript(CharSequence)}
>    * is used here!
>    *
>    * @return {@link IAjaxCallDecorator}
>    */
>   protected IAjaxCallDecorator getDecorator() {
>     return null;
>   }
>
>   /**
>    * @return the parentMarkupId
>    */
>   public String getParentMarkupId() {
>     return parentMarkupId;
>   }
>
>   /**
>    * @param parentMarkupId the parentMarkupId to set
>    */
>   public void setParentMarkupId(String parentMarkupId) {
>     this.parentMarkupId = parentMarkupId;
>   }
>
>   /**
>    * @return the isCollectString
>    */
>   public boolean isCollectString() {
>     return isCollectString;
>   }
>
>   /**
>    * @param isCollectString the isCollectString to set
>    */
>   public void setCollectString(boolean isCollectString) {
>     this.isCollectString = isCollectString;
>   }
>
>   /**
>    * @return the busySignal
>    */
>   public boolean isBusySignal() {
>     return busySignal;
>   }
>
> }
>
>
>
>
> **
> Martin
>
>
>> On Jan 10, 2015 4:43 AM, "Martin Makundi" <
>> [email protected]> wrote:
>>
>> > Hi!
>> >
>> > I tried to add and idea to
>> > https://cwiki.apache.org/confluence/display/WICKET/Ideas+for+Wicket+7.0
>> >
>> > However I cannot find any edit buttons when Logged in to confluence. The
>> > contribution page says anybody can contribute?
>> >
>> > My idea is related to "Better stateless support
>> > <
>> >
>> https://cwiki.apache.org/confluence/display/WICKET/Ideas+for+Wicket+7.0#IdeasforWicket7.0-Betterstatelesssupport
>> > >
>> > ":
>> >
>> >
>> >    - Wicket seems to have this inherent MVC design flaw that it's View
>> is
>> >    stateful when it would really be sufficient that the Model is
>> stateful
>> > and
>> >    it does not (and neither does controller) need to be serialized.
>> >    - It is possible to tweak to implement stateless View but it's quite
>> a
>> >    hack because most event listeners are attached to the hierarcy
>> instead
>> > of
>> >    page root which would have avoided the need to keep/serialize state
>> of
>> > the
>> >    view. We have prototypes of "FakeAjaxEventBehavior" which is bound to
>> > page
>> >    instead of a component; the component event thus invokes the
>> page-level
>> >    listener (on gui side) and thus in event processing (page level) we
>> > don't
>> >    need the component itself nor its state.
>> >    - Form components, however, are difficult to implement because they
>> >    inherently have state in view, but on the other hand it is rare (and
>> >    impractical) to actually have 'huge' forms; any such large editing
>> areas
>> >    will need to be 'worked around' some another way.
>> >
>> >
>> > **
>> > Martin
>> >
>>
>
>

Reply via email to