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

Reply via email to