You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2018/12/06 20:31:24 UTC

[04/14] wicket git commit: WICKET-6587 CheckBoxSelector allow dynamic list of CheckBoxes

WICKET-6587 CheckBoxSelector allow dynamic list of CheckBoxes

this closes #292 and closes #293


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/7b025aba
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/7b025aba
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/7b025aba

Branch: refs/heads/WICKET-6563
Commit: 7b025aba9886787c2c707b046f39657f2939afb8
Parents: b5c6a8d
Author: Sven Meier <sv...@apache.org>
Authored: Tue Nov 27 11:14:24 2018 +0100
Committer: Sven Meier <sv...@apache.org>
Committed: Tue Nov 27 11:52:02 2018 +0100

----------------------------------------------------------------------
 .../markup/html/form/CheckBoxSelector.java      |  74 ++++++-
 .../wicket/markup/html/form/CheckSelector.js    |   4 +-
 .../examples/compref/CheckBoxSelectorPage.html  |  93 ++++----
 .../examples/compref/CheckBoxSelectorPage.java  | 221 ++++++++++++-------
 4 files changed, 263 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/7b025aba/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckBoxSelector.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckBoxSelector.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckBoxSelector.java
index acea40d..83ae73d 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckBoxSelector.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckBoxSelector.java
@@ -16,10 +16,14 @@
  */
 package org.apache.wicket.markup.html.form;
 
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import org.apache.wicket.Component;
-
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.markup.html.WebMarkupContainer;
 
 /**
  * A Javascript-based "Select All" checkbox component that works with a loose collection of
@@ -33,31 +37,63 @@ public class CheckBoxSelector extends AbstractCheckSelector
 {
 	private static final long serialVersionUID = 1L;
 
+	private final Set<CheckBox> connectedCheckBoxes = new HashSet<>();
+	
+	private final Behavior cleanup = new Behavior()
+	{
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		public void onRemove(Component component)
+		{
+			connectedCheckBoxes.remove(component);
+			component.remove(this);
+		}
+	};
+
 	/**
-	 * Javascript array literal containing the markup IDs of the checkboxes we want to
-	 * check/uncheck. Example: "['foo', 'bar', 'baz']". Generated by
-	 * JavascriptUtils.buildMarkupIdJSArrayLiteral().
+	 * @param id
+	 *            The component ID
+	 *            
+	 * @see CheckBoxSelector#getCheckBoxes()
 	 */
-	private final String checkBoxIdArrayLiteral;
+	public CheckBoxSelector(String id)
+	{
+		super(id);
+	}
 
 	/**
 	 * @param id
 	 *            The component ID
 	 * @param boxes
-	 *            The CheckBoxes this selector will control.
+	 *            checkBoxes this selector will control
 	 */
 	public CheckBoxSelector(String id, CheckBox... boxes)
 	{
 		super(id);
 
-		checkBoxIdArrayLiteral = buildMarkupIdJSArrayLiteral(Arrays.asList(boxes));
+		for (CheckBox box : boxes)
+		{
+			connectedCheckBoxes.add(box);
+			box.add(cleanup);
+		}
 	}
 
 	@Override
 	protected CharSequence getFindCheckboxesFunction()
 	{
 		return String.format("Wicket.CheckboxSelector.getCheckboxesFunction(%s)",
-			checkBoxIdArrayLiteral);
+			buildMarkupIdJSArrayLiteral(getCheckBoxes()));
+	}
+
+	/**
+	 * Override this method to control a dynamic collection of {@link CheckBox}es.
+	 * 
+	 * @return by default returns the checkBoxes passed to the constructor
+	 */
+	protected Iterable<? extends CheckBox> getCheckBoxes()
+	{
+		return connectedCheckBoxes;
 	}
 
 	/**
@@ -68,7 +104,7 @@ public class CheckBoxSelector extends AbstractCheckSelector
 	 *            The components whose IDs we need
 	 * @return a properly formatted JS array literal
 	 */
-	private String buildMarkupIdJSArrayLiteral(final Iterable<? extends Component> components)
+	private String buildMarkupIdJSArrayLiteral(final Iterable<? extends CheckBox> components)
 	{
 		StringBuilder buf = new StringBuilder();
 		buf.append('[');
@@ -76,7 +112,6 @@ public class CheckBoxSelector extends AbstractCheckSelector
 		{
 			for (Component component : components)
 			{
-				component.setOutputMarkupId(true);
 				buf.append('\'').append(component.getMarkupId()).append("', ");
 			}
 			buf.delete(buf.length() - 2, buf.length());
@@ -85,4 +120,21 @@ public class CheckBoxSelector extends AbstractCheckSelector
 		return buf.toString();
 	}
 
+	/**
+	 * Utility method to collect all {@link CheckBox}es inside a container.
+	 * 
+	 * @param container
+	 *            container with checkBoxes
+	 * @return all contained checkBoxes
+	 */
+	public static final Iterable<CheckBox> collectCheckBoxes(WebMarkupContainer container)
+	{
+		List<CheckBox> checkBoxes = new ArrayList<>();
+
+		container.<CheckBox, Void> visitChildren(CheckBox.class, (child, visit) -> {
+			checkBoxes.add(child);
+		});
+
+		return checkBoxes;
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/7b025aba/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckSelector.js
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckSelector.js b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckSelector.js
index 66f2e19..5c0bce1 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckSelector.js
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/CheckSelector.js
@@ -145,7 +145,9 @@
 	
 				for (var i = 0; i < checkBoxIDs.length; i++) {
 					var checkBox = document.getElementById(checkBoxIDs[i]);
-					result.push(checkBox);
+					if (checkBox) {
+						result.push(checkBox);
+					}
 				}
 				return result;
 			};

http://git-wip-us.apache.org/repos/asf/wicket/blob/7b025aba/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.html
----------------------------------------------------------------------
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.html b/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.html
index 434d8c6..703fef7 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.html
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.html
@@ -1,41 +1,52 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-    <head>
-        <title>Wicket Examples - component reference</title>
-    </head>
-    <body>
-        <wicket:extend>
-
-        <h1>wicket.markup.html.form.CheckGroup</h1>
-        <wicket:link><a href="Index.html">[back to the reference]</a></wicket:link>
-
-        <p>
-            A CheckBoxSelector selects and deselects all Check components under the same CheckGroup as itself
-        </p>
-        <p>
-         <form wicket:id="form">
-             CheckGroup:<br/>
-             <div wicket:id="checkgroup">
-                 <input type="checkbox" wicket:id="check1"/> 1
-                 <input type="checkbox" wicket:id="check2"/> 2
-                 <input type="checkbox" wicket:id="check3"/> 3
-                 <input type="checkbox" wicket:id="check4"/> 4
-                 <input type="checkbox" wicket:id="groupSelector"/> select all
-             </div>
-             <input type="checkbox" wicket:id="groupSelectorOutside"/> select all (outside group)
-             <hr/>
-             CheckboxMultipleChoice:
-             <div wicket:id="choice"/>
-             <input type="checkbox" wicket:id="choiceSelector"/> select all
-             <hr/>
-             Loose Checkboxes:
-             <input type="checkbox" wicket:id="looseCheck1"/> 1
-             <input type="checkbox" wicket:id="looseCheck2"/> 2
-             <input type="checkbox" wicket:id="looseCheck3"/> 3
-             <input type="checkbox" wicket:id="looseCheck4"/> 4
-             <input type="checkbox" wicket:id="looseSelector"/> select all
-         </form>
-       </p>  
-    </wicket:extend>
-</body>
-</html>
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+    <head>
+        <title>Wicket Examples - component reference</title>
+    </head>
+    <body>
+        <wicket:extend>
+
+        <h1>wicket.markup.html.form.CheckGroup</h1>
+        <wicket:link><a href="Index.html">[back to the reference]</a></wicket:link>
+
+        <p>
+            A CheckBoxSelector selects and deselects all Check components under the same CheckGroup as itself
+        </p>
+        <p>
+         <form wicket:id="form">
+             CheckGroup:<br/>
+             <div wicket:id="checkgroup">
+                 <input type="checkbox" wicket:id="check1"/> 1
+                 <input type="checkbox" wicket:id="check2"/> 2
+                 <input type="checkbox" wicket:id="check3"/> 3
+                 <input type="checkbox" wicket:id="check4"/> 4
+                 <input type="checkbox" wicket:id="groupSelector"/> select all
+             </div>
+             <input type="checkbox" wicket:id="groupSelectorOutside"/> select all (outside group)
+             <hr/>
+             CheckboxMultipleChoice:
+             <div wicket:id="choice"/>
+             <input type="checkbox" wicket:id="choiceSelector"/> select all
+             <hr/>
+             Loose Checkboxes:
+             <input type="checkbox" wicket:id="looseCheck1"/> 1
+             <input type="checkbox" wicket:id="looseCheck2"/> 2
+             <input type="checkbox" wicket:id="looseCheck3"/> 3
+             <input type="checkbox" wicket:id="looseCheck4"/> 4
+             <input type="checkbox" wicket:id="looseSelector"/> select all
+             
+             <hr/>
+             Extensible Selector:
+             <ul>
+                 <li wicket:id="list">
+                     <input type="checkbox" wicket:id="check"/><wicket:label for="check"/>
+                 </li>
+             </ul>
+             <input type="checkbox" wicket:id="extensibleSelector"/> select all
+             <input type="submit" value="add a choice" wicket:id="addChoice"/>
+             <input type="submit" value="remove a choice" wicket:id="removeChoice"/>
+         </form>
+       </p>  
+    </wicket:extend>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/wicket/blob/7b025aba/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.java
----------------------------------------------------------------------
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.java
index aa1bcd9..aab653d 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/compref/CheckBoxSelectorPage.java
@@ -1,76 +1,145 @@
-/*
- * 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.examples.compref;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.apache.wicket.examples.WicketExamplePage;
-import org.apache.wicket.markup.html.form.Check;
-import org.apache.wicket.markup.html.form.CheckBox;
-import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
-import org.apache.wicket.markup.html.form.CheckBoxSelector;
-import org.apache.wicket.markup.html.form.CheckGroup;
-import org.apache.wicket.markup.html.form.CheckGroupSelector;
-import org.apache.wicket.markup.html.form.CheckboxMultipleChoiceSelector;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.request.mapper.parameter.PageParameters;
-
-/**
- * An example page for {@link CheckBoxSelector}
- */
-public class CheckBoxSelectorPage extends WicketExamplePage
-{
-	private static final long serialVersionUID = 1L;
-
-	/**
-	 * Constructor
-	 * 
-	 * @param parameters
-	 *            Page parameters
-	 */
-	public CheckBoxSelectorPage(final PageParameters parameters)
-	{
-		super(parameters);
-
-		final Form<?> form = new Form<>("form");
-		add(form);
-		final CheckGroup<Integer> checkgroup = new CheckGroup<>("checkgroup", Arrays.asList(
-			1, 2, 3, 4));
-		form.add(checkgroup);
-		checkgroup.add(new Check<>("check1", Model.of(1)));
-		checkgroup.add(new Check<>("check2", Model.of(2)));
-		checkgroup.add(new Check<>("check3", Model.of(3)));
-		checkgroup.add(new Check<>("check4", Model.of(4)));
-		// one selector inside the checkgroup...
-		checkgroup.add(new CheckGroupSelector("groupSelector"));
-
-		// ...and one selector outside the checkgroup
-		form.add(new CheckGroupSelector("groupSelectorOutside", checkgroup));
-		final CheckBoxMultipleChoice<Integer> choice = new CheckBoxMultipleChoice<>(
-			"choice", Model.ofList(new ArrayList<>()), Arrays.asList(1, 2, 3, 4));
-		form.add(choice);
-		form.add(new CheckboxMultipleChoiceSelector("choiceSelector", choice));
-		final CheckBox loose1 = new CheckBox("looseCheck1", Model.of(Boolean.FALSE));
-		final CheckBox loose2 = new CheckBox("looseCheck2", Model.of(Boolean.FALSE));
-		final CheckBox loose3 = new CheckBox("looseCheck3", Model.of(Boolean.FALSE));
-		final CheckBox loose4 = new CheckBox("looseCheck4", Model.of(Boolean.FALSE));
-		form.add(loose1, loose2, loose3, loose4);
-		form.add(new CheckBoxSelector("looseSelector", loose1, loose2, loose3, loose4));
-	}
-}
+/*
+ * 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.examples.compref;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.wicket.examples.WicketExamplePage;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.Check;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
+import org.apache.wicket.markup.html.form.CheckBoxSelector;
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.html.form.CheckGroupSelector;
+import org.apache.wicket.markup.html.form.CheckboxMultipleChoiceSelector;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+/**
+ * An example page for {@link CheckBoxSelector}
+ */
+public class CheckBoxSelectorPage extends WicketExamplePage
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param parameters
+	 *            Page parameters
+	 */
+	public CheckBoxSelectorPage(final PageParameters parameters)
+	{
+		super(parameters);
+
+		final Form<?> form = new Form<>("form");
+		add(form);
+		final CheckGroup<Integer> checkgroup = new CheckGroup<>("checkgroup", Arrays.asList(
+			1, 2, 3, 4));
+		form.add(checkgroup);
+		checkgroup.add(new Check<>("check1", Model.of(1)));
+		checkgroup.add(new Check<>("check2", Model.of(2)));
+		checkgroup.add(new Check<>("check3", Model.of(3)));
+		checkgroup.add(new Check<>("check4", Model.of(4)));
+		// one selector inside the checkgroup...
+		checkgroup.add(new CheckGroupSelector("groupSelector"));
+
+		// ...and one selector outside the checkgroup
+		form.add(new CheckGroupSelector("groupSelectorOutside", checkgroup));
+		
+		final CheckBoxMultipleChoice<Integer> choice = new CheckBoxMultipleChoice<>(
+			"choice", Model.ofList(new ArrayList<>()), Arrays.asList(1, 2, 3, 4));
+		form.add(choice);
+		form.add(new CheckboxMultipleChoiceSelector("choiceSelector", choice));
+
+		final CheckBox loose1 = new CheckBox("looseCheck1", Model.of(Boolean.FALSE));
+		final CheckBox loose2 = new CheckBox("looseCheck2", Model.of(Boolean.FALSE));
+		final CheckBox loose3 = new CheckBox("looseCheck3", Model.of(Boolean.FALSE));
+		final CheckBox loose4 = new CheckBox("looseCheck4", Model.of(Boolean.FALSE));
+		form.add(loose1, loose2, loose3, loose4);
+		form.add(new CheckBoxSelector("looseSelector", loose1, loose2, loose3, loose4));
+
+		// and one which will get more choices later
+		final List<Integer> extensibleChoices = new ArrayList<>(Arrays.asList(1, 2, 3));
+		final Set<Integer> selected = new HashSet<>();
+		final ListView<Integer> listView = new ListView<Integer>("list", extensibleChoices) {
+			@Override
+			protected void populateItem(final ListItem<Integer> item) {
+				final CheckBox check = new CheckBox("check", new Model<Boolean>() {
+					@Override
+					public Boolean getObject() {
+						return selected.contains(item.getModelObject());
+					}
+
+					@Override
+					public void setObject(Boolean object) {
+						if (object) {
+							selected.add(item.getModelObject());
+						} else {
+							selected.remove(item.getModelObject());
+						}
+					}
+				});
+				check.setLabel(() -> item.getModelObject().toString());
+				item.add(check);
+			}
+		};
+		listView.setReuseItems(true);
+		form.add(listView);
+		form.add(new Button("addChoice") {
+			@Override
+			public void onSubmit() {
+				extensibleChoices.add(extensibleChoices.get(extensibleChoices.size() - 1) + 1);
+			}
+		});
+		form.add(new Button("removeChoice") {
+			
+			@Override
+			protected void onConfigure()
+			{
+				super.onConfigure();
+
+				setEnabled(extensibleChoices.size() > 1);
+			}
+			
+			public void onSubmit()
+			{
+				
+				Integer integer = extensibleChoices.get(extensibleChoices.size() - 1);
+				extensibleChoices.remove(integer);
+				selected.remove(integer);
+			}
+		});
+
+		final CheckBoxSelector extensibleSelector = new CheckBoxSelector("extensibleSelector") {
+			@Override
+			protected Iterable<? extends CheckBox> getCheckBoxes()
+			{
+				return collectCheckBoxes(listView);
+			}
+		};
+		form.add(extensibleSelector);
+	}
+}