This is an automated email from the ASF dual-hosted git repository. benw pushed a commit to branch javax in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/javax by this push: new ae8ff3eef TAP5-2790: Fixing grouped SelectModel for Palette ae8ff3eef is described below commit ae8ff3eef5af2a6b02c6c4adbe0c741cb12c65cc Author: Ben Weidig <b...@netzgut.net> AuthorDate: Fri Nov 15 11:21:37 2024 +0100 TAP5-2790: Fixing grouped SelectModel for Palette --- .../META-INF/modules/t5/core/palette.coffee | 13 ++- .../internal/util/SelectModelRenderer.java | 51 +++++++--- tapestry-core/src/test/app1/PaletteGroupedDemo.tml | 42 ++++++++ .../tapestry5/integration/app1/PaletteTests.java | 37 +++++++ .../tapestry5/integration/app1/pages/Index.java | 1 + .../integration/app1/pages/PaletteDemo.java | 38 +++++++- .../integration/app1/pages/PaletteGroupedDemo.java | 107 +++++++++++++++++++++ .../corelib/components/option_group_attributes.txt | 2 +- .../tapestry5/corelib/components/option_groups.txt | 2 +- .../option_groups_precede_ungroup_options.txt | 2 +- 10 files changed, 274 insertions(+), 21 deletions(-) diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/palette.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/palette.coffee index 0ec5dea36..52fa98404 100644 --- a/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/palette.coffee +++ b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/palette.coffee @@ -1,4 +1,4 @@ -# Copyright 2012-2013 The Apache Software Foundation +# Copyright 2012-2024 The Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -235,7 +235,8 @@ define ["t5/core/dom", "underscore", "t5/core/events"], for o in movers @insertOption toOptions, o, atEnd - selectedOptions = if to is @selected then toOptions else fromOptions + isSelectedSelect = to is @selected + selectedOptions = if isSelectedSelect then toOptions else fromOptions @performUpdate false, selectedOptions, => for i in [(from.element.length - 1)..0] by -1 @@ -249,7 +250,13 @@ define ["t5/core/dom", "underscore", "t5/core/events"], to.element.remove i for o in toOptions - to.element.add o, null + groupIdx = o.getAttribute('data-optgroup-idx') + if isSelectedSelect or !groupIdx or groupIdx == '' + to.element.add o, null + else + group = to.element.children[parseInt(groupIdx)] + group.appendChild o + insertOption: (options, option, atEnd) -> diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/SelectModelRenderer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/SelectModelRenderer.java index 140ac3a7d..484cd229e 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/SelectModelRenderer.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/SelectModelRenderer.java @@ -1,3 +1,5 @@ +// Copyright 2008-2024 The Apache Software Foundation +// // Licensed 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 @@ -24,6 +26,9 @@ public class SelectModelRenderer implements SelectModelVisitor private final boolean raw; + private int optgroupIdx = -1; + private boolean inOptgroup = false; + public SelectModelRenderer(final MarkupWriter writer, ValueEncoder encoder, boolean raw) { this.writer = writer; @@ -31,56 +36,78 @@ public class SelectModelRenderer implements SelectModelVisitor this.raw = raw; } + @Override public void beginOptionGroup(OptionGroupModel groupModel) { - writer.element("optgroup", "label", groupModel.getLabel()); + this.optgroupIdx++; + this.inOptgroup = true; + this.writer.element("optgroup", "label", groupModel.getLabel()); writeDisabled(groupModel.isDisabled()); writeAttributes(groupModel.getAttributes()); } + @Override public void endOptionGroup(OptionGroupModel groupModel) { - writer.end(); // select + this.inOptgroup = false; + this.writer.end(); // select } + @Override @SuppressWarnings("unchecked") public void option(OptionModel optionModel) { Object optionValue = optionModel.getValue(); - String clientValue = encoder.toClient(optionValue); + String clientValue = this.encoder.toClient(optionValue); - writer.element("option", "value", clientValue); + this.writer.element("option", "value", clientValue); - if (isOptionSelected(optionModel, clientValue)) writer.attributes("selected", "selected"); + if (this.inOptgroup && this.optgroupIdx > -1) + { + this.writer.attributes("data-optgroup-idx", this.optgroupIdx); + } + + if (isOptionSelected(optionModel, clientValue)) + { + this.writer.attributes("selected", "selected"); + } writeDisabled(optionModel.isDisabled()); writeAttributes(optionModel.getAttributes()); - if (raw) + if (this.raw) { - writer.writeRaw(optionModel.getLabel()); + this.writer.writeRaw(optionModel.getLabel()); } else { - writer.write(optionModel.getLabel()); + this.writer.write(optionModel.getLabel()); } - writer.end(); + this.writer.end(); } private void writeDisabled(boolean disabled) { - if (disabled) writer.attributes("disabled", "disabled"); + if (disabled) + { + this.writer.attributes("disabled", "disabled"); + } } private void writeAttributes(Map<String, String> attributes) { - if (attributes == null) return; + if (attributes == null) + { + return; + } for (Map.Entry<String, String> e : attributes.entrySet()) - writer.attributes(e.getKey(), e.getValue()); + { + this.writer.attributes(e.getKey(), e.getValue()); + } } /** diff --git a/tapestry-core/src/test/app1/PaletteGroupedDemo.tml b/tapestry-core/src/test/app1/PaletteGroupedDemo.tml new file mode 100644 index 000000000..de0159264 --- /dev/null +++ b/tapestry-core/src/test/app1/PaletteGroupedDemo.tml @@ -0,0 +1,42 @@ +<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> + +<h1>Palette Grouped Demo</h1> + + +<t:form t:id="demo" class="form-horizontal"> + <div class="checkbox"> + <label> + <t:checkbox t:id="reorder"/> + Enable Reorder + </label> + </div> + + + <div class="form-group"> + + <t:label for="languages"/> + + <t:palette t:id="languages" model="languageModel" reorder="reorder" encoder="languageEncoder" + availableLabel="Languages Offered" validate="required"> + <t:parameter name="selectedLabel" xml:space="default"> + <t:if test="reorder" else="Selected">Ranked + </t:if> + Languages + </t:parameter> + </t:palette> + </div> + + <input type="submit" class="btn btn-primary"/> + +</t:form> + +<dl class="dl-horizontal"> + <dt>Languages:</dt> + <dd id="selected-languages">${languages}</dd> + <dt>Selected Values</dt> + <dd id="event-selection"/> + <dt>Reorder</dt> + <dd id="event-reorder"></dd> +</dl> + +</html> diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/PaletteTests.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/PaletteTests.java index 23553e149..a725580d9 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/PaletteTests.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/PaletteTests.java @@ -14,9 +14,12 @@ package org.apache.tapestry5.integration.app1; +import java.util.List; + import org.apache.tapestry5.corelib.components.Palette; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebElement; +import org.testng.Assert; import org.testng.annotations.Test; /** @@ -131,4 +134,38 @@ public class PaletteTests extends App1TestCase assertTextPresent("You must provide a value for Languages."); } + + @Test + public void palette_component_grouped() + { + openLinks("Palette Grouped Demo", "Reset Page State"); + + assertText("css=.palette-available .palette-title", "Languages Offered"); + assertText("css=.palette-selected .palette-title", "Selected Languages"); + + addSelection(AVAILABLE_OPTIONS, "label=HASKELL"); + addSelection(AVAILABLE_OPTIONS, "label=JAVA"); + click(SELECT_BUTTON); + + // What a listener on the events.palette.willChange event would see in memo.selectdValues: + assertText("id=event-selection", "[\"HASKELL\",\"JAVA\"]"); + + clickAndWait(SUBMIT); + + assertText("id=selected-languages", "[HASKELL, JAVA]"); + + addSelection(SELECTED_OPTIONS, "label=JAVA"); + + click(DESELECT_BUTTON); + + List<WebElement> funcOptions = this.webDriver + .findElements(convertLocator(AVAILABLE_OPTIONS + " optgroup[label=func] option")); + + List<WebElement> ooOptions = this.webDriver + .findElements(convertLocator(AVAILABLE_OPTIONS + " optgroup[label=oo] option")); + + Assert.assertEquals(funcOptions.size(), 2); + Assert.assertEquals(ooOptions.size(), 2); + + } } diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java index 22210bf9f..025b7eb07 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java @@ -396,6 +396,7 @@ public class Index "use expansions inside attributes of ordinary elements"), new Item("PaletteDemo", "Palette Demo", "multiple selection component"), + new Item("PaletteGroupedDemo", "Palette Grouped Demo", "multiple selection component (grouped)"), new Item("ReturnTypes", "Return Types", "tests various event handler return types"), diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PaletteDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PaletteDemo.java index d626c4c9a..3694f8ccc 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PaletteDemo.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PaletteDemo.java @@ -14,7 +14,13 @@ package org.apache.tapestry5.integration.app1.pages; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.apache.tapestry5.ComponentResources; +import org.apache.tapestry5.OptionGroupModel; +import org.apache.tapestry5.OptionModel; import org.apache.tapestry5.SelectModel; import org.apache.tapestry5.ValueEncoder; import org.apache.tapestry5.annotations.Import; @@ -22,13 +28,13 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.commons.services.TypeCoercer; import org.apache.tapestry5.integration.app1.data.ProgrammingLanguage; +import org.apache.tapestry5.internal.OptionGroupModelImpl; +import org.apache.tapestry5.internal.OptionModelImpl; import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.util.AbstractSelectModel; import org.apache.tapestry5.util.EnumSelectModel; import org.apache.tapestry5.util.EnumValueEncoder; -import java.util.ArrayList; -import java.util.List; - @Import(module="palette-demo") public class PaletteDemo { @@ -65,4 +71,30 @@ public class PaletteDemo { return new EnumValueEncoder(typeCoercer, ProgrammingLanguage.class); } + + public SelectModel getGroupedModel() + { + return new AbstractSelectModel() + { + + @Override + public List<OptionGroupModel> getOptionGroups() + { + List<OptionGroupModel> groups = new ArrayList<>(); + groups.add(new OptionGroupModelImpl("group1", false, + Arrays.asList(new OptionModelImpl("1")))); + groups.add(new OptionGroupModelImpl("group2", false, + Arrays.asList(new OptionModelImpl("1")))); + return null; + } + + @Override + public List<OptionModel> getOptions() + { + // TODO Auto-generated method stub + return null; + } + + }; + } } diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PaletteGroupedDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PaletteGroupedDemo.java new file mode 100644 index 000000000..0fe130ba7 --- /dev/null +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PaletteGroupedDemo.java @@ -0,0 +1,107 @@ +// Copyright 2007-2014 The Apache Software Foundation +// +// Licensed 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.tapestry5.integration.app1.pages; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.tapestry5.ComponentResources; +import org.apache.tapestry5.OptionGroupModel; +import org.apache.tapestry5.OptionModel; +import org.apache.tapestry5.SelectModel; +import org.apache.tapestry5.ValueEncoder; +import org.apache.tapestry5.annotations.Import; +import org.apache.tapestry5.annotations.Persist; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.commons.services.TypeCoercer; +import org.apache.tapestry5.integration.app1.data.ProgrammingLanguage; +import org.apache.tapestry5.internal.OptionGroupModelImpl; +import org.apache.tapestry5.internal.OptionModelImpl; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.util.AbstractSelectModel; +import org.apache.tapestry5.util.EnumValueEncoder; + +@Import(module="palette-demo") +public class PaletteGroupedDemo +{ + @Inject + private ComponentResources resources; + + @Persist + @Property + private List<ProgrammingLanguage> languages; + + @Persist + @Property + private boolean reorder; + + @Inject + private TypeCoercer typeCoercer; + + private static final Iterable<ProgrammingLanguage> FUNC = Arrays.asList( + ProgrammingLanguage.ERLANG, ProgrammingLanguage.HASKELL, ProgrammingLanguage.LISP); + private static final Iterable<ProgrammingLanguage> OO = Arrays.asList(ProgrammingLanguage.JAVA, + ProgrammingLanguage.RUBY); + + void onPrepareFromDemo() + { + if (this.languages == null) + { + this.languages = new ArrayList<>(); + } + } + + public SelectModel getLanguageModel() + { + return new AbstractSelectModel() + { + + @Override + public List<OptionGroupModel> getOptionGroups() + { + List<OptionGroupModel> groups = new ArrayList<>(); + groups.add(new OptionGroupModelImpl("func", false, + toOptionModels(FUNC))); + groups.add(new OptionGroupModelImpl("oo", false, toOptionModels(OO))); + return groups; + } + + @Override + public List<OptionModel> getOptions() + { + // TODO Auto-generated method stub + return null; + } + + }; + } + + private List<OptionModel> toOptionModels(Iterable<ProgrammingLanguage> languages) + { + List<OptionModel> options = new ArrayList<>(); + for (ProgrammingLanguage enumValue : languages) + { + options.add(new OptionModelImpl(enumValue.name(), enumValue)); + } + return options; + } + + @SuppressWarnings("unchecked") + public ValueEncoder getLanguageEncoder() + { + return new EnumValueEncoder(this.typeCoercer, ProgrammingLanguage.class); + } +} diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_group_attributes.txt b/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_group_attributes.txt index f0cff6bf5..683d4cf71 100644 --- a/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_group_attributes.txt +++ b/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_group_attributes.txt @@ -1,2 +1,2 @@ <?xml version="1.0"?> -<select><optgroup class="pixie" label="Husbands"><option selected="selected" value="Fred">Fred</option><option value="Barney">Barney</option></optgroup></select> \ No newline at end of file +<select><optgroup class="pixie" label="Husbands"><option selected="selected" data-optgroup-idx="0" value="Fred">Fred</option><option data-optgroup-idx="0" value="Barney">Barney</option></optgroup></select> \ No newline at end of file diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups.txt b/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups.txt index 3035c4af9..c1d4fd14b 100644 --- a/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups.txt +++ b/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups.txt @@ -1,2 +1,2 @@ <?xml version="1.0"?> -<select><optgroup label="Husbands"><option selected="selected" value="Fred">Fred</option><option value="Barney">Barney</option></optgroup><optgroup disabled="disabled" label="Wives"><option value="Wilma">Wilma</option><option value="Betty">Betty</option></optgroup></select> \ No newline at end of file +<select><optgroup label="Husbands"><option selected="selected" data-optgroup-idx="0" value="Fred">Fred</option><option data-optgroup-idx="0" value="Barney">Barney</option></optgroup><optgroup disabled="disabled" label="Wives"><option data-optgroup-idx="1" value="Wilma">Wilma</option><option data-optgroup-idx="1" value="Betty">Betty</option></optgroup></select> \ No newline at end of file diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups_precede_ungroup_options.txt b/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups_precede_ungroup_options.txt index 7d49d8e8f..da0aebcb0 100644 --- a/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups_precede_ungroup_options.txt +++ b/tapestry-core/src/test/resources/org/apache/tapestry5/corelib/components/option_groups_precede_ungroup_options.txt @@ -1,2 +1,2 @@ <?xml version="1.0"?> -<select><optgroup label="Husbands"><option selected="selected" value="Fred">Fred</option><option value="Barney">Barney</option></optgroup><option value="Wilma">Wilma</option><option value="Betty">Betty</option></select> \ No newline at end of file +<select><optgroup label="Husbands"><option selected="selected" data-optgroup-idx="0" value="Fred">Fred</option><option data-optgroup-idx="0" value="Barney">Barney</option></optgroup><option value="Wilma">Wilma</option><option value="Betty">Betty</option></select> \ No newline at end of file