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
>> >
>>
>
>