You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by hn...@apache.org on 2023/06/12 07:17:43 UTC
[myfaces-tobago] 01/02: fix(select[One/Many]List): events
This is an automated email from the ASF dual-hosted git repository.
hnoeth pushed a commit to branch tobago-5.x
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
commit cdc0dd316897a08d51ed69617a130819df2a889a
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Mon Jun 5 15:32:55 2023 +0200
fix(select[One/Many]List): events
* make click/dblclick/focus/blur events work
* fix: change event with tc:event
* getFieldIdForBehavior() removed; The hidden select component has now the field id.
* a click on a label or an error message (label for attribute) focus the component
* remove "input" event from supported behavior list. Use the change event instead.
* adjust tests
* add event test
Issue: TOBAGO-2220
---
.../myfaces/tobago/component/SupportFieldId.java | 4 --
.../component/AbstractUISelectManyList.java | 12 ++---
.../component/AbstractUISelectOneList.java | 6 +--
.../renderkit/renderer/SelectManyListRenderer.java | 16 +++----
.../renderkit/renderer/SelectOneListRenderer.java | 16 +++----
.../renderer/TobagoClientBehaviorRenderer.java | 2 +-
.../component/SelectManyListTagDeclaration.java | 20 +++-----
.../component/SelectOneListTagDeclaration.java | 1 -
.../selectManyList/selectManyListAjax.html | 6 +--
.../renderer/selectOneList/selectOneListAjax.html | 6 +--
.../80-selectManyList/SelectManyList.test.js | 14 +++---
.../content/900-test/6000-event/Event.test.js | 30 ++++++++++++
.../webapp/content/900-test/6000-event/Event.xhtml | 2 +-
.../6000-event/x-event-selectOneList.xhtml | 55 ++++++++++++++++++++++
.../src/main/ts/tobago-select-list-base.ts | 22 ++++++++-
.../src/main/ts/tobago-select-many-list.ts | 12 ++++-
.../src/main/ts/tobago-select-one-list.ts | 12 +++--
17 files changed, 165 insertions(+), 71 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/SupportFieldId.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/SupportFieldId.java
index df60a8bbff..fbacd787ac 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/SupportFieldId.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/SupportFieldId.java
@@ -24,8 +24,4 @@ import javax.faces.context.FacesContext;
public interface SupportFieldId {
String getFieldId(FacesContext facesContext);
-
- default String getFieldIdForBehavior(FacesContext facesContext) {
- return getFieldId(facesContext);
- }
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectManyList.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectManyList.java
index 5a5164d188..66dfa52d89 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectManyList.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectManyList.java
@@ -36,8 +36,8 @@ import java.util.Collection;
* {@link SelectManyListTagDeclaration}
*/
public abstract class AbstractUISelectManyList extends AbstractUISelectManyBase
- implements SupportsAutoSpacing, Visual, SupportsLabelLayout, ClientBehaviorHolder, SupportsHelp, SupportFieldId,
- SupportsFilter {
+ implements SupportsAutoSpacing, Visual, SupportsLabelLayout, ClientBehaviorHolder, SupportsHelp, SupportFieldId,
+ SupportsFilter {
private transient boolean nextToRenderIsLabel;
@@ -56,11 +56,6 @@ public abstract class AbstractUISelectManyList extends AbstractUISelectManyBase
return getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "field";
}
- @Override
- public String getFieldIdForBehavior(FacesContext facesContext) {
- return getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "selected";
- }
-
public abstract Integer getTabIndex();
public abstract boolean isDisabled();
@@ -69,8 +64,7 @@ public abstract class AbstractUISelectManyList extends AbstractUISelectManyBase
public boolean isError() {
final FacesContext facesContext = FacesContext.getCurrentInstance();
- return !isValid()
- || !facesContext.getMessageList(getClientId(facesContext)).isEmpty();
+ return !isValid() || !facesContext.getMessageList(getClientId(facesContext)).isEmpty();
}
public abstract boolean isFocus();
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectOneList.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectOneList.java
index 118c623ca5..9c65a9c565 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectOneList.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISelectOneList.java
@@ -31,11 +31,7 @@ public abstract class AbstractUISelectOneList extends AbstractUISelectOneBase im
return getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "field";
}
- @Override
- public String getFieldIdForBehavior(FacesContext facesContext) {
- return getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "selected";
- }
-
public abstract String getFilter();
+
public abstract boolean isExpanded();
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java
index 6bfaa3dc28..5b4aa562e8 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java
@@ -70,8 +70,8 @@ public class SelectManyListRenderer<T extends AbstractUISelectManyList> extends
final String clientId = component.getClientId(facesContext);
final String fieldId = component.getFieldId(facesContext);
+ final String selectFieldId = clientId + ComponentUtils.SUB_SEPARATOR + "selectField";
final String filterId = clientId + ComponentUtils.SUB_SEPARATOR + "filter";
- final String selectedId = clientId + ComponentUtils.SUB_SEPARATOR + "selected";
final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, component);
final boolean disabled = !items.iterator().hasNext() || component.isDisabled() || component.isReadonly();
final String filter = component.getFilter();
@@ -79,7 +79,7 @@ public class SelectManyListRenderer<T extends AbstractUISelectManyList> extends
final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
final Integer tabIndex = component.getTabIndex();
- encodeHiddenSelect(facesContext, component, items, clientId, selectedId, disabled);
+ encodeHiddenSelect(facesContext, component, items, clientId, fieldId, disabled);
writer.startElement(HtmlElements.DIV);
writer.writeClassAttribute(
@@ -87,7 +87,7 @@ public class SelectManyListRenderer<T extends AbstractUISelectManyList> extends
expanded ? BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)) : null);
encodeSelectField(facesContext, component,
- clientId, fieldId, filterId, filter, disabled, expanded, title, tabIndex);
+ clientId, selectFieldId, filterId, filter, disabled, expanded, title, tabIndex);
encodeOptions(facesContext, component, items, clientId, expanded, disabled);
writer.endElement(HtmlElements.DIV);
@@ -102,11 +102,11 @@ public class SelectManyListRenderer<T extends AbstractUISelectManyList> extends
private void encodeHiddenSelect(
final FacesContext facesContext, final T component, final List<SelectItem> items,
- final String clientId, final String selectedId, final boolean disabled) throws IOException {
+ final String clientId, final String fieldId, final boolean disabled) throws IOException {
final TobagoResponseWriter writer = getResponseWriter(facesContext);
writer.startElement(HtmlElements.SELECT);
- writer.writeIdAttribute(selectedId);
+ writer.writeIdAttribute(fieldId);
writer.writeNameAttribute(clientId);
writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
@@ -121,12 +121,12 @@ public class SelectManyListRenderer<T extends AbstractUISelectManyList> extends
private void encodeSelectField(
final FacesContext facesContext, final T component,
- final String clientId, final String fieldId, final String filterId, final String filter, final boolean disabled,
- final boolean expanded, final String title, final Integer tabIndex) throws IOException {
+ final String clientId, final String selectFieldId, final String filterId, final String filter,
+ final boolean disabled, final boolean expanded, final String title, final Integer tabIndex) throws IOException {
final TobagoResponseWriter writer = getResponseWriter(facesContext);
writer.startElement(HtmlElements.DIV);
- writer.writeIdAttribute(fieldId);
+ writer.writeIdAttribute(selectFieldId);
writer.writeNameAttribute(clientId);
HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
writer.writeClassAttribute(
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java
index dc6cbb4997..c24f4e394e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java
@@ -48,8 +48,8 @@ public class SelectOneListRenderer<T extends AbstractUISelectOneList> extends Se
final String clientId = component.getClientId(facesContext);
final String fieldId = component.getFieldId(facesContext);
+ final String selectFieldId = clientId + ComponentUtils.SUB_SEPARATOR + "selectField";
final String filterId = clientId + ComponentUtils.SUB_SEPARATOR + "filter";
- final String selectedId = clientId + ComponentUtils.SUB_SEPARATOR + "selected";
final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, component);
final boolean disabled = !items.iterator().hasNext() || component.isDisabled() || component.isReadonly();
final String filter = component.getFilter();
@@ -57,7 +57,7 @@ public class SelectOneListRenderer<T extends AbstractUISelectOneList> extends Se
final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
final Integer tabIndex = component.getTabIndex();
- encodeHiddenSelect(facesContext, component, items, clientId, selectedId, disabled);
+ encodeHiddenSelect(facesContext, component, items, clientId, fieldId, disabled);
writer.startElement(HtmlElements.DIV);
writer.writeClassAttribute(
@@ -65,7 +65,7 @@ public class SelectOneListRenderer<T extends AbstractUISelectOneList> extends Se
expanded ? BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)) : null);
encodeSelectField(facesContext, component,
- clientId, fieldId, filterId, filter, disabled, expanded, title, tabIndex);
+ clientId, selectFieldId, filterId, filter, disabled, expanded, title, tabIndex);
encodeOptions(facesContext, component, items, clientId, expanded, disabled);
writer.endElement(HtmlElements.DIV);
@@ -73,11 +73,11 @@ public class SelectOneListRenderer<T extends AbstractUISelectOneList> extends Se
private void encodeHiddenSelect(
final FacesContext facesContext, final T component, final List<SelectItem> items,
- final String clientId, final String selectedId, final boolean disabled) throws IOException {
+ final String clientId, final String fieldId, final boolean disabled) throws IOException {
final TobagoResponseWriter writer = getResponseWriter(facesContext);
writer.startElement(HtmlElements.SELECT);
- writer.writeIdAttribute(selectedId);
+ writer.writeIdAttribute(fieldId);
writer.writeNameAttribute(clientId);
writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
@@ -90,12 +90,12 @@ public class SelectOneListRenderer<T extends AbstractUISelectOneList> extends Se
private void encodeSelectField(
final FacesContext facesContext, final T component,
- final String clientId, final String fieldId, final String filterId, final String filter, final boolean disabled,
- final boolean expanded, final String title, final Integer tabIndex) throws IOException {
+ final String clientId, final String selectFieldId, final String filterId, final String filter,
+ final boolean disabled, final boolean expanded, final String title, final Integer tabIndex) throws IOException {
final TobagoResponseWriter writer = getResponseWriter(facesContext);
writer.startElement(HtmlElements.DIV);
- writer.writeIdAttribute(fieldId);
+ writer.writeIdAttribute(selectFieldId);
writer.writeNameAttribute(clientId);
HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
writer.writeClassAttribute(
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java
index 95aa7a2559..d2477683c1 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java
@@ -86,7 +86,7 @@ public class TobagoClientBehaviorRenderer extends javax.faces.render.ClientBehav
final Collection<String> render = ajaxBehavior.getRender();
clientId = uiComponent.getClientId(facesContext);
if (uiComponent instanceof SupportFieldId) {
- fieldId = ((SupportFieldId) uiComponent).getFieldIdForBehavior(facesContext);
+ fieldId = ((SupportFieldId) uiComponent).getFieldId(facesContext);
}
executeIds = ComponentUtils.evaluateClientIds(facesContext, uiComponent, execute.toArray(new String[0]));
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyListTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyListTagDeclaration.java
index 9a45cbb624..2ada75a058 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyListTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectManyListTagDeclaration.java
@@ -31,12 +31,12 @@ 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.HasDecorationPosition;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasFilter;
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;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasLabelLayout;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasDecorationPosition;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasRequiredMessageForSelect;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasTabIndex;
import org.apache.myfaces.tobago.internal.taglib.declaration.HasTip;
@@ -65,19 +65,11 @@ import javax.faces.component.UISelectMany;
rendererType = RendererTypes.SELECT_MANY_LIST,
allowedChildComponenents = {"javax.faces.SelectItem", "javax.faces.SelectItems"},
behaviors = {
- @Behavior(
- name = ClientBehaviors.CHANGE,
- isDefault = true),
- @Behavior(
- name = ClientBehaviors.INPUT),
- @Behavior(
- name = ClientBehaviors.CLICK),
- @Behavior(
- name = ClientBehaviors.DBLCLICK),
- @Behavior(
- name = ClientBehaviors.FOCUS),
- @Behavior(
- name = ClientBehaviors.BLUR)
+ @Behavior(name = ClientBehaviors.CHANGE, isDefault = true),
+ @Behavior(name = ClientBehaviors.CLICK),
+ @Behavior(name = ClientBehaviors.DBLCLICK),
+ @Behavior(name = ClientBehaviors.FOCUS),
+ @Behavior(name = ClientBehaviors.BLUR)
})
public interface SelectManyListTagDeclaration
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneListTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneListTagDeclaration.java
index eceb39fc85..3d171634a7 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneListTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectOneListTagDeclaration.java
@@ -65,7 +65,6 @@ import javax.faces.component.UISelectMany;
allowedChildComponenents = {"javax.faces.SelectItem", "javax.faces.SelectItems"},
behaviors = {
@Behavior(name = ClientBehaviors.CHANGE, isDefault = true),
- @Behavior(name = ClientBehaviors.INPUT),
@Behavior(name = ClientBehaviors.CLICK),
@Behavior(name = ClientBehaviors.DBLCLICK),
@Behavior(name = ClientBehaviors.FOCUS),
diff --git a/tobago-core/src/test/resources/renderer/selectManyList/selectManyListAjax.html b/tobago-core/src/test/resources/renderer/selectManyList/selectManyListAjax.html
index a68d057a0c..295f2a96aa 100644
--- a/tobago-core/src/test/resources/renderer/selectManyList/selectManyListAjax.html
+++ b/tobago-core/src/test/resources/renderer/selectManyList/selectManyListAjax.html
@@ -16,13 +16,13 @@
-->
<tobago-select-many-list id='id' class='tobago-auto-spacing'>
- <select id='id::selected' name='id' class='d-none' multiple='multiple'>
+ <select id='id::field' name='id' class='d-none' multiple='multiple'>
<option value='Stratocaster'>Stratocaster
</option>
<option value='Telecaster'>Telecaster
</option></select>
<div class='dropdown'>
- <div id='id::field' name='id' class='form-select tobago-select-field dropdown-toggle' aria-expanded='false'>
+ <div id='id::selectField' name='id' class='form-select tobago-select-field dropdown-toggle' aria-expanded='false'>
<input type='search' id='id::filter' class='tobago-filter form-control' autocomplete='off' readonly='readonly'>
</div>
<div class='tobago-options tobago-dropdown-menu' name='id'>
@@ -46,5 +46,5 @@
</table>
</div>
</div>
- <tobago-behavior event='change' client-id='id' field-id='id::selected' execute='id'></tobago-behavior>
+ <tobago-behavior event='change' client-id='id' field-id='id::field' execute='id'></tobago-behavior>
</tobago-select-many-list>
diff --git a/tobago-core/src/test/resources/renderer/selectOneList/selectOneListAjax.html b/tobago-core/src/test/resources/renderer/selectOneList/selectOneListAjax.html
index 79ebbf73f7..148808fa04 100644
--- a/tobago-core/src/test/resources/renderer/selectOneList/selectOneListAjax.html
+++ b/tobago-core/src/test/resources/renderer/selectOneList/selectOneListAjax.html
@@ -16,13 +16,13 @@
-->
<tobago-select-one-list id='id' class='tobago-auto-spacing'>
- <select id='id::selected' name='id' class='d-none'>
+ <select id='id::field' name='id' class='d-none'>
<option value='Stratocaster'>Stratocaster
</option>
<option value='Telecaster'>Telecaster
</option></select>
<div class='dropdown'>
- <div id='id::field' name='id' class='form-select tobago-select-field dropdown-toggle' aria-expanded='false'>
+ <div id='id::selectField' name='id' class='form-select tobago-select-field dropdown-toggle' aria-expanded='false'>
<span></span>
<input type='search' id='id::filter' class='tobago-filter form-control' autocomplete='off' readonly='readonly'>
</div>
@@ -47,5 +47,5 @@
</table>
</div>
</div>
- <tobago-behavior event='change' client-id='id' field-id='id::selected' execute='id'></tobago-behavior>
+ <tobago-behavior event='change' client-id='id' field-id='id::field' execute='id'></tobago-behavior>
</tobago-select-one-list>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/80-selectManyList/SelectManyList.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/80-selectManyList/SelectManyList.test.js
index e980348b78..ed037558c7 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/80-selectManyList/SelectManyList.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/80-selectManyList/SelectManyList.test.js
@@ -19,14 +19,14 @@ import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
import {elementByIdFn, querySelectorAllFn, querySelectorFn} from "/script/tobago-test.js";
it("Standard: remove 'Earth'", function (done) {
- const removeEarthButtonFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:field .btn-group[data-tobago-value='Earth'] .tobago-button");
- const badgeVenusFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:field .btn-group[data-tobago-value='Venus']");
- const badgeEarthFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:field .btn-group[data-tobago-value='Earth']");
- const badgeJupiterFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:field .btn-group[data-tobago-value='Jupiter']");
+ const removeEarthButtonFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:selectField .btn-group[data-tobago-value='Earth'] .tobago-button");
+ const badgeVenusFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:selectField .btn-group[data-tobago-value='Venus']");
+ const badgeEarthFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:selectField .btn-group[data-tobago-value='Earth']");
+ const badgeJupiterFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedStandard\\:\\:selectField .btn-group[data-tobago-value='Jupiter']");
const selectedRowsFn = querySelectorAllFn("#page\\:mainForm\\:basic\\:selectedStandard tr.table-primary");
- const disabledBadgeVenusFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedDisabled\\:\\:field .btn-group[data-tobago-value='Venus']");
- const disabledBadgeEarthFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedDisabled\\:\\:field .btn-group[data-tobago-value='Earth']");
- const disabledBadgeJupiterFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedDisabled\\:\\:field .btn-group[data-tobago-value='Jupiter']");
+ const disabledBadgeVenusFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedDisabled\\:\\:selectField .btn-group[data-tobago-value='Venus']");
+ const disabledBadgeEarthFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedDisabled\\:\\:selectField .btn-group[data-tobago-value='Earth']");
+ const disabledBadgeJupiterFn = querySelectorFn("#page\\:mainForm\\:basic\\:selectedDisabled\\:\\:selectField .btn-group[data-tobago-value='Jupiter']");
const submitFn = elementByIdFn("page:mainForm:basic:submit");
const resetFn = elementByIdFn("page:mainForm:basic:reset");
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.test.js
index 8bd1a4ecc3..ad43cba9cd 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.test.js
@@ -71,6 +71,28 @@ it("tc:selectBooleanCheckbox", function (done) {
test.start();
});
+it("tc:selectOneList", function (done) {
+ const eventNames = ["change", "focus", "blur"];
+ const eventComponentFn = elementByIdFn("page:mainForm:selectOneListevent::field");
+ const ajaxComponentFn = elementByIdFn("page:mainForm:selectOneListajax::field");
+
+ const clickEventNames = ["click", "dblclick"];
+ const clickEventComponentFn = elementByIdFn("page:mainForm:selectOneListevent::selectField");
+
+ const changeValueFn = function (componentFn) {
+ if (componentFn().closest("tobago-select-one-list").querySelectorAll("option")[0].selected) {
+ componentFn().closest("tobago-select-one-list").querySelectorAll("option")[1].selected = true;
+ } else {
+ componentFn().closest("tobago-select-one-list").querySelectorAll("option")[0].selected = true;
+ }
+ };
+
+ const test = new JasmineTestTool(done);
+ createSteps(test, "selectOneList", eventNames, eventComponentFn, ajaxComponentFn, changeValueFn);
+ createSteps(test, "selectOneList", clickEventNames, clickEventComponentFn, ajaxComponentFn, changeValueFn);
+ test.start();
+});
+
it("tc:selectOneListbox", function (done) {
const eventNames = ["change", "click", "dblclick", "focus", "blur"];
const eventComponentFn = elementByIdFn("page:mainForm:selectOneListboxevent::field");
@@ -109,6 +131,7 @@ it("tc:textarea", function (done) {
});
function createSteps(test, componentName, eventNames, eventComponentFn, ajaxComponentFn, changeValueFn) {
+ const resetButtonFn = elementByIdFn("page:mainForm:reset");
const actionCountFn = elementByIdFn("page:mainForm:inAction::field");
const actionListenerCountFn = elementByIdFn("page:mainForm:inActionListener::field");
const ajaxListenerCountFn = elementByIdFn("page:mainForm:inAjaxListener::field");
@@ -138,6 +161,13 @@ function createSteps(test, componentName, eventNames, eventComponentFn, ajaxComp
test.do(() => oldTimestamp = parseInt(timestampFn().value));
test.event("click", selectorButton, () => parseInt(timestampFn().value) > oldTimestamp);
+ test.setup(() =>
+ parseInt(actionCountFn().value)
+ + parseInt(actionListenerCountFn().value)
+ + parseInt(ajaxListenerCountFn().value)
+ + parseInt(valueChangeListenerCountFn().value) === 0,
+ null, "click", resetButtonFn);
+
test.do(() => oldActionCount = parseInt(actionCountFn().value));
test.do(() => oldActionListenerCount = parseInt(actionListenerCountFn().value));
test.do(() => oldAjaxListenerCount = parseInt(ajaxListenerCountFn().value));
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.xhtml
index 396f0139d9..6d9ae69bc2 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/Event.xhtml
@@ -27,7 +27,7 @@
<tc:box id="metrics" label="Metrics">
<f:facet name="bar">
- <tc:button label="Reset" action="#{eventController.reset}"/>
+ <tc:button id="reset" label="Reset" action="#{eventController.reset}"/>
</f:facet>
<tc:in id="inAction" label="Action" value="#{eventController.actionCount}" readonly="true" focus="true"/>
<tc:in id="inActionListener" label="ActionListener" value="#{eventController.actionListenerCount}"
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/x-event-selectOneList.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/x-event-selectOneList.xhtml
new file mode 100644
index 0000000000..9cb862cb4e
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/6000-event/x-event-selectOneList.xhtml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * 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.
+-->
+
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
+ xmlns:f="http://xmlns.jcp.org/jsf/core"
+ xmlns:tc="http://myfaces.apache.org/tobago/component"
+ xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
+ <tc:selectOneList id="selectOneList#{eventType}" valueChangeListener="#{eventController.valueChangeListener}" expanded="true">
+ <tc:selectItem itemValue="alpha" itemLabel="Alpha"/>
+ <tc:selectItem itemValue="beta" itemLabel="Beta"/>
+ <tc:selectItem itemValue="gamma" itemLabel="Gamma"/>
+ <tc:selectItem itemValue="delta" itemLabel="Delta"/>
+ <c:if test="#{eventType == 'ajax'}">
+ <f:ajax event="change" render="metrics" listener="#{eventController.ajaxListener}"
+ disabled="#{eventName != 'change'}"/>
+ <f:ajax event="click" render="metrics" listener="#{eventController.ajaxListener}"
+ disabled="#{eventName != 'click'}"/>
+ <f:ajax event="dblclick" render="metrics" listener="#{eventController.ajaxListener}"
+ disabled="#{eventName != 'dblclick'}"/>
+ <f:ajax event="focus" render="metrics" listener="#{eventController.ajaxListener}"
+ disabled="#{eventName != 'focus'}"/>
+ <f:ajax event="blur" render="metrics" listener="#{eventController.ajaxListener}"
+ disabled="#{eventName != 'blur'}"/>
+ </c:if>
+ <c:if test="#{eventType == 'event'}">
+ <tc:event event="change" action="#{eventController.action}" actionListener="#{eventController.actionListener}"
+ rendered="#{eventName == 'change'}"/>
+ <tc:event event="click" action="#{eventController.action}" actionListener="#{eventController.actionListener}"
+ rendered="#{eventName == 'click'}"/>
+ <tc:event event="dblclick" action="#{eventController.action}" actionListener="#{eventController.actionListener}"
+ rendered="#{eventName == 'dblclick'}"/>
+ <tc:event event="focus" action="#{eventController.action}" actionListener="#{eventController.actionListener}"
+ rendered="#{eventName == 'focus'}"/>
+ <tc:event event="blur" action="#{eventController.action}" actionListener="#{eventController.actionListener}"
+ rendered="#{eventName == 'blur'}"/>
+ </c:if>
+ </tc:selectOneList>
+</ui:composition>
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-list-base.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-list-base.ts
index a4117e55de..20ab4f6ce3 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-list-base.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-list-base.ts
@@ -32,10 +32,12 @@ export abstract class SelectListBase extends HTMLElement {
}
set focused(focused: boolean) {
- if (focused) {
+ if (focused && !this.focused) {
this.classList.add(Css.TOBAGO_FOCUS);
- } else {
+ this.hiddenSelect.dispatchEvent(new Event("focus", {bubbles: true}));
+ } else if (!focused && this.focused) {
this.classList.remove(Css.TOBAGO_FOCUS);
+ this.hiddenSelect.dispatchEvent(new Event("blur", {bubbles: true}));
}
}
@@ -96,6 +98,7 @@ export abstract class SelectListBase extends HTMLElement {
window.addEventListener("resize", () => this.updateDropdownMenuWidth());
}
document.addEventListener("click", this.globalClickEvent.bind(this));
+ this.hiddenSelect.addEventListener("click", this.labelClickEvent.bind(this));
this.selectField.addEventListener("keydown", this.keydownEventBase.bind(this));
this.filterInput.addEventListener("focus", this.focusEvent.bind(this));
this.filterInput.addEventListener("blur", this.blurEvent.bind(this));
@@ -110,10 +113,25 @@ export abstract class SelectListBase extends HTMLElement {
if (document.activeElement.id === this.filterInput.id) {
this.focusEvent();
}
+
+ // redirect click events for ajax behavior
+ this.selectField.addEventListener("click", () => this.hiddenSelect.dispatchEvent(new Event("click")));
+ this.options.addEventListener("click", () => this.hiddenSelect.dispatchEvent(new Event("click")));
+ this.selectField.addEventListener("dblclick", () => this.hiddenSelect.dispatchEvent(new Event("dblclick")));
+ this.options.addEventListener("dblclick", () => this.hiddenSelect.dispatchEvent(new Event("dblclick")));
}
protected abstract globalClickEvent(event: MouseEvent): void;
+ /**
+ * The label for attribute targets the hidden select field, so an event which is dispatched on the label is also
+ * dispatched on the hidden select field. This method must ensure that a click on a label focus the
+ * Select[One/Many]List component.
+ * @param event
+ * @protected
+ */
+ protected abstract labelClickEvent(event: MouseEvent): void;
+
private keydownEventBase(event: KeyboardEvent) {
switch (event.key) {
case Key.ESCAPE:
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many-list.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many-list.ts
index a13aa46026..c89ddd4fd3 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many-list.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many-list.ts
@@ -57,13 +57,21 @@ class SelectManyList extends SelectListBase {
}
}
+ protected labelClickEvent(event: MouseEvent): void {
+ event.stopPropagation(); // stop propagation to avoid execution of globalClickEvent()
+ if (!this.filterInput.disabled) {
+ this.filterInput.focus();
+ } else if (this.badgeCloseButtons.length > 0) {
+ this.badgeCloseButtons[0].focus();
+ }
+ }
+
protected select(row: HTMLTableRowElement): void {
const itemValue = row.dataset.tobagoValue;
const option: HTMLOptionElement = this.hiddenSelect.querySelector(`[value="${itemValue}"]`);
option.selected = !option.selected;
this.sync(option);
- const e = new Event("change");
- this.hiddenSelect.dispatchEvent(e);
+ this.hiddenSelect.dispatchEvent(new Event("change", {bubbles: true}));
}
private sync(option: HTMLOptionElement) {
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-one-list.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-one-list.ts
index 07389aaf34..ed72a2d149 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-one-list.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-one-list.ts
@@ -32,7 +32,7 @@ class SelectOneList extends SelectListBase {
this.selectField.querySelector("span").textContent = text;
}
- get selectedOption() :HTMLOptionElement {
+ get selectedOption(): HTMLOptionElement {
const value = this.hiddenSelect.value;
return this.hiddenSelect.querySelector(`[value="${value}"]`);
}
@@ -60,6 +60,13 @@ class SelectOneList extends SelectListBase {
}
}
+ protected labelClickEvent(event: MouseEvent): void {
+ event.stopPropagation(); // stop propagation to avoid execution of globalClickEvent()
+ if (!this.filterInput.disabled) {
+ this.filterInput.focus();
+ }
+ }
+
private keydownEvent(event: KeyboardEvent) {
switch (event.key) {
case Key.ESCAPE:
@@ -83,8 +90,7 @@ class SelectOneList extends SelectListBase {
option.selected = true;
this.filterInput.value = null;
this.sync();
- const e = new Event("change");
- this.hiddenSelect.dispatchEvent(e);
+ this.hiddenSelect.dispatchEvent(new Event("change", {bubbles: true}));
}
private sync() {