You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2021/07/02 22:27:40 UTC
[myfaces-tobago] branch master updated: feat: grouping of radio
buttons
This is an automated email from the ASF dual-hosted git repository.
lofwyr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/master by this push:
new 551d03a feat: grouping of radio buttons
551d03a is described below
commit 551d03a0466aff2034fc5a2811d1c52e2235cc7b
Author: Udo Schnurpfeil <ud...@irian.eu>
AuthorDate: Sat Jul 3 00:08:25 2021 +0200
feat: grouping of radio buttons
wip - basic implementation - missing decoding
issue: tobago-2057
---
.../myfaces/tobago/component/Attributes.java | 1 +
.../tobago/context/TobagoExceptionHandler.java | 13 ++--
.../renderkit/renderer/SelectOneRadioRenderer.java | 52 ++++++++++++++-
.../renderkit/renderer/SelectOneRendererBase.java | 9 ++-
.../SelectManyCheckboxTagDeclaration.java | 5 +-
.../component/SelectOneRadioTagDeclaration.java | 4 +-
.../internal/taglib/declaration/HasGroup.java | 32 +++++++++
.../030-select/30-selectOneRadio/Radio.xhtml | 76 ++++++++++++++++++----
.../50-selectManyCheckbox/Multi_Checkbox.xhtml | 40 ++++++++----
9 files changed, 195 insertions(+), 37 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
index 4a054f3..790c744 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
@@ -121,6 +121,7 @@ public enum Attributes {
gridRow,
gridTemplateColumns,
gridTemplateRows,
+ group,
help,
height,
hidden,
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoExceptionHandler.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoExceptionHandler.java
index d4e38b5..8706459 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoExceptionHandler.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoExceptionHandler.java
@@ -97,7 +97,10 @@ public class TobagoExceptionHandler extends ExceptionHandlerWrapper {
while (iterator.hasNext()) {
final ExceptionQueuedEvent event = iterator.next();
final ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
- final Throwable cause = this.getWrapped().getRootCause(context.getException());
+ Throwable cause = this.getWrapped().getRootCause(context.getException());
+ if (cause == null) {
+ cause = context.getException();
+ }
final NavigationHandler nav = facesContext.getApplication().getNavigationHandler();
if (cause instanceof ViewExpiredException
@@ -143,22 +146,18 @@ public class TobagoExceptionHandler extends ExceptionHandlerWrapper {
} else {
final HttpServletResponse response =
(HttpServletResponse) facesContext.getExternalContext().getResponse();
- try {
- response.resetBuffer(); // undo rendering, if you can.
- } catch (Exception e) {
- LOG.info("Can't reset buffer!");
- }
+ response.resetBuffer(); // undo rendering, if you can.
final ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
final ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext, viewId);
final UIViewRoot viewRoot = viewHandler.createView(facesContext, viewId);
vdl.buildView(facesContext, viewRoot);
facesContext.getApplication().publishEvent(facesContext, PreRenderViewEvent.class, viewRoot);
vdl.renderView(facesContext, viewRoot);
- facesContext.responseComplete();
}
} catch (Exception e) {
LOG.error("Exception while exception handling!", e);
} finally {
+ facesContext.responseComplete();
iterator.remove();
}
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
index a657ed8..9bacbdc 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
@@ -19,7 +19,9 @@
package org.apache.myfaces.tobago.internal.renderkit.renderer;
+import org.apache.myfaces.tobago.component.Attributes;
import org.apache.myfaces.tobago.context.Markup;
+import org.apache.myfaces.tobago.internal.component.AbstractUIFormBase;
import org.apache.myfaces.tobago.internal.component.AbstractUISelectOneRadio;
import org.apache.myfaces.tobago.internal.component.AbstractUISelectReference;
import org.apache.myfaces.tobago.internal.util.ArrayUtils;
@@ -33,19 +35,66 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
import org.apache.myfaces.tobago.util.ComponentUtils;
import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import java.io.IOException;
+import java.lang.invoke.MethodHandles;
public class SelectOneRadioRenderer<T extends AbstractUISelectOneRadio> extends SelectOneRendererBase<T> {
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ @Override
+ public void decodeInternal(final FacesContext facesContext, final T component) {
+ if (isOutputOnly(component)) {
+ return;
+ }
+ final String group = component.getGroup();
+ if (StringUtils.isBlank(group)) {
+ super.decodeInternal(facesContext, component);
+ } else {
+ final String decodingId = getDecodingId(facesContext, component);
+ final Object newValue = facesContext.getExternalContext().getRequestParameterMap().get(decodingId);
+ LOG.debug("decode: key='{}' value='{}'", decodingId, newValue);
+ if (component.getValueExpression(Attributes.value.name()) != null) {
+ LOG.debug("setSubmittedValue");
+ component.setSubmittedValue(newValue);
+ } else {
+ LOG.debug("resetValue");
+ component.resetValue();
+ }
+
+ decodeClientBehaviors(facesContext, component);
+ }
+ }
+
@Override
public HtmlElements getComponentTag() {
return HtmlElements.TOBAGO_SELECT_ONE_RADIO;
}
@Override
+ protected String getDecodingId(final FacesContext facesContext, final T component) {
+ final String group = component.getGroup();
+ final String name;
+ if (StringUtils.isNotBlank(group)) {
+ final AbstractUIFormBase form = ComponentUtils.findForm(component);
+ if (form != null) {
+ name = form.getClientId(facesContext) + facesContext.getNamingContainerSeparatorChar() + group;
+ } else {
+ LOG.warn("Can't find form for grouping id.");
+ name = group;
+ }
+ } else {
+ name = component.getClientId(facesContext);
+ }
+ return name;
+ }
+
+ @Override
protected void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
final AbstractUISelectReference reference = component.getRenderRangeReference();
final TobagoResponseWriter writer = getResponseWriter(facesContext);
@@ -60,6 +109,7 @@ public class SelectOneRadioRenderer<T extends AbstractUISelectOneRadio> extends
final boolean inline = component.isInline();
final Markup markup = component.getMarkup();
final boolean isInsideCommand = isInside(facesContext, HtmlElements.COMMAND);
+ final String name = getDecodingId(facesContext, component);
writer.startElement(getTag(facesContext));
writer.writeClassAttribute(
@@ -92,7 +142,7 @@ public class SelectOneRadioRenderer<T extends AbstractUISelectOneRadio> extends
checked = ObjectUtils.equals(formattedValue, submittedValue);
}
writer.writeAttribute(HtmlAttributes.CHECKED, checked);
- writer.writeNameAttribute(id);
+ writer.writeNameAttribute(name);
writer.writeIdAttribute(itemId);
writer.writeAttribute(HtmlAttributes.VALUE, formattedValue, true);
writer.writeAttribute(HtmlAttributes.DISABLED, itemDisabled);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java
index f470133..229075a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java
@@ -44,11 +44,14 @@ public abstract class SelectOneRendererBase<T extends AbstractUISelectOneBase> e
final String clientId = component.getClientId(facesContext);
final Object newValue =
facesContext.getExternalContext().getRequestParameterMap().get(clientId);
- if (LOG.isDebugEnabled()) {
- LOG.debug("decode: key='" + clientId + "' value='" + newValue + "'");
- }
+ LOG.debug("decode: key='{}' value='{}'", clientId, newValue);
component.setSubmittedValue(newValue);
decodeClientBehaviors(facesContext, component);
}
+
+ protected String getDecodingId(final FacesContext facesContext, final T component) {
+ return component.getClientId(facesContext);
+ }
+
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyCheckboxTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyCheckboxTagDeclaration.java
index cb27a1b..d90f76d 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyCheckboxTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyCheckboxTagDeclaration.java
@@ -27,9 +27,11 @@ import org.apache.myfaces.tobago.apt.annotation.UIComponentTag;
import org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute;
import org.apache.myfaces.tobago.component.ClientBehaviors;
import org.apache.myfaces.tobago.component.RendererTypes;
+import org.apache.myfaces.tobago.internal.taglib.declaration.HasAutoSpacing;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasBinding;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasConverter;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasConverterMessage;
+import org.apache.myfaces.tobago.internal.taglib.declaration.HasGroup;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasHelp;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasId;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasLabel;
@@ -41,7 +43,6 @@ import org.apache.myfaces.tobago.internal.taglib.declaration.HasTip;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasValidator;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasValidatorMessage;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasValueChangeListener;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasAutoSpacing;
import org.apache.myfaces.tobago.internal.taglib.declaration.IsDisabled;
import org.apache.myfaces.tobago.internal.taglib.declaration.IsFocus;
import org.apache.myfaces.tobago.internal.taglib.declaration.IsInline;
@@ -83,7 +84,7 @@ public interface SelectManyCheckboxTagDeclaration extends
HasBinding, IsReadonly, HasConverter, HasLabelLayout,
HasLabel, HasValidator, HasValueChangeListener,
HasValidatorMessage, HasConverterMessage, HasRequiredMessageForSelect, HasTabIndex, IsFocus, IsVisual,
- HasAutoSpacing {
+ HasAutoSpacing, HasGroup {
/**
* The value of the multi select.
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneRadioTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneRadioTagDeclaration.java
index 19e8767..2811c52 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneRadioTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneRadioTagDeclaration.java
@@ -30,6 +30,7 @@ import org.apache.myfaces.tobago.component.RendererTypes;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasBinding;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasConverter;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasConverterMessage;
+import org.apache.myfaces.tobago.internal.taglib.declaration.HasGroup;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasHelp;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasId;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasLabel;
@@ -82,7 +83,8 @@ import javax.faces.component.UISelectOne;
public interface SelectOneRadioTagDeclaration
extends HasValidator, HasValue, HasValueChangeListener, HasTabIndex, IsFocus, IsVisual,
HasValidatorMessage, HasConverterMessage, HasRequiredMessage, IsDisabled, IsReadonly, HasId, HasTip, HasHelp,
- IsInline, HasRenderRange, IsRendered, HasBinding, HasConverter, HasLabel, HasLabelLayout, HasAutoSpacing {
+ IsInline, HasRenderRange, IsRendered, HasBinding, HasConverter, HasLabel, HasLabelLayout, HasAutoSpacing,
+ HasGroup {
/**
* Flag indicating that selecting an Item representing a Value is Required.
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/declaration/HasGroup.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/declaration/HasGroup.java
new file mode 100644
index 0000000..3b5097f
--- /dev/null
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/declaration/HasGroup.java
@@ -0,0 +1,32 @@
+/*
+ * 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.myfaces.tobago.internal.taglib.declaration;
+
+import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
+import org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute;
+
+public interface HasGroup {
+ /**
+ * XXX Warning: Not fully implemented yet! For further use to be flexible with layout of radio and multi checkboxes.
+ */
+ @TagAttribute
+ @UIComponentTagAttribute
+ void setGroup(String group);
+}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.xhtml
index 630d096..4991ef1 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.xhtml
@@ -155,26 +155,80 @@
</tc:section>
- <tc:section label="Free layout with pure JSF (JSF 2.3 only)">
+ <tc:section id="selectGroup" label="Free layout with group attribute">
+
+ <tc:badge markup="warning" value="Work in progress!"/>
+ Decoding and validation is case of "group" is not implemented yet.
+
+ <tc:segmentLayout medium="4seg 4seg 4seg">
+ <tc:box>
+ First and second giant planets:
+ <tc:selectOneRadio id="group0" group="giantGroup" labelLayout="segmentRight"
+ value="#{selectOneRadioController.selectedGiantPlanet}">
+ <f:selectItem id="si0" itemValue="#{astroData.giantPlanets[0].value}" itemLabel="#{astroData.giantPlanets[0].label}"/>
+ <f:selectItem id="si1" itemValue="#{astroData.giantPlanets[1].value}" itemLabel="#{astroData.giantPlanets[1].label}"/>
+ </tc:selectOneRadio>
+ </tc:box>
+
+ <tc:box>
+ Discovered #{astroData.giantPlanets[2].value.discoverYear}:
+ <tc:selectOneRadio id="group2" group="giantGroup" labelLayout="segmentRight">
+ <f:selectItem id="si2" itemValue="#{astroData.giantPlanets[2].value}" itemLabel="#{astroData.giantPlanets[2].label}"/>
+ </tc:selectOneRadio>
+ </tc:box>
+
+ <tc:box>
+ Discovered #{astroData.giantPlanets[3].value.discoverYear}:
+ <tc:selectOneRadio id="group3" group="giantGroup" labelLayout="segmentRight">
+ <f:selectItem id="si3" itemValue="#{astroData.giantPlanets[3].value}" itemLabel="#{astroData.giantPlanets[3].label}"/>
+ </tc:selectOneRadio>
+ </tc:box>
+ </tc:segmentLayout>
+
+ <tc:button label="Submit">
+ <f:ajax execute="selectGroup" render="selectGroup :page:messages"/>
+ </tc:button>
+
+ <tc:out label="Selected:" value="#{selectOneRadioController.selectedGiantPlanet.name}"/>
+
+ </tc:section>
+
+ <tc:section id="selectGroupJsf" label="Free layout with group attribute (JSF HTML tags - since JSF 2.3)">
<p>
<span class="#{demo:bootstrapClass('BADGE')} #{demo:bootstrapClass('BADGE_DANGER')}">Attention!</span>
This example is only temporary for testing purpose.
+ Does not currently work with Mojarra or MyFaces, but for different reasons.
</p>
- <h:selectOneRadio id="terrestrial0" group="terrestrial"
- value="#{selectOneRadioController.selectedTerrestrialPlanet}">
- <f:selectItems value="#{astroData.terrestrialPlanets}"/>
- </h:selectOneRadio>
+ <tc:segmentLayout medium="3seg 3seg 3seg 3seg">
+
+ <tc:box>
+ <h:selectOneRadio id="terrestrial0" group="terrestrial"
+ value="#{selectOneRadioController.selectedTerrestrialPlanet}">
+ <f:selectItems value="#{astroData.terrestrialPlanets}"/>
+ </h:selectOneRadio>
+ </tc:box>
+
+ <tc:box>
+ <h:selectOneRadio id="terrestrial1" group="terrestrial"/>
+ </tc:box>
+
+ <tc:box>
+ <h:selectOneRadio id="terrestrial2" group="terrestrial"/>
+ </tc:box>
+
+ <tc:box>
+ <h:selectOneRadio id="terrestrial3" group="terrestrial"/>
+ </tc:box>
- <br/>
- <h:selectOneRadio id="terrestrial1" group="terrestrial"/>
+ </tc:segmentLayout>
- <br/>
- <h:selectOneRadio id="terrestrial2" group="terrestrial"/>
+ <tc:button label="Submit">
+ <f:ajax execute="selectGroupJsf" render="selectGroupJsf :page:messages"/>
+ </tc:button>
- <br/>
- <h:selectOneRadio id="terrestrial3" group="terrestrial"/>
+ <tc:out label="Selected:" value="#{selectOneRadioController.selectedTerrestrialPlanet.name}"/>
</tc:section>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/50-selectManyCheckbox/Multi_Checkbox.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/50-selectManyCheckbox/Multi_Checkbox.xhtml
index d41a0a4..1436859 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/50-selectManyCheckbox/Multi_Checkbox.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/50-selectManyCheckbox/Multi_Checkbox.xhtml
@@ -145,26 +145,42 @@
</tc:section>
- <tc:section label="Free layout with pure JSF (JSF 2.3 only)">
+ <tc:section id="selectGroupJsf" label="Free layout with group attribute (JSF HTML tags - since JSF 2.3)">
<p>
- <span class="#{demo:bootstrapClass('BADGE')} #{demo:bootstrapClass('BADGE_DANGER')}">Attanion!</span>
+ <span class="#{demo:bootstrapClass('BADGE')} #{demo:bootstrapClass('BADGE_DANGER')}">Attention!</span>
This example is only temporary for testing purpose.
+ Does not currently work with Mojarra or MyFaces, but for different reasons.
</p>
- <h:selectManyCheckbox id="terrestrial0" group="terrestrial"
- value="#{selectManyCheckboxController.selectedTerrestrialPlanet}">
- <f:selectItems value="#{astroData.terrestrialPlanets}"/>
- </h:selectManyCheckbox>
+ <tc:segmentLayout medium="3seg 3seg 3seg 3seg">
+
+ <tc:box>
+ <h:selectManyCheckbox id="terrestrial0" group="terrestrial"
+ value="#{selectManyCheckboxController.selectedTerrestrialPlanet}">
+ <f:selectItems value="#{astroData.terrestrialPlanets}"/>
+ </h:selectManyCheckbox>
+ </tc:box>
+
+ <tc:box>
+ <h:selectManyCheckbox id="terrestrial1" group="terrestrial"/>
+ </tc:box>
+
+ <tc:box>
+ <h:selectManyCheckbox id="terrestrial2" group="terrestrial"/>
+ </tc:box>
+
+ <tc:box>
+ <h:selectManyCheckbox id="terrestrial3" group="terrestrial"/>
+ </tc:box>
- <br/>
- <h:selectManyCheckbox id="terrestrial1" group="terrestrial"/>
+ </tc:segmentLayout>
- <br/>
- <h:selectManyCheckbox id="terrestrial2" group="terrestrial"/>
+ <tc:button label="Submit">
+ <f:ajax execute="selectGroupJsf" render="selectGroupJsf :page:messages"/>
+ </tc:button>
- <br/>
- <h:selectManyCheckbox id="terrestrial3" group="terrestrial"/>
+ <tc:out label="Selected:" value="#{selectManyCheckboxController.selectedTerrestrialPlanet.name}"/>
</tc:section>