Repository: wicket Updated Branches: refs/heads/WICKET-6183 [created] b87b91b34
Porting of stateless AJAX components to the official project Integrated examples and unit tests Added javadoc added chapter for stateless AJAX Minor fix Update ajax_7.gdoc Started to reuse code from existing AJAX entities Code cleaning Code optimization. Removed stateless entities. Minor fix Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/96ba4888 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/96ba4888 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/96ba4888 Branch: refs/heads/WICKET-6183 Commit: 96ba48889fee11f5a1dd31dd4cb48998ed9cf2c6 Parents: 9ff894d Author: Andrea Del Bene <[email protected]> Authored: Tue Apr 5 18:43:38 2016 +0200 Committer: Andrea Del Bene <[email protected]> Committed: Thu May 26 23:22:11 2016 +0200 ---------------------------------------------------------------------- .../ajax/AbstractDefaultAjaxBehavior.java | 10 +- .../ajax/form/AjaxFormSubmitBehavior.java | 2 +- .../ajax/markup/html/AjaxFallbackLink.java | 7 + .../ajax/markup/html/form/AjaxButton.java | 7 + .../ajax/markup/html/form/AjaxSubmitLink.java | 7 + .../org/apache/wicket/ajax/StatelessPage.html | 40 ++++ .../org/apache/wicket/ajax/StatelessPage.java | 170 ++++++++++++++ .../html/StatelessAjaxFallbackLinkTest.java | 70 ++++++ .../html/form/StatelessAjaxSubmitLinkTest.java | 71 ++++++ .../wicket/examples/ajax/builtin/BasePage.java | 13 ++ .../stateless/AjaxStatelessExample.html | 72 ++++++ .../stateless/AjaxStatelessExample.java | 220 +++++++++++++++++++ .../apache/wicket/examples/stateless/Index.html | 3 + .../apache/wicket/examples/stateless/Index.java | 13 ++ .../src/docs/guide/ajax/ajax_7.gdoc | 43 +++- .../src/docs/guide/ajax/ajax_8.gdoc | 7 + wicket-user-guide/src/docs/guide/toc.yml | 3 +- 17 files changed, 752 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java index 43f031d..3766b98 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java @@ -81,7 +81,15 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior @Override protected void onBind() { - getComponent().setOutputMarkupId(true); + final Component component = getComponent(); + + component.setOutputMarkupId(true); + + if (getStatelessHint(component)) + { + //generate behavior id + component.getBehaviorId(this); + } } /** http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java index c734e9b..69ff89a 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java @@ -168,7 +168,7 @@ public abstract class AjaxFormSubmitBehavior extends AjaxEventBehavior @Override protected void onEvent(final AjaxRequestTarget target) { - getForm().getRootForm().onFormSubmitted(new AjaxFormSubmitter(this, target)); + getForm().getRootForm().onFormSubmitted(new AjaxFormSubmitBehavior.AjaxFormSubmitter(this, target)); } /** http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java index 18488da..6c5f348 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/AjaxFallbackLink.java @@ -16,6 +16,7 @@ */ package org.apache.wicket.ajax.markup.html; +import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxEventBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; @@ -97,6 +98,12 @@ public abstract class AjaxFallbackLink<T> extends Link<T> implements IAjaxLink attributes.setPreventDefault(true); AjaxFallbackLink.this.updateAjaxAttributes(attributes); } + + @Override + public boolean getStatelessHint(Component component) + { + return AjaxFallbackLink.this.getStatelessHint(); + } }; } http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java index 8706414..83b5d8b 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxButton.java @@ -16,6 +16,7 @@ */ package org.apache.wicket.ajax.markup.html.form; +import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior; @@ -140,6 +141,12 @@ public abstract class AjaxButton extends Button { return AjaxButton.this.getDefaultFormProcessing(); } + + @Override + public boolean getStatelessHint(Component component) + { + return AjaxButton.this.getStatelessHint(); + } }; } http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxSubmitLink.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxSubmitLink.java b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxSubmitLink.java index 619e289..b1bf987 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxSubmitLink.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/markup/html/form/AjaxSubmitLink.java @@ -16,6 +16,7 @@ */ package org.apache.wicket.ajax.markup.html.form; +import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior; @@ -115,6 +116,12 @@ public abstract class AjaxSubmitLink extends AbstractSubmitLink { AjaxSubmitLink.this.onAfterSubmit(target, getForm()); } + + @Override + public boolean getStatelessHint(Component component) + { + return AjaxSubmitLink.this.getStatelessHint(); + } }; } http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.html ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.html b/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.html new file mode 100644 index 0000000..2ab9df2 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.html @@ -0,0 +1,40 @@ +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" > + <head> + <title>Wicket Quickstart Archetype Homepage</title> + </head> + <body> + <ul wicket:id="list"> + <li wicket:id="item"><span wicket:id="value">Item 1</span></li> + </ul> + <div id="new"></div> + <a href="#" wicket:id="more">More Data</a> + <a href="#" wicket:id="home">Home</a> + + <form wicket:id="inputForm" > + <label for="name">Name:</label> + <input wicket:id="name" id="name" type="text" size="15"/><br/> + <label for="surname">Surname:</label> + <input wicket:id="surname" id="surname" type="text" size="15"/><br/> + <button id="submitButton" wicket:id="submit">Submit</button> + <div wicket:id="feedback" id="feedback"></div> + </form> + </body> +</html> http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.java b/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.java new file mode 100644 index 0000000..7e324a4 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/ajax/StatelessPage.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.ajax; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.MarkupContainer; +import org.apache.wicket.ajax.markup.html.AjaxFallbackLink; +import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.StatelessForm; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.markup.html.link.Link; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.FeedbackPanel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; + + +/** + * Homepage + */ +public class StatelessPage extends WebPage +{ + public static final String AJAX_SUBMIT = "AJAX submit"; + + public static final String FORM_SUBMIT = "form submit"; + + static int itemCount = 0; + + private static final long serialVersionUID = 1L; + + static List<String> getList() + { + final ArrayList<String> list = new ArrayList<String>(itemCount); + final int count = ++itemCount; + + for (int idx = 1; idx <= count; idx++) + { + list.add(Integer.toString(idx)); + } + + return list; + } + + /** + * Constructor that is invoked when page is invoked without a session. + * + * @param parameters + * Page parameters + */ + public StatelessPage(final PageParameters parameters) + { + super(parameters); + + final MarkupContainer list = new WebMarkupContainer("list"); + final List<String> data = getList(); + final ListView<String> listView = new ListView<String>("item", data) + { + private static final long serialVersionUID = 200478523599165606L; + + @Override + protected void populateItem(final ListItem<String> item) + { + final String _item = item.getModelObject(); + + item.add(new Label("value", _item)); + } + }; + final Link<String[]> moreLink = new AjaxFallbackLink<String[]>("more") + { + private static final long serialVersionUID = -1023445535126577565L; + + @Override + public void onClick(final AjaxRequestTarget target) + { + final List<String> _data = getList(); + + System.out.println(_data); + + listView.setModelObject(_data); + + if (target != null) + { + target.add(list, "new"); + } + } + + @Override + protected boolean getStatelessHint() + { + return true; + } + }; + final Link<String> homeLink = new BookmarkablePageLink<String>("home", StatelessPage.class); + + add(homeLink); + list.add(listView); + add(list); + add(moreLink); + + // add form + TextField<String> name = new TextField<String>("name", new Model<String>("name")); + TextField<String> surname = new TextField<String>("surname", new Model<String>("surname")); + + Form<String> form = new StatelessForm<String>("inputForm") + { + /** + * + */ + private static final long serialVersionUID = -6554405700693024016L; + + @Override + protected void onSubmit() + { + super.onSubmit(); + info(FORM_SUBMIT); + } + }; + + form.add(name, surname); + + final FeedbackPanel feedback; + form.add(feedback = new FeedbackPanel("feedback")); + feedback.setOutputMarkupId(true); + + form.add(new AjaxSubmitLink("submit") + { + /** + * + */ + private static final long serialVersionUID = -7296676299335203926L; + + @Override + protected void onSubmit(AjaxRequestTarget target, Form<?> form) + { + super.onSubmit(target, form); + info(AJAX_SUBMIT); + target.add(feedback); + } + + @Override + protected boolean getStatelessHint() + { + return true; + } + }); + add(form); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/StatelessAjaxFallbackLinkTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/StatelessAjaxFallbackLinkTest.java b/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/StatelessAjaxFallbackLinkTest.java new file mode 100644 index 0000000..5cf7ff2 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/StatelessAjaxFallbackLinkTest.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.ajax.markup.html; + +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.apache.wicket.Session; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.StatelessPage; +import org.apache.wicket.behavior.Behavior; +import org.apache.wicket.mock.MockApplication; +import org.apache.wicket.util.tester.WicketTester; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class StatelessAjaxFallbackLinkTest +{ + protected WicketTester tester; + + @Before + public void setUp() + { + tester = new WicketTester(new MockApplication()); + } + + @After + public void teardown() + { + // things must stay stateless + assertTrue(Session.get().isTemporary()); + } + + @Test + @SuppressWarnings("unchecked") + public void testGetStatelessHint() + { + tester.startPage(StatelessPage.class); + + final StatelessPage page = (StatelessPage)tester.getLastRenderedPage(); + final AjaxFallbackLink<Void> link = (AjaxFallbackLink<Void>)page.get("more"); + + assertTrue(link.isStateless()); + + link.onClick(); + + final List<? extends Behavior> behaviors = link.getBehaviors(); + final AjaxEventBehavior behavior = (AjaxEventBehavior)behaviors.get(0); + + behavior.onRequest(); + + assertTrue(link.isStateless()); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/form/StatelessAjaxSubmitLinkTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/form/StatelessAjaxSubmitLinkTest.java b/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/form/StatelessAjaxSubmitLinkTest.java new file mode 100644 index 0000000..51f7840 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/ajax/markup/html/form/StatelessAjaxSubmitLinkTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.ajax.markup.html.form; + +import static org.junit.Assert.assertTrue; + +import org.apache.wicket.Session; +import org.apache.wicket.ajax.StatelessPage; +import org.apache.wicket.mock.MockApplication; +import org.apache.wicket.page.XmlPartialPageUpdate; +import org.apache.wicket.util.tester.FormTester; +import org.apache.wicket.util.tester.WicketTester; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class StatelessAjaxSubmitLinkTest +{ + protected WicketTester tester; + + @Before + public void setUp() + { + tester = new WicketTester(new MockApplication()); + } + + @After + public void teardown() + { + // things must stay stateless + assertTrue(Session.get().isTemporary()); + } + + @Test + public void testSubmitForm() throws Exception + { + tester.startPage(StatelessPage.class); + + FormTester formTester = tester.newFormTester("inputForm"); + formTester.setValue("name", "myname"); + formTester.setValue("surname", "mysurname"); + + tester.executeAjaxEvent("inputForm:submit", "click"); + + String response = tester.getLastResponseAsString(); + + boolean isAjaxResponse = response.contains(XmlPartialPageUpdate.START_ROOT_ELEMENT) + && response.contains(XmlPartialPageUpdate.END_ROOT_ELEMENT); + + assertTrue(isAjaxResponse); + + boolean formAjaxSubmit = response.contains(StatelessPage.FORM_SUBMIT) && + response.contains(StatelessPage.AJAX_SUBMIT); + + assertTrue(formAjaxSubmit); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/BasePage.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/BasePage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/BasePage.java index bac53a3..b06bcd2 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/BasePage.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/BasePage.java @@ -18,6 +18,7 @@ package org.apache.wicket.examples.ajax.builtin; import org.apache.wicket.examples.WicketExamplePage; import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.request.mapper.parameter.PageParameters; /** @@ -30,6 +31,18 @@ public class BasePage extends WicketExamplePage */ public BasePage() { + + } + + public BasePage(PageParameters pageParameters) + { + super(pageParameters); + } + + @Override + protected void onInitialize() + { + super.onInitialize(); add(new BookmarkablePageLink<>("back", Index.class).setAutoEnable(true)); } } http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.html ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.html b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.html new file mode 100644 index 0000000..1f07813 --- /dev/null +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.html @@ -0,0 +1,72 @@ +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org"> + <head> + <title>Stateless Wicket</title> + <link rel="stylesheet" type="text/css" href="style.css"/> + </head> + <body> + <span wicket:id="mainNavigation"></span> + <span wicket:id="message" id="message">Message goes here</span> + <br /> + <a wicket:id="indexLink" href="#">go to index</a> + <br /> + <h2>Statless ajax fallback link</h2> + <div>This link uses ajax when it is available, and a regular + wicket roundtrip when ajax or javascript are not available and the + page should be stateless.</div> + + <b>Counter: </b> + <span id="c2" wicket:id="incrementLabel"></span> + <a href="#" id="c2-link" wicket:id="incrementLink">increment</a> + <br /> + <br /> + + <h2>Stateless form submit example</h2> + <p>Submit form via AJAX. Each field is required.</p> + <form wicket:id="inputForm"> + <label for="name">Name:</label> <input wicket:id="name" id="name" + type="text" size="15" /><br /> <label for="surname">Surname:</label> + <input wicket:id="surname" id="surname" type="text" size="15" /><br /> + <button id="submitButton" wicket:id="submit">Submit</button> + + <div id="feedbackPanel" wicket:id="feedback"></div> + <br /> <span id="submittedValues" wicket:id="submittedValues"></span> + + </form> + + <h2>Form component updating behavior example</h2> + <p>The select component submits its value via AJAX on 'change' + event.</p> + <select id="select" wicket:id="select"></select> + <span id="selectedValue" wicket:id="selectedValue"></span> + + <br /> + <br /> + <h2>AJAX indicator link example</h2> + <p>AJAX indicator link and button which show their indicator for + 5 seconds.</p> + <a id="indicatingLink" wicket:id="indicatingLink">link</a> + <br /> + + <form wicket:id="indicatingForm"></form> + <button id="indicatingButton" wicket:id="indicatingButton">Button</button> + </body> +</html> http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.java b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.java new file mode 100644 index 0000000..32c5e81 --- /dev/null +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/AjaxStatelessExample.java @@ -0,0 +1,220 @@ +package org.apache.wicket.examples.stateless; + +import java.util.Arrays; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.ajax.markup.html.AjaxFallbackLink; +import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; +import org.apache.wicket.examples.WicketExamplePage; +import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton; +import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxFallbackLink; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.StatelessForm; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.markup.html.link.Link; +import org.apache.wicket.markup.html.panel.FeedbackPanel; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.util.string.StringValue; + + +public class AjaxStatelessExample extends WicketExamplePage +{ + + private static final String COUNTER_PARAM = "counter"; + + /** + * Constructor that is invoked when page is invoked without a session. + * + * @param parameters + * Page parameters + */ + public AjaxStatelessExample(final PageParameters parameters) + { + super(parameters); + setStatelessHint(true); + + add(new Label("message", new SessionModel())); + add(new BookmarkablePageLink<>("indexLink", Index.class)); + + final Label incrementLabel = new Label("incrementLabel", new AbstractReadOnlyModel<Integer>() + { + private static final long serialVersionUID = 1L; + + @Override + public Integer getObject() + { + final String counter = getParameter(parameters, COUNTER_PARAM); + return counter != null ? Integer.parseInt(counter) : 0; + } + + }); + final Link<?> incrementLink = new AjaxFallbackLink<Void>("incrementLink") + { + + @Override + public void onClick(final AjaxRequestTarget target) + { + Integer counter = (Integer)incrementLabel.getDefaultModelObject(); + updateParams(getPageParameters(), counter); + + target.add(incrementLabel, this); + } + + @Override + protected boolean getStatelessHint() + { + return true; + } + }; + + add(incrementLink); + add(incrementLabel.setOutputMarkupId(true)); + + final TextField<String> nameField = new TextField<String>("name", new Model<String>("")); + final TextField<String> surnameField = new TextField<String>("surname", new Model<String>("")); + + final Form<String> form = new StatelessForm<String>("inputForm") + { + + @Override + protected void onSubmit() + { + + } + + }; + final DropDownChoice<String> select = new DropDownChoice<String>("select", + new Model<String>("2"), Arrays.asList(new String[] { "1", "2", "3" })); + final Label selectedValue = new Label("selectedValue", ""); + add(selectedValue.setOutputMarkupId(true)); + + select.add(new AjaxFormComponentUpdatingBehavior("change") + { + + @Override + protected void onUpdate(final AjaxRequestTarget target) + { + final String value = select.getModelObject(); + selectedValue.setDefaultModelObject("Selected value: " + value); + target.add(selectedValue); + } + + @Override + public boolean getStatelessHint(Component component) + { + return true; + } + }); + + form.add(nameField.setRequired(true)); + form.add(surnameField.setRequired(true)); + + final Component feedback = new FeedbackPanel("feedback"); + final Label submittedValues = new Label("submittedValues", ""); + + form.add(feedback.setOutputMarkupId(true)); + form.add(submittedValues.setOutputMarkupId(true)); + + form.add(new AjaxSubmitLink("submit") + { + @Override + protected void onError(AjaxRequestTarget target, Form<?> form) + { + super.onError(target, form); + target.add(feedback); + } + + @Override + protected void onSubmit(AjaxRequestTarget target, Form<?> form) + { + super.onSubmit(target, form); + String values = "Your name is: " + nameField.getModelObject() + " " + surnameField.getModelObject(); + submittedValues.setDefaultModelObject(values); + target.add(feedback, submittedValues); + } + + @Override + protected boolean getStatelessHint() + { + return true; + } + }); + + add(form); + + add(select); + + + add(new IndicatingAjaxFallbackLink("indicatingLink") + { + @Override + public void onClick(AjaxRequestTarget target) + { + try + { + Thread.sleep(5000); // 1000 milliseconds is one second. + } + catch (InterruptedException ex) + { + Thread.currentThread().interrupt(); + } + } + + @Override + protected boolean getStatelessHint() + { + return true; + } + }); + + StatelessForm indicatingForm = new StatelessForm("indicatingForm"); + + add(indicatingForm); + add(new IndicatingAjaxButton("indicatingButton", indicatingForm) + { + @Override + protected void onSubmit(AjaxRequestTarget target, Form<?> form) + { + try + { + Thread.sleep(5000); // 1000 milliseconds is one second. + } + catch (InterruptedException ex) + { + Thread.currentThread().interrupt(); + } + } + + @Override + protected boolean getStatelessHint() + { + return true; + } + }); + + } + + private String getParameter(final PageParameters parameters, final String key) + { + final StringValue value = parameters.get(key); + + if (value.isNull() || value.isEmpty()) + { + return null; + } + + return value.toString(); + } + + protected final void updateParams(final PageParameters pageParameters, final int counter) + { + pageParameters.set(COUNTER_PARAM, Integer.toString(counter + 1)); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.html ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.html b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.html index 4c4a4fb..4239cc9 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.html +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.html @@ -18,6 +18,9 @@ <br /> <a wicket:id="linkToStatefulPage" href="#">go to a stateful page (triggers session creation if not already done so)</a> <br /> + <a wicket:id="linkToAjaxExamples" href="#">Stateless AJAX Example</a> + <br/> + <br/> <a wicket:id="invalidatesession" href="#">Invalidate the session</a> </body> </html> http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.java b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.java index 5b86437..95b7dea 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/stateless/Index.java @@ -61,6 +61,19 @@ public class Index extends WicketExamplePage setResponsePage(StatefulPage.class); } }); + add(new StatelessLink<Void>("linkToAjaxExamples") + { + private static final long serialVersionUID = 1L; + + /** + * @see org.apache.wicket.markup.html.link.Link#onClick() + */ + @Override + public void onClick() + { + setResponsePage(AjaxStatelessExample.class); + } + }); add(new StatelessLink<Void>("invalidatesession") { private static final long serialVersionUID = 1L; http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-user-guide/src/docs/guide/ajax/ajax_7.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/ajax/ajax_7.gdoc b/wicket-user-guide/src/docs/guide/ajax/ajax_7.gdoc index 83650d4..dd01c1f 100644 --- a/wicket-user-guide/src/docs/guide/ajax/ajax_7.gdoc +++ b/wicket-user-guide/src/docs/guide/ajax/ajax_7.gdoc @@ -1,7 +1,44 @@ +Wicket makes working with AJAX easy and pleasant with its component-oriented abstraction. However as side effect, AJAX components and behaviors make their hosting page stateful. This can be quite annoying if we are working on a page that must be stateless (for example a login page). +Starting from version 7.4.0 Wicket has made quite easy forcing existing AJAX components to be stateless. All we have to do is to override component's method @getStatelessHint@ returning true: +{code} +final Link<?> incrementLink = new AjaxFallbackLink<Void>("incrementLink") +{ -AJAX is another example of how Wicket can simplify web technologies providing a good component and object oriented abstraction of them. + ... + + @Override + protected boolean getStatelessHint() + { + return true; + } +}; +{code} -In this chapter we have seen how to take advantage of the AJAX support provided by Wicket to write AJAX-enhanced applications. Most of the chapter has been dedicated to the built-in components and behaviors that let us adopt AJAX without almost any effort. -In the final part of the chapter we have seen how Wicket physically implements an AJAX call on client side using AJAX request attributes. Then, we have learnt how to use call listeners to execute custom JavaScript during AJAX request lifecycle. +Just like components also AJAX behaviors can be turned to stateless overriding @getStatelessHint(Component component)@ + +{code} + final AjaxFormSubmitBehavior myBehavior = new AjaxFormSubmitBehavior(form, event) + { + ... + + @Override + protected boolean getStatelessHint(Component component) + { + return true; + } +}; +{code} + +h3. Usage + +Stateless components and behaviors follows the same rules and conventions of their standard stateful version shipped with Wicket. Therefore you will find different handler methods like @onSubmit@ or @onClick@ that provide an instance of @AjaxRequestTarget@ to refresh components markup. Such components must have a markup id in order to be manipulated via JavaScript. +However in this case calling @setOutputMarkupId@ on a component is not enough. Since we are working with a stateless page, the id of the component to refresh must be unique but also static, meaning that it should not depend on page instance. In other words, the id should be constant through different instances of the same page. +By default Wicket generates markup ids using a session-level counter and this make them not static. Hence, to refresh component in a stateless page we must provide them with static ids, either setting them in Java code (with @Component.setMarkupId@) or simply writing them directly in the markup: + +{code} + <span id="staticIdToUSe" wicket:id="componentWicketId"></span> +{code} + +See examples site for a full showcase of AJAX-stateless capabilities. http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-user-guide/src/docs/guide/ajax/ajax_8.gdoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/ajax/ajax_8.gdoc b/wicket-user-guide/src/docs/guide/ajax/ajax_8.gdoc new file mode 100644 index 0000000..83650d4 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/ajax/ajax_8.gdoc @@ -0,0 +1,7 @@ + + +AJAX is another example of how Wicket can simplify web technologies providing a good component and object oriented abstraction of them. + +In this chapter we have seen how to take advantage of the AJAX support provided by Wicket to write AJAX-enhanced applications. Most of the chapter has been dedicated to the built-in components and behaviors that let us adopt AJAX without almost any effort. + +In the final part of the chapter we have seen how Wicket physically implements an AJAX call on client side using AJAX request attributes. Then, we have learnt how to use call listeners to execute custom JavaScript during AJAX request lifecycle. http://git-wip-us.apache.org/repos/asf/wicket/blob/96ba4888/wicket-user-guide/src/docs/guide/toc.yml ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/docs/guide/toc.yml b/wicket-user-guide/src/docs/guide/toc.yml index b0e7631..537ae51 100644 --- a/wicket-user-guide/src/docs/guide/toc.yml +++ b/wicket-user-guide/src/docs/guide/toc.yml @@ -154,7 +154,8 @@ ajax: ajax_4: Using an activity indicator ajax_5: AJAX request attributes and call listeners ajax_6: Creating custom AJAX call listener - ajax_7: Summary + ajax_7: Stateless AJAX components/behaviors + ajax_8: Summary jee: title: Integration with enterprise containers jee_1: Integrating Wicket with EJB
