You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wicket.apache.org by Martin Makundi <ma...@koodaripalvelut.com> on 2015/01/10 04:40:42 UTC

Ideas for wicket 7.0

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

Re: Ideas for wicket 7.0

Posted by Martin Makundi <ma...@koodaripalvelut.com>.
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 <martin.makundi@koodaripalvelut.com
>:

>
> 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" <
>> martin.makundi@koodaripalvelut.com> 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
>> >
>>
>
>

Re: Ideas for wicket 7.0

Posted by Martin Makundi <ma...@koodaripalvelut.com>.
> 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" <
> martin.makundi@koodaripalvelut.com> 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
> >
>

Re: Ideas for wicket 7.0

Posted by Martin Grigorov <mg...@apache.org>.
Wicket 7.0.0 is about to be released so it's a bit late for ideas.
But what you describe sounds like what  wicketstuff-stateless project
already provides.
On Jan 10, 2015 4:43 AM, "Martin Makundi" <
martin.makundi@koodaripalvelut.com> 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
>